//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

function EditorGui::getPrefs()
{
   EWorldEditor.dropType = getPrefSetting($Pref::WorldEditor::dropType, "atCamera");

   // same defaults as WorldEditor ctor
   EWorldEditor.planarMovement = getPrefSetting($pref::WorldEditor::planarMovement, true);
   EWorldEditor.undoLimit = getPrefSetting($pref::WorldEditor::undoLimit, 40);
   EWorldEditor.dropType = getPrefSetting($pref::WorldEditor::dropType, "screenCenter");
   EWorldEditor.projectDistance = getPrefSetting($pref::WorldEditor::projectDistance, 2000);
   EWorldEditor.boundingBoxCollision = getPrefSetting($pref::WorldEditor::boundingBoxCollision, true);
   EWorldEditor.renderPlane = getPrefSetting($pref::WorldEditor::renderPlane, true);
   EWorldEditor.renderPlaneHashes = getPrefSetting($pref::WorldEditor::renderPlaneHashes, true);
   EWorldEditor.gridColor = getPrefSetting($pref::WorldEditor::gridColor, "255 255 255 20");
   EWorldEditor.planeDim = getPrefSetting($pref::WorldEditor::planeDim, 500);
   EWorldEditor.gridSize = getPrefSetting($pref::WorldEditor::gridSize, "10 10 10");
   EWorldEditor.renderPopupBackground = getPrefSetting($pref::WorldEditor::renderPopupBackground, true);
   EWorldEditor.popupBackgroundColor = getPrefSetting($pref::WorldEditor::popupBackgroundColor, "100 100 100");
   EWorldEditor.popupTextColor = getPrefSetting($pref::WorldEditor::popupTextColor, "255 255 0");
   EWorldEditor.selectHandle = getPrefSetting($pref::WorldEditor::selectHandle, "gui/Editor_SelectHandle.png");
   EWorldEditor.defaultHandle = getPrefSetting($pref::WorldEditor::defaultHandle, "gui/Editor_DefaultHandle.png");
   EWorldEditor.lockedHandle = getPrefSetting($pref::WorldEditor::lockedHandle, "gui/Editor_LockedHandle.png");
   EWorldEditor.objectTextColor = getPrefSetting($pref::WorldEditor::objectTextColor, "255 255 255");
   EWorldEditor.objectsUseBoxCenter = getPrefSetting($pref::WorldEditor::objectsUseBoxCenter, true);
   EWorldEditor.axisGizmoMaxScreenLen = getPrefSetting($pref::WorldEditor::axisGizmoMaxScreenLen, 200);
   EWorldEditor.axisGizmoActive = getPrefSetting($pref::WorldEditor::axisGizmoActive, true);
   EWorldEditor.mouseMoveScale = getPrefSetting($pref::WorldEditor::mouseMoveScale, 0.2);
   EWorldEditor.mouseRotateScale = getPrefSetting($pref::WorldEditor::mouseRotateScale, 0.01);
   EWorldEditor.mouseScaleScale = getPrefSetting($pref::WorldEditor::mouseScaleScale, 0.01);
   EWorldEditor.minScaleFactor = getPrefSetting($pref::WorldEditor::minScaleFactor, 0.1);
   EWorldEditor.maxScaleFactor = getPrefSetting($pref::WorldEditor::maxScaleFactor, 4000);
   EWorldEditor.objSelectColor = getPrefSetting($pref::WorldEditor::objSelectColor, "255 0 0");
   EWorldEditor.objMouseOverSelectColor = getPrefSetting($pref::WorldEditor::objMouseOverSelectColor, "0 0 255");
   EWorldEditor.objMouseOverColor = getPrefSetting($pref::WorldEditor::objMouseOverColor, "0 255 0");
   EWorldEditor.showMousePopupInfo = getPrefSetting($pref::WorldEditor::showMousePopupInfo, true);
   EWorldEditor.dragRectColor = getPrefSetting($pref::WorldEditor::dragRectColor, "255 255 0");
   EWorldEditor.renderObjText = getPrefSetting($pref::WorldEditor::renderObjText, true);
   EWorldEditor.renderObjHandle = getPrefSetting($pref::WorldEditor::renderObjHandle, true);
   EWorldEditor.faceSelectColor = getPrefSetting($pref::WorldEditor::faceSelectColor, "0 0 100 100");
   EWorldEditor.renderSelectionBox = getPrefSetting($pref::WorldEditor::renderSelectionBox, true);
   EWorldEditor.selectionBoxColor = getPrefSetting($pref::WorldEditor::selectionBoxColor, "255 255 0");
   EWorldEditor.snapToGrid = getPrefSetting($pref::WorldEditor::snapToGrid, false);
   EWorldEditor.snapRotations = getPrefSetting($pref::WorldEditor::snapRotations, false);
   EWorldEditor.rotationSnap = getPrefSetting($pref::WorldEditor::rotationSnap, "15");

   ETerrainEditor.softSelecting = 1;
   ETerrainEditor.currentAction = "raiseHeight";
   ETerrainEditor.currentMode = "select";
}

function EditorGui::setPrefs()
{
   $Pref::WorldEditor::dropType = EWorldEditor.dropType;
   $pref::WorldEditor::planarMovement = EWorldEditor.planarMovement;
   $pref::WorldEditor::undoLimit = EWorldEditor.undoLimit;
   $pref::WorldEditor::dropType = EWorldEditor.dropType;
   $pref::WorldEditor::projectDistance = EWorldEditor.projectDistance;
   $pref::WorldEditor::boundingBoxCollision = EWorldEditor.boundingBoxCollision;
   $pref::WorldEditor::renderPlane = EWorldEditor.renderPlane;
   $pref::WorldEditor::renderPlaneHashes = EWorldEditor.renderPlaneHashes;
   $pref::WorldEditor::gridColor = EWorldEditor.GridColor;
   $pref::WorldEditor::planeDim = EWorldEditor.planeDim;
   $pref::WorldEditor::gridSize = EWorldEditor.GridSize;
   $pref::WorldEditor::renderPopupBackground = EWorldEditor.renderPopupBackground;
   $pref::WorldEditor::popupBackgroundColor = EWorldEditor.PopupBackgroundColor;
   $pref::WorldEditor::popupTextColor = EWorldEditor.PopupTextColor;
   $pref::WorldEditor::selectHandle = EWorldEditor.selectHandle;
   $pref::WorldEditor::defaultHandle = EWorldEditor.defaultHandle;
   $pref::WorldEditor::lockedHandle = EWorldEditor.lockedHandle;
   $pref::WorldEditor::objectTextColor = EWorldEditor.ObjectTextColor;
   $pref::WorldEditor::objectsUseBoxCenter = EWorldEditor.objectsUseBoxCenter;
   $pref::WorldEditor::axisGizmoMaxScreenLen = EWorldEditor.axisGizmoMaxScreenLen;
   $pref::WorldEditor::axisGizmoActive = EWorldEditor.axisGizmoActive;
   $pref::WorldEditor::mouseMoveScale = EWorldEditor.mouseMoveScale;
   $pref::WorldEditor::mouseRotateScale = EWorldEditor.mouseRotateScale;
   $pref::WorldEditor::mouseScaleScale = EWorldEditor.mouseScaleScale;
   $pref::WorldEditor::minScaleFactor = EWorldEditor.minScaleFactor;
   $pref::WorldEditor::maxScaleFactor = EWorldEditor.maxScaleFactor;
   $pref::WorldEditor::objSelectColor = EWorldEditor.objSelectColor;
   $pref::WorldEditor::objMouseOverSelectColor = EWorldEditor.objMouseOverSelectColor;
   $pref::WorldEditor::objMouseOverColor = EWorldEditor.objMouseOverColor;
   $pref::WorldEditor::showMousePopupInfo = EWorldEditor.showMousePopupInfo;
   $pref::WorldEditor::dragRectColor = EWorldEditor.dragRectColor;
   $pref::WorldEditor::renderObjText = EWorldEditor.renderObjText;
   $pref::WorldEditor::renderObjHandle = EWorldEditor.renderObjHandle;
   $pref::WorldEditor::raceSelectColor = EWorldEditor.faceSelectColor;
   $pref::WorldEditor::renderSelectionBox = EWorldEditor.renderSelectionBox;
   $pref::WorldEditor::selectionBoxColor = EWorldEditor.selectionBoxColor;
   $pref::WorldEditor::snapToGrid = EWorldEditor.snapToGrid;
   $pref::WorldEditor::snapRotations = EWorldEditor.snapRotations;
   $pref::WorldEditor::rotationSnap = EWorldEditor.rotationSnap;

}

function EditorGui::onSleep(%this)
{
   %this.setPrefs();
}

function EditorGui::init(%this)
{
   %this.getPrefs();

   if(!isObject("terraformer"))
      new Terraformer("terraformer");
   $SelectedOperation = -1;
   $NextOperationId   = 1;
   $HeightfieldDirtyRow = -1;

   EditorMenuBar.clearMenus();
   EditorMenuBar.addMenu("File", 0);
   EditorMenuBar.addMenuItem("File", "New Mission...", 1);
   EditorMenuBar.addMenuItem("File", "Open Mission...", 2, "Ctrl O");
   EditorMenuBar.addMenuItem("File", "Save Mission...", 3, "Ctrl S");
   EditorMenuBar.addMenuItem("File", "Save Mission As...", 4);
   EditorMenuBar.addMenuItem("File", "-", 0);
   EditorMenuBar.addMenuItem("File", "Import Terraform Data...", 6);
   EditorMenuBar.addMenuItem("File", "Import Texture Data...", 5);
   EditorMenuBar.addMenuItem("File", "-", 0);
   EditorMenuBar.addMenuItem("File", "Export Terraform Bitmap...", 5);

   EditorMenuBar.addMenu("Edit", 1);
   EditorMenuBar.addMenuItem("Edit", "Undo", 1, "Ctrl Z");
   EditorMenuBar.setMenuItemBitmap("Edit", "Undo", 1);
   EditorMenuBar.addMenuItem("Edit", "Redo", 2, "Ctrl R");
   EditorMenuBar.setMenuItemBitmap("Edit", "Redo", 2);
   EditorMenuBar.addMenuItem("Edit", "-", 0);
   EditorMenuBar.addMenuItem("Edit", "Cut", 3, "Ctrl X");
   EditorMenuBar.setMenuItemBitmap("Edit", "Cut", 3);
   EditorMenuBar.addMenuItem("Edit", "Copy", 4, "Ctrl C");
   EditorMenuBar.setMenuItemBitmap("Edit", "Copy", 4);
   EditorMenuBar.addMenuItem("Edit", "Paste", 5, "Ctrl V");
   EditorMenuBar.setMenuItemBitmap("Edit", "Paste", 5);
   EditorMenuBar.addMenuItem("Edit", "-", 0);
   EditorMenuBar.addMenuItem("Edit", "Select All", 6, "Ctrl A");
   EditorMenuBar.addMenuItem("Edit", "Select None", 7, "Ctrl N");
   EditorMenuBar.addMenuItem("Edit", "-", 0);
   EditorMenuBar.addMenuItem("Edit", "Relight Scene", 14, "Alt L");
   EditorMenuBar.addMenuItem("Edit", "-", 0);
   EditorMenuBar.addMenuItem("Edit", "World Editor Settings...", 12);
   EditorMenuBar.addMenuItem("Edit", "Terrain Editor Settings...", 13);

   EditorMenuBar.addMenu("Camera", 7);
   EditorMenuBar.addMenuItem("Camera", "Drop Camera at Player", 1, "Alt Q");
   EditorMenuBar.addMenuItem("Camera", "Drop Player at Camera", 2, "Alt W");
   EditorMenuBar.addMenuItem("Camera", "Toggle Camera", 10, "Alt C");
   EditorMenuBar.addMenuItem("Camera", "-", 0);
   EditorMenuBar.addMenuItem("Camera", "Slowest", 3, "Shift 1", 1);
   EditorMenuBar.addMenuItem("Camera", "Very Slow", 4, "Shift 2", 1);
   EditorMenuBar.addMenuItem("Camera", "Slow", 5, "Shift 3", 1);
   EditorMenuBar.addMenuItem("Camera", "Medium Pace", 6, "Shift 4", 1);
   EditorMenuBar.addMenuItem("Camera", "Fast", 7, "Shift 5", 1);
   EditorMenuBar.addMenuItem("Camera", "Very Fast", 8, "Shift 6", 1);
   EditorMenuBar.addMenuItem("Camera", "Fastest", 9, "Shift 7", 1);

   EditorMenuBar.addMenu("World", 6);
   EditorMenuBar.addMenuItem("World", "Lock Selection", 10, "Ctrl L");
   EditorMenuBar.addMenuItem("World", "Unlock Selection", 11, "Ctrl Shift L");
   EditorMenuBar.addMenuItem("World", "-", 0);
   EditorMenuBar.addMenuItem("World", "Hide Selection", 12, "Ctrl H");
   EditorMenuBar.addMenuItem("World", "Show Selection", 13, "Ctrl Shift H");
   EditorMenuBar.addMenuItem("World", "-", 0);
   EditorMenuBar.addMenuItem("World", "Delete Selection", 17, "Delete");
   EditorMenuBar.addMenuItem("World", "Camera To Selection", 14);
   EditorMenuBar.addMenuItem("World", "Reset Transforms", 15);
   EditorMenuBar.addMenuItem("World", "Drop Selection", 16, "Ctrl D");
   EditorMenuBar.addMenuItem("World", "Add Selection to Instant Group", 17);
   EditorMenuBar.addMenuItem("World", "-", 0);
   EditorMenuBar.addMenuItem("World", "Drop at Origin", 0, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop at Camera", 1, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop at Camera w/Rot", 2, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop below Camera", 3, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop at Screen Center", 4, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop at Centroid", 5, "", 1);
   EditorMenuBar.addMenuItem("World", "Drop to Ground", 6, "", 1);

   EditorMenuBar.addMenu("Action", 3);
   EditorMenuBar.addMenuItem("Action", "Select", 1, "", 1);
   EditorMenuBar.addMenuItem("Action", "Adjust Selection", 2, "", 1);
   EditorMenuBar.addMenuItem("Action", "-", 0);
   EditorMenuBar.addMenuItem("Action", "Add Dirt", 6, "", 1);
   EditorMenuBar.addMenuItem("Action", "Excavate", 6, "", 1);
   EditorMenuBar.addMenuItem("Action", "Adjust Height", 6, "", 1);
   EditorMenuBar.addMenuItem("Action", "Flatten", 4, "", 1);
   EditorMenuBar.addMenuItem("Action", "Smooth", 5, "", 1);
   EditorMenuBar.addMenuItem("Action", "Set Height", 7, "", 1);
   EditorMenuBar.addMenuItem("Action", "-", 0);
   EditorMenuBar.addMenuItem("Action", "Set Empty", 8, "", 1);
   EditorMenuBar.addMenuItem("Action", "Clear Empty", 8, "", 1);
   EditorMenuBar.addMenuItem("Action", "-", 0);
   EditorMenuBar.addMenuItem("Action", "Paint Material", 9, "", 1);

   EditorMenuBar.addMenu("Brush", 4);
   EditorMenuBar.addMenuItem("Brush", "Box Brush", 91, "", 1);
   EditorMenuBar.addMenuItem("Brush", "Circle Brush", 92, "", 1);
   EditorMenuBar.addMenuItem("Brush", "-", 0);
   EditorMenuBar.addMenuItem("Brush", "Soft Brush", 93, "", 2);
   EditorMenuBar.addMenuItem("Brush", "Hard Brush", 94, "", 2);
   EditorMenuBar.addMenuItem("Brush", "-", 0);
   EditorMenuBar.addMenuItem("Brush", "Size 1 x 1", 1, "Alt 1", 3);
   EditorMenuBar.addMenuItem("Brush", "Size 3 x 3", 3, "Alt 2", 3);
   EditorMenuBar.addMenuItem("Brush", "Size 5 x 5", 5, "Alt 3", 3);
   EditorMenuBar.addMenuItem("Brush", "Size 9 x 9", 9, "Alt 4", 3);
   EditorMenuBar.addMenuItem("Brush", "Size 15 x 15", 15, "Alt 5", 3);
   EditorMenuBar.addMenuItem("Brush", "Size 25 x 25", 25, "Alt 6", 3);

   EditorMenuBar.addMenu("Window", 2);
   EditorMenuBar.addMenuItem("Window", "World Editor", 2, "F2", 1);
   EditorMenuBar.addMenuItem("Window", "World Editor Inspector", 3, "F3", 1);
   EditorMenuBar.addMenuItem("Window", "World Editor Creator", 4, "F4", 1);
   EditorMenuBar.addMenuItem("Window", "Mission Area Editor", 5, "F5", 1);
   EditorMenuBar.addMenuItem("Window", "-", 0);
   EditorMenuBar.addMenuItem("Window", "Terrain Editor", 6, "F6", 1);
   EditorMenuBar.addMenuItem("Window", "Terrain Terraform Editor", 7, "F7", 1);
   EditorMenuBar.addMenuItem("Window", "Terrain Texture Editor", 8, "F8", 1);
   EditorMenuBar.addMenuItem("Window", "Terrain Texture Painter", 9, "", 1);

   EditorMenuBar.onActionMenuItemSelect(0, "Adjust Height");
   EditorMenuBar.onBrushMenuItemSelect(0, "Circle Brush");
   EditorMenuBar.onBrushMenuItemSelect(0, "Soft Brush");
   EditorMenuBar.onBrushMenuItemSelect(9, "Size 9 x 9");
   EditorMenuBar.onCameraMenuItemSelect(6, "Medium Pace");
   EditorMenuBar.onWorldMenuItemSelect(0, "Drop at Screen Center");

   EWorldEditor.init();
   ETerrainEditor.attachTerrain();
   TerraformerInit();
   TextureInit();

   //
   Creator.init();
   EditorTree.init();
   ObjectBuilderGui.init();

   EWorldEditor.isDirty = false;
   ETerrainEditor.isDirty = false;
   ETerrainEditor.isMissionDirty = false;
   EditorGui.saveAs = false;
}

function EditorNewMission()
{
   if(ETerrainEditor.isMissionDirty || ETerrainEditor.isDirty || EWorldEditor.isDirty)
   {
      MessageBoxYesNo("Mission Modified", "Would you like to save changes to the current mission \"" @
         $Server::MissionFile @ "\" before creating a new mission?", "EditorDoNewMission(true);", "EditorDoNewMission(false);");
   }
   else
      EditorDoNewMission(false);
}

function EditorSaveMissionMenu()
{
   if(EditorGui.saveAs)
      EditorSaveMissionAs();
   else
      EditorSaveMission();
}

function EditorSaveMission()
{
   // just save the mission without renaming it

   // first check for dirty and read-only files:
   if((EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) && !isWriteableFileName($Server::MissionFile))
   {
      MessageBoxOK("Error", "Mission file \""@ $Server::MissionFile @ "\" is read-only.");
      return false;
   }
   if(ETerrainEditor.isDirty && !isWriteableFileName(Terrain.terrainFile))
   {
      MessageBoxOK("Error", "Terrain file \""@ Terrain.terrainFile @ "\" is read-only.");
      return false;
   }
  
   // now write the terrain and mission files out:

   if(EWorldEditor.isDirty || ETerrainEditor.isMissionDirty)
      MissionGroup.save($Server::MissionFile);
   if(ETerrainEditor.isDirty)
      Terrain.save(Terrain.terrainFile);
   EWorldEditor.isDirty = false;
   ETerrainEditor.isDirty = false;
   ETerrainEditor.isMissionDirty = false;
   EditorGui.saveAs = false;

   return true;
}

function EditorDoSaveAs(%missionName)
{
   ETerrainEditor.isDirty = true;
   EWorldEditor.isDirty = true;
   %saveMissionFile = $Server::MissionFile;
   %saveTerrName = Terrain.terrainFile;

   $Server::MissionFile = %missionName;
   Terrain.terrainFile = filePath(%missionName) @ "/" @ fileBase(%missionName) @ ".ter";

   if(!EditorSaveMission())
   {
      $Server::MissionFile = %saveMissionFile;
      Terrain.terrainFile = %saveTerrName;
   }
}

function EditorSaveMissionAs()
{
   getSaveFilename("*.mis", "EditorDoSaveAs", $Server::MissionFile);

}

function EditorDoLoadMission(%file)
{
   // close the current editor, it will get cleaned up by MissionCleanup
   Editor.close();

   loadMission( %file, true ) ;

   // recreate and open the editor
   Editor::create();
   MissionCleanup.add(Editor);
   EditorGui.loadingMission = true;
   Editor.open();
}

function EditorSaveBeforeLoad()
{
   if(EditorSaveMission())
      getLoadFilename("*.mis", "EditorDoLoadMission");
}

function EditorDoNewMission(%saveFirst)
{
   if(%saveFirst)
      EditorSaveMission();

   %file = findFirstFile("*/newMission.mis");
   if(%file $= "")
   {
      MessageBoxOk("Error", "Missing mission template \"newMission.mis\".");
      return;
   }
   EditorDoLoadMission(%file);
   EditorGui.saveAs = true;
   EWorldEditor.isDirty = true;
   ETerrainEditor.isDirty = true;
}

function EditorOpenMission()
{
   if(ETerrainEditor.isMissionDirty || ETerrainEditor.isDirty || EWorldEditor.isDirty)
   {
      MessageBoxYesNo("Mission Modified", "Would you like to save changes to the current mission \"" @
         $Server::MissionFile @ "\" before opening a new mission?", "EditorSaveBeforeLoad();", "getLoadFilename(\"*.mis\", \"EditorDoLoadMission\");");
   }
   else
      getLoadFilename("*.mis", "EditorDoLoadMission");
}

function EditorMenuBar::onMenuSelect(%this, %menuId, %menu)
{
   if(%menu $= "File")
   {
      %editingHeightfield = ETerrainEditor.isVisible() && EHeightField.isVisible();
      EditorMenuBar.setMenuItemEnable("File", "Export Terraform Bitmap...", %editingHeightfield);
      EditorMenuBar.setMenuItemEnable("File", "Save Mission...", ETerrainEditor.isDirty || ETerrainEditor.isMissionDirty || EWorldEditor.isDirty);
   }
   else if(%menu $= "Edit")
   {
      // enable/disable undo, redo, cut, copy, paste depending on editor settings

      if(EWorldEditor.isVisible())
      {
         // do actions based on world editor...
         EditorMenuBar.setMenuItemEnable("Edit", "Select All", true);
         EditorMenuBar.setMenuItemEnable("Edit", "Paste", EWorldEditor.canPasteSelection());
         %canCutCopy = EWorldEditor.getSelectionSize() > 0;

         EditorMenuBar.setMenuItemEnable("Edit", "Cut", %canCutCopy);
         EditorMenuBar.setMenuItemEnable("Edit", "Copy", %canCutCopy);

      }
      else if(ETerrainEditor.isVisible())
      {
         EditorMenuBar.setMenuItemEnable("Edit", "Cut", false);
         EditorMenuBar.setMenuItemEnable("Edit", "Copy", false);
         EditorMenuBar.setMenuItemEnable("Edit", "Paste", false);
         EditorMenuBar.setMenuItemEnable("Edit", "Select All", false);
      }
   }
   else if(%menu $= "World")
   {
      %selSize = EWorldEditor.getSelectionSize();
      %lockCount = EWorldEditor.getSelectionLockCount();
      %hideCount = EWorldEditor.getSelectionHiddenCount();

      EditorMenuBar.setMenuItemEnable("World", "Lock Selection", %lockCount < %selSize);
      EditorMenuBar.setMenuItemEnable("World", "Unlock Selection", %lockCount > 0);
      EditorMenuBar.setMenuItemEnable("World", "Hide Selection", %hideCount < %selSize);
      EditorMenuBar.setMenuItemEnable("World", "Show Selection", %hideCount > 0);

      EditorMenuBar.setMenuItemEnable("World", "Add Selection to Instant Group", %selSize > 0);
      EditorMenuBar.setMenuItemEnable("World", "Camera To Selection", %selSize > 0);
      EditorMenuBar.setMenuItemEnable("World", "Reset Transforms", %selSize > 0 && %lockCount == 0);
      EditorMenuBar.setMenuItemEnable("World", "Drop Selection", %selSize > 0 && %lockCount == 0);
      EditorMenuBar.setMenuItemEnable("World", "Delete Selection", %selSize > 0 && %lockCount == 0);
   }
}

function EditorMenuBar::onMenuItemSelect(%this, %menuId, %menu, %itemId, %item)
{
   switch$(%menu)
   {
      case "File":
         %this.onFileMenuItemSelect(%itemId, %item);
      case "Edit":
         %this.onEditMenuItemSelect(%itemId, %item);
      case "World":
         %this.onWorldMenuItemSelect(%itemId, %item);
      case "Window":
         %this.onWindowMenuItemSelect(%itemId, %item);
      case "Action":
         %this.onActionMenuItemSelect(%itemId, %item);
      case "Brush":
         %this.onBrushMenuItemSelect(%itemId, %item);
      case "Camera":
         %this.onCameraMenuItemSelect(%itemId, %item);
   }
}

function EditorMenuBar::onFileMenuItemSelect(%this, %itemId, %item)
{
   switch$(%item)
   {
      case "New Mission...":
         EditorNewMission();
      case "Open Mission...":
         EditorOpenMission();
      case "Save Mission...":
         EditorSaveMissionMenu();
      case "Save Mission As...":
         EditorSaveMissionAs();
      case "Import Texture Data...":
         Texture::import();
      case "Import Terraform Data...":
         Heightfield::import();
      case "Export Terraform Bitmap...":
         Heightfield::saveBitmap("");
      case "Quit":
   }
}

function EditorMenuBar::onCameraMenuItemSelect(%this, %itemId, %item)
{
   switch$(%item)
   {
      case "Drop Camera at Player":
         commandToServer('dropCameraAtPlayer');
      case "Drop Player at Camera":
         commandToServer('DropPlayerAtCamera');
      case "Toggle Camera":
         commandToServer('ToggleCamera');
      default:
         // all the rest are camera speeds:
         // item ids go from 3 (slowest) to 9 (fastest)
         %this.setMenuItemChecked("Camera", %itemId, true);
         // camera movement speed goes from 5 to 200:
         $Camera::movementSpeed = ((%itemId - 3) / 6.0) * 195 + 5;
   }
}

function EditorMenuBar::onActionMenuItemSelect(%this, %itemId, %item)
{
   EditorMenuBar.setMenuItemChecked("Action", %item, true);
   switch$(%item)
   {
      case "Select":
         ETerrainEditor.currentMode = "select";
         ETerrainEditor.selectionHidden = false;
         ETerrainEditor.renderVertexSelection = true;
         ETerrainEditor.setAction("select");
      case "Adjust Selection":
         ETerrainEditor.currentMode = "adjust";
         ETerrainEditor.selectionHidden = false;
         ETerrainEditor.setAction("adjustHeight");
         ETerrainEditor.currentAction = brushAdjustHeight;
         ETerrainEditor.renderVertexSelection = true;
      default:
         ETerrainEditor.currentMode = "paint";
         ETerrainEditor.selectionHidden = true;
         ETerrainEditor.setAction(ETerrainEditor.currentAction);
         switch$(%item)
         {
            case "Add Dirt":
               ETerrainEditor.currentAction = raiseHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Paint Material":
               ETerrainEditor.currentAction = paintMaterial;
               ETerrainEditor.renderVertexSelection = true;
            case "Excavate":
               ETerrainEditor.currentAction = lowerHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Set Height":
               ETerrainEditor.currentAction = setHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Adjust Height":
               ETerrainEditor.currentAction = brushAdjustHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Flatten":
               ETerrainEditor.currentAction = flattenHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Smooth":
               ETerrainEditor.currentAction = smoothHeight;
               ETerrainEditor.renderVertexSelection = true;
            case "Set Empty":
               ETerrainEditor.currentAction = setEmpty;
               ETerrainEditor.renderVertexSelection = false;
            case "Clear Empty":
               ETerrainEditor.currentAction = clearEmpty;
               ETerrainEditor.renderVertexSelection = false;
         }
         if(ETerrainEditor.currentMode $= "select")
            ETerrainEditor.processAction(ETerrainEditor.currentAction);
         else if(ETerrainEditor.currentMode $= "paint")
            ETerrainEditor.setAction(ETerrainEditor.currentAction);
   }
}

function EditorMenuBar::onBrushMenuItemSelect(%this, %itemId, %item)
{
   EditorMenuBar.setMenuItemChecked("Brush", %item, true);
   switch$(%item)
   {
      case "Box Brush":
         ETerrainEditor.setBrushType(box);
      case "Circle Brush":
         ETerrainEditor.setBrushType(ellipse);
      case "Soft Brush":
         ETerrainEditor.enableSoftBrushes = true;
      case "Hard Brush":
         ETerrainEditor.enableSoftBrushes = false;
      default:
         // the rest are brush sizes:
         ETerrainEditor.brushSize = %itemId;
         
         ETerrainEditor.setBrushSize(%itemId, %itemId);
   }
}

function EditorMenuBar::onWorldMenuItemSelect(%this, %itemId, %item)
{
   // edit commands for world editor...
   switch$(%item)
   {
      case "Lock Selection":
         EWorldEditor.lockSelection(true);
      case "Unlock Selection":
         EWorldEditor.lockSelection(false);
      case "Hide Selection":
         EWorldEditor.hideSelection(true);
      case "Show Selection":
         EWorldEditor.hideSelection(false);
      case "Camera To Selection":
         EWorldEditor.dropCameraToSelection();
      case "Reset Transforms":
         EWorldEditor.resetTransforms();
      case "Drop Selection":
         EWorldEditor.dropSelection();
      case "Delete Selection":
         EWorldEditor.deleteSelection();
      case "Add Selection to Instant Group":
         EWorldEditor.addSelectionToAddGroup();
      default:
         EditorMenuBar.setMenuItemChecked("World", %item, true);
         switch$(%item)
         {
            case "Drop at Origin":
               EWorldEditor.dropType = "atOrigin";
            case "Drop at Camera":
               EWorldEditor.dropType = "atCamera";
            case "Drop at Camera w/Rot":
               EWorldEditor.dropType = "atCameraRot";
            case "Drop below Camera":
               EWorldEditor.dropType = "belowCamera";
            case "Drop at Screen Center":
               EWorldEditor.dropType = "screenCenter";
            case "Drop to Ground":
               EWorldEditor.dropType = "toGround";
            case "Drop at Centroid":
               EWorldEditor.dropType = "atCentroid";
         }
   }
}

function EditorMenuBar::onEditMenuItemSelect(%this, %itemId, %item)
{
   if(%item $= "World Editor Settings...")
      Canvas.pushDialog(WorldEditorSettingsDlg);
   else if(%item $= "Terrain Editor Settings...")
      Canvas.pushDialog(TerrainEditorValuesSettingsGui, 99);
   else if(%item $= "Relight Scene")
      lightScene("", forceAlways);
   else if(EWorldEditor.isVisible())
   {
      // edit commands for world editor...
      switch$(%item)
      {
         case "Undo":
            EWorldEditor.undo();
         case "Redo":
            EWorldEditor.redo();
         case "Copy":
            EWorldEditor.copySelection();
         case "Cut":
            EWorldEditor.copySelection();
            EWorldEditor.deleteSelection();
         case "Paste":
            EWorldEditor.pasteSelection();
         case "Select All":
         case "Select None":
      }
   }
   else if(ETerrainEditor.isVisible())
   {
      // do some terrain stuffin'
      switch$(%item)
      {
         case "Undo":
            ETerrainEditor.undo();
         case "Redo":
            ETerrainEditor.redo();
         case "Select None":
            ETerrainEditor.clearSelection();
      }
   }
}

function EditorMenuBar::onWindowMenuItemSelect(%this, %itemId, %item)
{
   EditorGui.setEditor(%item);
}

function EditorGui::setWorldEditorVisible(%this)
{
   EWorldEditor.setVisible(true);
   ETerrainEditor.setVisible(false);
   EditorMenuBar.setMenuVisible("World", true);
   EditorMenuBar.setMenuVisible("Action", false);
   EditorMenuBar.setMenuVisible("Brush", false);
   EWorldEditor.makeFirstResponder(true);
}

function EditorGui::setTerrainEditorVisible(%this)
{
   EWorldEditor.setVisible(false);
   ETerrainEditor.setVisible(true);
   ETerrainEditor.attachTerrain();
   EHeightField.setVisible(false);
   ETexture.setVisible(false);
   EditorMenuBar.setMenuVisible("World", false);
   EditorMenuBar.setMenuVisible("Action", true);
   EditorMenuBar.setMenuVisible("Brush", true);
   ETerrainEditor.makeFirstResponder(true);
   EPainter.setVisible(false);
}

function EditorGui::setEditor(%this, %editor)
{
   EditorMenuBar.setMenuItemBitmap("Window", %this.currentEditor, -1);
   EditorMenuBar.setMenuItemBitmap("Window", %editor, 0);
   %this.currentEditor = %editor;

   switch$(%editor)
   {
      case "World Editor":
         EWFrame.setVisible(false);
         EWMissionArea.setVisible(false);
         %this.setWorldEditorVisible();
      case "World Editor Inspector":
         EWFrame.setVisible(true);
         EWMissionArea.setVisible(false);
         EWCreatorPane.setVisible(false);
         EWInspectorPane.setVisible(true);
         %this.setWorldEditorVisible();
      case "World Editor Creator":
         EWFrame.setVisible(true);
         EWMissionArea.setVisible(false);
         EWCreatorPane.setVisible(true);
         EWInspectorPane.setVisible(false);
         %this.setWorldEditorVisible();
      case "Mission Area Editor":
         EWFrame.setVisible(false);
         EWMissionArea.setVisible(true);
         %this.setWorldEditorVisible();
      case "Terrain Editor":
         %this.setTerrainEditorVisible();
      case "Terrain Terraform Editor":
         %this.setTerrainEditorVisible();
         EHeightField.setVisible(true);
      case "Terrain Texture Editor":
         %this.setTerrainEditorVisible();
         ETexture.setVisible(true);
      case "Terrain Texture Painter":
         %this.setTerrainEditorVisible();
         EPainter.setVisible(true);
         EPainter.setup();

   }
}

function EditorGui::getHelpPage(%this)
{
   switch$(%this.currentEditor)
   {
      case "World Editor" or "World Editor Inspector" or "World Editor Creator":
         return "5. World Editor";
      case "Mission Area Editor":
         return "6. Mission Area Editor";
      case "Terrain Editor":
         return "7. Terrain Editor";
      case "Terrain Terraform Editor":
         return "8. Terrain Terraform Editor";
      case "Terrain Texture Editor":
         return "9. Terrain Texture Editor";
      case "Terrain Texture Painter":
         return "10. Terrain Texture Painter";
   }
}


function ETerrainEditor::setPaintMaterial(%this, %matIndex)
{
   ETerrainEditor.paintMaterial = EPainter.mat[%matIndex];
}

function ETerrainEditor::changeMaterial(%this, %matIndex)
{
   EPainter.matIndex = %matIndex;
   getLoadFilename("*/terrains/*.png\t*/terrains/*.jpg", EPainterChangeMat);
}

function EPainterChangeMat(%file)
{
   // make sure the material isn't already in the terrain.
   %file = filePath(%file) @ "/" @ fileBase(%file);
   for(%i = 0; %i < 6; %i++)
      if(EPainter.mat[%i] $= %file)
         return;

   EPainter.mat[EPainter.matIndex] = %file;
   %mats = "";
   for(%i = 0; %i < 6; %i++)
      %mats = %mats @ EPainter.mat[%i] @ "\n";
   ETerrainEditor.setTerrainMaterials(%mats);
   EPainter.setup();
   ("ETerrainMaterialPaint" @ EPainter.matIndex).performClick();
}

function EPainter::setup(%this)
{
   EditorMenuBar.onActionMenuItemSelect(0, "Paint Material");
   %mats = ETerrainEditor.getTerrainMaterials();
   %valid = true;
   for(%i = 0; %i < 6; %i++)
   {
      %mat = getRecord(%mats, %i);
      %this.mat[%i] = %mat;
      ("ETerrainMaterialText" @ %i).setText(fileBase(%mat));
      ("ETerrainMaterialBitmap" @ %i).setBitmap(%mat);
      ("ETerrainMaterialChange" @ %i).setActive(true);
      ("ETerrainMaterialPaint" @ %i).setActive(%mat !$= "");
      if(%mat $= "")
      {
         ("ETerrainMaterialChange" @ %i).setText("Add...");
         if(%valid)
            %valid = false;
         else
            ("ETerrainMaterialChange" @ %i).setActive(false);
      }
      else
         ("ETerrainMaterialChange" @ %i).setText("Change...");
   }
   ETerrainMaterialPaint0.performClick();
}

function EditorGui::onWake(%this)
{
   MoveMap.push();
   EditorMap.push();
   %this.setEditor(%this.currentEditor);
}

function EditorGui::onSleep(%this)
{
   EditorMap.pop();
   MoveMap.pop();
}

function AreaEditor::onUpdate(%this, %area)
{
   AreaEditingText.setValue( "X: " @ getWord(%area,0) @ " Y: " @ getWord(%area,1) @ " W: " @ getWord(%area,2) @ " H: " @ getWord(%area,3));
}

function AreaEditor::onWorldOffset(%this, %offset)
{
}

function EditorTree::init(%this)
{
   %this.open(MissionGroup);

   // context menu
   new GuiControl(ETContextPopupDlg)
   {
      profile = "GuiModelessDialogProfile";
	   horizSizing = "width";
	   vertSizing = "height";
	   position = "0 0";
	   extent = "640 480";
	   minExtent = "8 8";
	   visible = "1";
	   setFirstResponder = "0";
	   modal = "1";
      
      new GuiPopUpMenuCtrl(ETContextPopup)
      {
         profile = "GuiScrollProfile";
         position = "0 0";
         extent = "0 0";
         minExtent = "0 0";
         maxPopupHeight = "200";
         command = "canvas.popDialog(ETContextPopupDlg);";
      };
   };
   ETContextPopup.setVisible(false);
}

function EditorTree::onInspect(%this, %obj)
{
   Inspector.inspect(%obj);
   InspectorNameEdit.setValue(%obj.getName());
}

function EditorTree::onSelect(%this, %obj)
{
   if($AIEdit)   
      aiEdit.selectObject(%obj);
   else
      EWorldEditor.selectObject(%obj);

}

function EditorTree::onUnselect(%this, %obj)
{
   if($AIEdit)
      aiEdit.unselectObject(%obj);
   else
      EWorldEditor.unselectObject(%obj);
}

function ETContextPopup::onSelect(%this, %index, %value)
{
   switch(%index)
   {
      case 0:
         EditorTree.contextObj.delete();
   }
}

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------

function WorldEditor::init(%this)
{
   // add objclasses which we do not want to collide with
   %this.ignoreObjClass(TerrainBlock, Sky, AIObjective);

   // editing modes
   %this.numEditModes = 3;
   %this.editMode[0]    = "move";
   %this.editMode[1]    = "rotate";
   %this.editMode[2]    = "scale";

   // context menu
   new GuiControl(WEContextPopupDlg)
   {
      profile = "GuiModelessDialogProfile";
	   horizSizing = "width";
	   vertSizing = "height";
	   position = "0 0";
	   extent = "640 480";
	   minExtent = "8 8";
	   visible = "1";
	   setFirstResponder = "0";
	   modal = "1";
      
      new GuiPopUpMenuCtrl(WEContextPopup)
      {
         profile = "GuiScrollProfile";
         position = "0 0";
         extent = "0 0";
         minExtent = "0 0";
         maxPopupHeight = "200";
         command = "canvas.popDialog(WEContextPopupDlg);";
      };
   };
   WEContextPopup.setVisible(false);
}

//------------------------------------------------------------------------------

function WorldEditor::onDblClick(%this, %obj)
{
   // Commented out because making someone double click to do this is stupid
   // and has the possibility of moving hte object
   
   //Inspector.inspect(%obj);
   //InspectorNameEdit.setValue(%obj.getName());
}

function WorldEditor::onClick( %this, %obj )
{
   Inspector.inspect( %obj );
   InspectorNameEdit.setValue( %obj.getName() );
}

//------------------------------------------------------------------------------

function WorldEditor::export(%this)
{
   getSaveFilename("~/editor/*.mac", %this @ ".doExport", "selection.mac");
}

function WorldEditor::doExport(%this, %file)
{
   missionGroup.save("~/editor/" @ %file, true);
}

function WorldEditor::import(%this)
{
   getLoadFilename("~/editor/*.mac", %this @ ".doImport");
}

function WorldEditor::doImport(%this, %file)
{
   exec("~/editor/" @ %file);
}

function WorldEditor::onGuiUpdate(%this, %text)
{
}

function WorldEditor::getSelectionLockCount(%this)
{
   %ret = 0;
   for(%i = 0; %i < %this.getSelectionSize(); %i++)
   {
      %obj = %this.getSelectedObject(%i);
      if(%obj.locked $= "true")
         %ret++;
   }
   return %ret;
}

function WorldEditor::getSelectionHiddenCount(%this)
{
   %ret = 0;
   for(%i = 0; %i < %this.getSelectionSize(); %i++)
   {
      %obj = %this.getSelectedObject(%i);
      if(%obj.hidden $= "true")
         %ret++;
   }
   return %ret;
}

function WorldEditor::dropCameraToSelection(%this)
{
   if(%this.getSelectionSize() == 0)
      return;

   %pos = %this.getSelectionCentroid();
   %cam = LocalClientConnection.camera.getTransform();

   // set the pnt
   %cam = setWord(%cam, 0, getWord(%pos, 0));
   %cam = setWord(%cam, 1, getWord(%pos, 1));
   %cam = setWord(%cam, 2, getWord(%pos, 2));

   LocalClientConnection.camera.setTransform(%cam);
}

// * pastes the selection at the same place (used to move obj from a group to another)
function WorldEditor::moveSelectionInPlace(%this)
{
   %saveDropType = %this.dropType;
   %this.dropType = "atCentroid";
   %this.copySelection();
   %this.deleteSelection();
   %this.pasteSelection();
   %this.dropType = %saveDropType;
}

function WorldEditor::addSelectionToAddGroup(%this)
{
   for(%i = 0; %i < %this.getSelectionSize(); %i++) {
      %obj = %this.getSelectedObject(%i);
      $InstantGroup.add(%obj);
   }

}   
// resets the scale and rotation on the selection set
function WorldEditor::resetTransforms(%this)
{
   %this.addUndoState();

   for(%i = 0; %i < %this.getSelectionSize(); %i++)
   {
      %obj = %this.getSelectedObject(%i);
      %transform = %obj.getTransform();

      %transform = setWord(%transform, 3, "0");
      %transform = setWord(%transform, 4, "0");
      %transform = setWord(%transform, 5, "1");
      %transform = setWord(%transform, 6, "0");
         
      //
      %obj.setTransform(%transform);
      %obj.setScale("1 1 1");
   }
}


function WorldEditorToolbarDlg::init(%this)
{
   WorldEditorInspectorCheckBox.setValue(WorldEditorToolFrameSet.isMember("EditorToolInspectorGui"));
   WorldEditorMissionAreaCheckBox.setValue(WorldEditorToolFrameSet.isMember("EditorToolMissionAreaGui"));
   WorldEditorTreeCheckBox.setValue(WorldEditorToolFrameSet.isMember("EditorToolTreeViewGui"));
   WorldEditorCreatorCheckBox.setValue(WorldEditorToolFrameSet.isMember("EditorToolCreatorGui"));
}

function Creator::init( %this ) 
{
   %this.clear();

   $InstantGroup = "MissionGroup";

   // ---------- INTERIORS    
   %base = %this.addGroup( 0, "Interiors" );

   // walk all the interiors and add them to the correct group
   %interiorId = "";
   %file = findFirstFile( "*.dif" );
   
   while( %file !$= "" ) 
   {
      // Determine which group to put the file in
      // and build the group heirarchy as we go
      %split    = strreplace(%file, "/", " ");
      %dirCount = getWordCount(%split)-1;
      %parentId = %base;
      
      for(%i=0; %i<%dirCount; %i++)
      {
         %parent = getWords(%split, 0, %i);
         // if the group doesn't exist create it
         if ( !%interiorId[%parent] )
            %interiorId[%parent] = %this.addGroup( %parentId, getWord(%split, %i));
         %parentId = %interiorId[%parent];
      }
      // Add the file to the group
      %create = "createInterior(" @ "\"" @ %file @ "\"" @ ");";
      %this.addItem( %parentId, fileBase( %file ), %create );
   
      %file = findNextFile( "*.dif" );
   }


   // ---------- SHAPES - add in all the shapes now...
   %base = %this.addGroup(0, "Shapes");
   %dataGroup = "DataBlockGroup";
   
   for(%i = 0; %i < %dataGroup.getCount(); %i++)
   {
      %obj = %dataGroup.getObject(%i);
      echo ("Obj: " @ %obj.getName() @ " - " @ %obj.category );
      if(%obj.category !$= "" || %obj.category != 0)
      {
         %grp = %this.addGroup(%base, %obj.category);
         %this.addItem(%grp, %obj.getName(), %obj.getClassName() @ "::create(" @ %obj.getName() @ ");");
      }
   }


   // ---------- Static Shapes    
   %base = %this.addGroup( 0, "Static Shapes" );

   // walk all the statics and add them to the correct group
   %staticId = "";
   %file = findFirstFile( "*.dts" );
   while( %file !$= "" ) 
   {
      // Determine which group to put the file in
      // and build the group heirarchy as we go
      %split    = strreplace(%file, "/", " ");
      %dirCount = getWordCount(%split)-1;
      %parentId = %base;
      
      for(%i=0; %i<%dirCount; %i++)
      {
         %parent = getWords(%split, 0, %i);
         // if the group doesn't exist create it
         if ( !%staticId[%parent] )
            %staticId[%parent] = %this.addGroup( %parentId, getWord(%split, %i));
         %parentId = %staticId[%parent];
      }
      // Add the file to the group
      %create = "TSStatic::create(\"" @ %file @ "\");";
      %this.addItem( %parentId, fileBase( %file ), %create );
   
      %file = findNextFile( "*.dts" );
   }


   // *** OBJECTS - do the objects now...
   %objGroup[0] = "Environment";
   %objGroup[1] = "Mission";
   %objGroup[2] = "System";
   //%objGroup[3] = "AI";

   %Environment_Item[0]  = "Sky";
   %Environment_Item[1]  = "Sun";
   %Environment_Item[2]  = "Lightning";
   %Environment_Item[3]  = "Water";
   %Environment_Item[4]  = "Terrain";
   %Environment_Item[5]  = "AudioEmitter";
   %Environment_Item[6]  = "Precipitation";
   %Environment_Item[7]  = "ParticleEmitter";
   %Environment_Item[8]  = "fxSunLight";
   %Environment_Item[9]  = "fxShapeReplicator";
   %Environment_Item[10] = "fxFoliageReplicator";
   %Environment_Item[11] = "fxLightDB";
   %Environment_Item[12] = "fxLight";

   %Mission_Item[0] = "MissionArea";
   %Mission_Item[1] = "Marker";
   %Mission_Item[2] = "Trigger";
   %Mission_Item[3] = "PhysicalZone";
   %Mission_Item[4] = "Camera";
   //%Mission_Item[5] = "GameType";
   //%Mission_Item[6] = "Forcefield";

   %System_Item[0] = "SimGroup";

   //%AI_Item[0] = "Objective";
   //%AI_Item[1] = "NavigationGraph";

   // objects group
   %base = %this.addGroup(0, "Mission Objects");

   // create 'em
   for(%i = 0; %objGroup[%i] !$= ""; %i++)
   {
      %grp = %this.addGroup(%base, %objGroup[%i]);

      %groupTag = "%" @ %objGroup[%i] @ "_Item";

      %done = false;
      for(%j = 0; !%done; %j++)
      {
         eval("%itemTag = " @ %groupTag @ %j @ ";");
         if(%itemTag $= "")
            %done = true;
         else
            %this.addItem(%grp, %itemTag, "ObjectBuilderGui.build" @ %itemTag @ "();");
      }
   }
}

function createInterior(%name)
{
   %obj = new InteriorInstance()
   {
      position = "0 0 0";
      rotation = "0 0 0";
      interiorFile = %name;
   };
   
   return(%obj);
}

function Creator::onAction(%this)
{
//   %this.currentSel = -1;
//   %this.currentRoot = -1;
//   %this.currentObj = -1;

   %sel = %this.getSelected();
   if(%sel == -1 || %this.isGroup(%sel) || !$missionRunning)
      return;
      
   // the value is the callback function..
   if(%this.getValue(%sel) $= "")
      return;

//   %this.currentSel = %sel;
//   %this.currentRoot = %this.getRootGroup(%sel);

   %this.create(%sel);
}

function Creator::create(%this, %sel)
{
   // create the obj and add to the instant group
   %obj = eval(%this.getValue(%sel));

   if(%obj == -1 || %obj == 0)
      return;

//   %this.currentObj = %obj;

   $InstantGroup.add(%obj);
      
   // drop it from the editor - only SceneObjects can be selected...
   EWorldEditor.clearSelection();
   EWorldEditor.selectObject(%obj);
   EWorldEditor.dropSelection();
}


function TSStatic::create(%shapeName)
{
   %obj = new TSStatic() 
   {
      shapeName = %shapeName;
   };
   return(%obj);
}

function TSStatic::damage(%this)
{
   // prevent console error spam
}


//function Creator::getRootGroup(%sel)
//{
//   if(%sel == -1 || %sel == 0)
//      return(-1);
//
//   %parent = %this.getParent(%sel);
//   while(%parent != 0 || %parent != -1)
//   {
//      %sel = %parent;
//      %parent = %this.getParent(%sel);
//   }
//
//   return(%sel);
//}
//   
//function Creator::getLastItem(%rootGroup)
//{
//   %traverse = %rootGroup + 1;
//   while(%this.getRootGroup(%traverse) == %rootGroup)
//      %traverse++;
//   return(%traverse - 1);
//}
//
//function Creator::createNext(%this)
//{
//   if(%this.currentSel == -1 || %this.currentRoot == -1 || %this.currentObj == -1)
//      return;
//
//   %sel = %this.currentSel;
//   %this.currentSel++;
//
//   while(%this.currentSel != %sel)
//   {
//      if(%this.getRootGroup(%this.currentSel) != %this.currentRoot)
//         %this.currentSel = %this.currentRoot + 1;
//
//      if(%this.isGroup(%this.currentSel))
//         %this.currentSel++;
//      else
//         %sel = %this.currentSel;
//   }
//
//   //
//   %this.currentObj.delete();
//   %this.create(%sel);
//}
//
//function Creator::createPrevious(%this)
//{
//   if(%this.currentSel == -1 || %this.currentGroup == -1 || %this.currentObj == -1)
//      return;
//
//   %sel = %this.currentSel;
//   %this.currentSel--;
//
//   while(%this.currentSel != %sel)
//   {
//      if(%this.getRootGroup(%this.currentSel) != %this.currentRoot)
//         %this.currentSel = getLastItem(%this.currentRoot);
//
//      if(%this.isGroup(%this.currentSel))
//         %this.currentSel--;
//      else
//         %sel = %this.currentSel;
//   }
//
//   //
//   %this.currentObj.delete();
//   %this.create(%sel);
//}


function TerraformerGui::init(%this)
{
   TerraformerHeightfieldGui.init();
   TerraformerTextureGui.init();
}

function TerraformerGui::onWake(%this)
{
   // Only the canvas level gui's get wakes, so udpate manually.
   TerraformerTextureGui.update();
}

function TerraformerGui::onSleep(%this)
{
   %this.setPrefs();
}

$nextTextureId = 1;
$nextTextureRegister = 1000;
$selectedMaterial = -1;
$selectedTextureOperation = -1;
$TerraformerTextureDir = "common/editor/textureScripts";

//--------------------------------------

function TextureInit()
{
   // Assumes the terrain object is called terrain
   
   Texture_operation_menu.clear();
   Texture_operation_menu.setText("Placement Operations");
   Texture_operation_menu.add("Place by Fractal", 1);
   Texture_operation_menu.add("Place by Height", 2);
   Texture_operation_menu.add("Place by Slope", 3);
   Texture_operation_menu.add("Place by Water Level", 4);

   $HeightfieldSrcRegister = Heightfield_operation.rowCount()-1;

   // sync up the preview windows
   TexturePreview.setValue(HeightfieldPreview.getValue());
   %script = terrain.getTextureScript();
   if(%script !$= "")
      Texture::loadFromScript(%script);

   if (Texture_material.rowCount() == 0)
   {
      Texture_operation.clear();
      $nextTextureRegister = 1000;
   }
   else
   {
      // it's difficult to tell if the heightfield was modified so 
      // just in case flag all dependent operations as dirty.
      %rowCount = Texture_material.rowCount();
      for (%row = 0; %row < %rowCount; %row++)
      {
         %data = Texture_material.getRowText(%row);
         %entry= getRecord(%data,0);
         %reg  = getField(%entry,1);
         $dirtyTexture[ %reg ] = true;

         %opCount = getRecordCount(%data);
         for (%op = 2; %op < %opCount; %op++)
         {
            %entry= getRecord(%data,%op);
            %label= getField(%entry,0);
            if (%label !$= "Place by Fractal" && %label !$= "Fractal Distortion")
            {
               %reg  = getField(%entry,2);
               $dirtyTexture[ %reg ] = true;
            }
         }
      }
      Texture::previewMaterial();   
   }
}

function TerraformerTextureGui::refresh(%this)
{
}   


//--------------------------------------
function Texture_material_menu::onSelect(%this, %id, %text)
{
   %this.setText("Materials");

   // FORMAT
   //   material name
   //   register
   //     operation
   //       name
   //       tab name
   //       register
   //       distortion register
   //       {field,value}, ...
   //     operation
   //       ...
   Texture::saveMaterial();
   Texture::hideTab();   
   %id = Texture::addMaterial(%text @ "\t" @ $nextTextureRegister++);
   
   if (%id != -1)
   {
      Texture_material.setSelectedById(%id);
      Texture::addOperation("Fractal Distortion\ttab_DistortMask\t" @ $nextTextureRegister++ @ "\t0\tdmask_interval\t20\tdmask_rough\t0\tdmask_seed\t" @ terraFormer.generateSeed() @ "\tdmask_filter\t0.00000 0.00000 0.13750 0.487500 0.86250 1.00000 1.00000");
   }
}   


function Texture::addMaterialTexture()
{
   %root = filePath(terrain.terrainFile);
   getLoadFilename("*/terrains/*.png\t*/terrains/*.jpg", addLoadedMaterial);
}

function addLoadedMaterial(%file)
{
   Texture::saveMaterial();
   Texture::hideTab();   
   %text = filePath(%file) @ "/" @ fileBase(%file);
   %id = Texture::addMaterial(%text @ "\t" @ $nextTextureRegister++);
   if (%id != -1)
   {
      Texture_material.setSelectedById(%id);
      Texture::addOperation("Fractal Distortion\ttab_DistortMask\t" @ $nextTextureRegister++ @ "\t0\tdmask_interval\t20\tdmask_rough\t0\tdmask_seed\t" @ terraFormer.generateSeed() @ "\tdmask_filter\t0.00000 0.00000 0.13750 0.487500 0.86250 1.00000 1.00000");
   }
   Texture::save();
}

//--------------------------------------
function Texture_material::onSelect(%this, %id, %text) 
{
   Texture::saveMaterial();
   if (%id != $selectedMaterial)
   {
      $selectedTextureOperation = -1;
      Texture_operation.clear();
      
      Texture::hideTab();
      Texture::restoreMaterial(%id);
   }

   %matName = getField(%text, 0);
   ETerrainEditor.paintMaterial = %matName;

   Texture::previewMaterial(%id);
   $selectedMaterial = %id;
   $selectedTextureOperation = -1;
   Texture_operation.clearSelection();
}   


//--------------------------------------
function Texture_operation_menu::onSelect(%this, %id, %text)
{
   %this.setText("Placement Operations");
   %id = -1;

   if ($selectedMaterial == -1)
      return;

   %dreg = getField(Texture_operation.getRowText(0),2);
                     
   switch$ (%text)
   {
      case "Place by Fractal":
         %id = Texture::addOperation("Place by Fractal\ttab_FractalMask\t" @ $nextTextureRegister++ @ "\t" @ %dreg @ "\tfbmmask_interval\t16\tfbmmask_rough\t0.000\tfbmmask_seed\t" @ terraFormer.generateSeed() @ "\tfbmmask_filter\t0.000000 0.166667 0.333333 0.500000 0.666667 0.833333 1.000000\tfBmDistort\ttrue");

      case "Place by Height":
         %id = Texture::addOperation("Place by Height\ttab_HeightMask\t" @ $nextTextureRegister++ @ "\t" @ %dreg @ "\ttextureHeightFilter\t0 0.2 0.4 0.6 0.8 1.0\theightDistort\ttrue");

      case "Place by Slope":
         %id = Texture::addOperation("Place by Slope\ttab_SlopeMask\t" @ $nextTextureRegister++ @ "\t" @ %dreg @ "\ttextureSlopeFilter\t0 0.2 0.4 0.6 0.8 1.0\tslopeDistort\ttrue");

      case "Place by Water Level":
         %id = Texture::addOperation("Place by Water Level\ttab_WaterMask\t" @ $nextTextureRegister++ @ "\t" @ %dreg @ "\twaterDistort\ttrue");
   }

   // select it
   Texture::hideTab();
   if (%id != -1)
      Texture_operation.setSelectedById(%id);
}   


//--------------------------------------
function Texture_operation::onSelect(%this, %id, %text)
{
   Texture::saveOperation();   
   if (%id !$= $selectedTextureOperation)   
   {
      Texture::hideTab();   
      Texture::restoreOperation(%id);
      Texture::showTab(%id);   
   }

   Texture::previewOperation(%id);
   $selectedTextureOperation = %id;
}   


//--------------------------------------
function Texture::deleteMaterial(%id)
{
   if (%id $= "")
      %id = $selectedMaterial;
   if (%id == -1)   
      return;
   
   %row = Texture_material.getRowNumById(%id);
   
   Texture_material.removeRow(%row);

   // find the next row to select
   %rowCount = Texture_material.rowCount()-1;
   if (%row > %rowCount)
      %row = %rowCount;

   if (%id == $selectedMaterial)
      $selectedMaterial = -1;

   Texture_operation.clear();
   %id = Texture_material.getRowId(%row);
   Texture_material.setSelectedById(%id);
   Texture::save();
}   


//--------------------------------------
function Texture::deleteOperation(%id)
{
   if (%id $= "")
      %id = $selectedTextureOperation;
   if (%id == -1)   
      return;
   
   %row = Texture_operation.getRowNumById(%id);
   
   // don't delete the first entry
   if (%row == 0)
      return;
   
   Texture_operation.removeRow(%row);

   // find the next row to select
   %rowCount = Texture_operation.rowCount()-1;
   if (%row > %rowCount)
      %row = %rowCount;

   if (%id == $selectedTextureOperation)
      $selectedTextureOperation = -1;

   %id = Texture_operation.getRowId(%row);
   Texture_operation.setSelectedById(%id);
   Texture::save();
}   


//--------------------------------------
function Texture::applyMaterials()
{
   Texture::saveMaterial();
   %count = Texture_material.rowCount();
   if (%count > 0)   
   {
      %data = getRecord(Texture_material.getRowText(0),0);
      %mat_list = getField( %data, 0);
      %reg_list = getField( %data, 1);
      Texture::evalMaterial(Texture_material.getRowId(0));
      
      for (%i=1; %i<%count; %i++)
      {
         Texture::evalMaterial(Texture_material.getRowId(%i));
         %data = getRecord(Texture_material.getRowText(%i),0);
         %mat_list = %mat_list @ " " @ getField( %data, 0);
         %reg_list = %reg_list @ " " @ getField( %data, 1);
      }
      terraformer.setMaterials(%reg_list, %mat_list);
   }
}   


//--------------------------------------
function Texture::previewMaterial(%id)
{
   if (%id $= "")
      %id = $selectedMaterial;
   if (%id == -1)
      return;

   %data = Texture_material.getRowTextById(%id);
   %row  = Texture_material.getRowNumById(%id);
   %reg  = getField(getRecord(%data,0),1);

   Texture::evalMaterial(%id);

   terraformer.preview(TexturePreview, %reg);
}   


//--------------------------------------
function Texture::evalMaterial(%id)
{
   if (%id $= "")
      %id = $selectedMaterial;
   if (%id == -1)   
      return;

   %data = Texture_material.getRowTextbyId(%id);
   %reg  = getField(getRecord(%data,0), 1);

   // make sure all operation on this material are up to date
   // and accumulate register data for each
   %opCount = getRecordCount(%data);
   if (%opCount >= 2)    // record0=material record1=fractal
   {
      %entry = getRecord(%data, 1);
      Texture::evalOperationData(%entry, 1);
      for (%op=2; %op<%opCount; %op++)
      {
         %entry = getRecord(%data, %op);
         %reg_list = %reg_list @ getField(%entry, 2) @ " ";
         Texture::evalOperationData(%entry, %op);
      }
      // merge the masks in to the dst reg
      terraformer.mergeMasks(%reg_list, %reg);
   }
   Texture::save();
}   


//--------------------------------------
function Texture::evalOperation(%id)
{
   if (%id $= "")
      %id = $selectedTextureOperation;
   if (%id == -1)   
      return;
   
   %data   = Texture_operation.getRowTextById(%id);
   %row    = Texture_operation.getRowNumById(%id);
   
   if (%row != 0)    
      Texture::evalOperation( Texture_operation.getRowId(0) );

   Texture::evalOperationData(%data, %row);
   Texture::save();
}   


//--------------------------------------
function Texture::evalOperationData(%data, %row)
{
   %label  = getField(%data, 0);
   %reg    = getField(%data, 2);
   %dreg   = getField(%data, 3);
   %id     = Texture_material.getRowId(%row);

   if ( $dirtyTexture[%reg] == false )
   {
      return;
   }

   switch$ (%label)
   {
      case "Fractal Distortion":
         terraformer.maskFBm( %reg, getField(%data,5), getField(%data,7), getField(%data,9), getField(%data,11), false, 0 );

      case "Place by Fractal":
         terraformer.maskFBm( %reg, getField(%data,5), getField(%data,7), getField(%data,9), getField(%data,11), getField(%data,13), %dreg );

      case "Place by Height":
         terraformer.maskHeight( $HeightfieldSrcRegister, %reg, getField(%data,5), getField(%data,7), %dreg );

      case "Place by Slope":
         terraformer.maskSlope( $HeightfieldSrcRegister, %reg, getField(%data,5), getField(%data,7), %dreg );

      case "Place by Water Level":
         terraformer.maskWater( $HeightfieldSrcRegister, %reg, getField(%data,5), %dreg );
   }


   $dirtyTexture[%reg] = false;
}   



//--------------------------------------
function Texture::previewOperation(%id)
{
   if (%id $= "")
      %id = $selectedTextureOperation;
   if (%id == -1)
      return;

   %row  = Texture_operation.getRowNumById(%id);
   %data = Texture_operation.getRowText(%row);
   %reg  = getField(%data,2);

   Texture::evalOperation(%id);
   terraformer.preview(TexturePreview, %reg);
}   



//--------------------------------------
function Texture::restoreMaterial(%id)
{
   if (%id == -1)
      return;

   %data = Texture_material.getRowTextById(%id);
   
   Texture_operation.clear();
   %recordCount = getRecordCount(%data);
   for (%record=1; %record<%recordCount; %record++)
   {
      %entry = getRecord(%data, %record);
      Texture_operation.addRow($nextTextureId++, %entry);
   }
}   


//--------------------------------------
function Texture::saveMaterial()
{
   %id = $selectedMaterial;
   if (%id == -1)
      return;

   Texture::SaveOperation();
   %data = Texture_Material.getRowTextById(%id);
   %newData = getRecord(%data,0);

   %rowCount = Texture_Operation.rowCount();
   for (%row=0; %row<%rowCount; %row++)
      %newdata = %newdata @ "\n" @ Texture_Operation.getRowText(%row);

   Texture_Material.setRowById(%id, %newdata);
   Texture::save();
}   


//--------------------------------------
function Texture::restoreOperation(%id)
{
   if (%id == -1)
      return;

   %data = Texture_operation.getRowTextById(%id);

   %fieldCount = getFieldCount(%data);
   for (%field=4; %field<%fieldCount; %field += 2)
   {
      %obj = getField(%data, %field);
      %obj.setValue( getField(%data, %field+1) );
   }
   Texture::save();
}   


//--------------------------------------
function Texture::saveOperation()
{
   %id = $selectedTextureOperation;
   if (%id == -1)
      return;

   %data = Texture_operation.getRowTextById(%id);
   %newData = getField(%data,0) @ "\t" @ getField(%data,1) @ "\t" @ getField(%data,2) @ "\t" @ getField(%data,3); 

   // go through each object and update its value
   %fieldCount = getFieldCount(%data);
   for (%field=4; %field<%fieldCount; %field += 2)
   {
      %obj = getField(%data, %field);
      %newdata = %newdata @ "\t" @ %obj @ "\t" @ %obj.getValue();
   }

   %dirty = (%data !$= %newdata);
   %reg   = getField(%data, 2);
   $dirtyTexture[%reg] = %dirty;
      
   Texture_operation.setRowById(%id, %newdata);

   // mark the material register as dirty too
   if (%dirty == true)
   {
      %data = Texture_Material.getRowTextById($selectedMaterial);
      %reg  = getField(getRecord(%data,0), 1);
      $dirtyTexture[ %reg ] = true;
   }

   // if row is zero the fractal mask was modified
   // mark everything else in the list as dirty
    %row = Texture_material.getRowNumById(%id);
    if (%row == 0)
    {
       %rowCount = Texture_operation.rowCount();
       for (%r=1; %r<%rowCount; %r++)
       {
          %data = Texture_operation.getRowText(%r);
          $dirtyTexture[ getField(%data,2) ] = true;
       }
   }
   Texture::save();
}   


//--------------------------------------
function Texture::addMaterial(%entry)
{
   %id = $nextTextureId++;
   Texture_material.addRow(%id, %entry);
   
   %reg = getField(%entry, 1);
   $dirtyTexture[%reg] = true;

   Texture::save();
   return %id;
}   

//--------------------------------------
function Texture::addOperation(%entry)
{
   // Assumes: operation is being added to selected material

   %id = $nextTextureId++;
   Texture_operation.addRow(%id, %entry);

   %reg = getField(%entry, 2);
   $dirtyTexture[%reg] = true;

   Texture::save();
   return %id;
}   


//--------------------------------------
function Texture::save()
{
   %script = "";

   // loop through each operation and save it to disk
   %rowCount = Texture_material.rowCount();
   for(%row = 0; %row < %rowCount; %row++)
   {
      if(%row != 0)
         %script = %script @ "\n";
      %data = expandEscape(Texture_material.getRowText(%row));
      %script = %script @ %data;
   }
   terrain.setTextureScript(%script);
   ETerrainEditor.isDirty = true;
}

//--------------------------------------
function Texture::import()
{
   getLoadFilename("*.ter", "Texture::doLoadTexture");
}   

function Texture::loadFromScript(%script)
{
   Texture_material.clear();
   Texture_operation.clear();
   $selectedMaterial = -1;
   $selectedTextureOperation = -1;

   %i = 0;
   for(%rec = getRecord(%script, %i); %rec !$= ""; %rec = getRecord(%script, %i++))
      Texture::addMaterial(collapseEscape(%rec));
   // initialize dirty register array
   // patch up register usage
   // ...and deterime what the next register should be.
   $nextTextureRegister = 1000;
   %rowCount = Texture_material.rowCount();
   for (%row = 0; %row < %rowCount; %row++)
   {
      $dirtyTexture[ $nextTextureRegister ] = true;
      %data    = Texture_material.getRowText(%row);
      %rec     = getRecord(%data, 0);
      %rec     = setField(%rec, 1, $nextTextureRegister);
      %data    = setRecord(%data, 0, %rec);
      $nextTextureRegister++;
      
      %opCount = getRecordCount(%data);
      for (%op = 1; %op < %opCount; %op++)
      {
         if (%op == 1)
            %frac_reg = $nextTextureRegister;
         $dirtyTexture[ $nextTextureRegister ] = true;
         %rec  = getRecord(%data,%op);
         %rec  = setField(%rec, 2, $nextTextureRegister);
         %rec  = setField(%rec, 3, %frac_reg);
         %data = setRecord(%data, %op, %rec);
         $nextTextureRegister++;
      }
      %id = Texture_material.getRowId(%row);
      Texture_material.setRowById(%id, %data);
   }

   $selectedMaterial = -1;
   Texture_material.setSelectedById(Texture_material.getRowId(0));
}

//--------------------------------------
function Texture::doLoadTexture(%name)
{
   // ok, we're getting a terrain file...
   %newTerr = new TerrainBlock() // unnamed - since we'll be deleting it shortly:
   {
      position = "0 0 0";
      terrainFile = %name;
      squareSize = 8;
      visibleDistance = 100;
   };
   if(isObject(%newTerr))
   {
      %script = %newTerr.getTextureScript();
      if(%script !$= "")
         Texture::loadFromScript(%script);
      %newTerr.delete();
   }   
}   



//--------------------------------------
function Texture::hideTab()
{
   tab_DistortMask.setVisible(false);   
   tab_FractalMask.setVisible(false);   
   tab_HeightMask.setVisible(false);   
   tab_SlopeMask.setVisible(false);   
   tab_waterMask.setVisible(false);   
}   


//--------------------------------------
function Texture::showTab(%id)
{
   Texture::hideTab();
   %data = Texture_operation.getRowTextById(%id);
   %tab  = getField(%data,1);
   %tab.setVisible(true);
}   



$TerraformerHeightfieldDir = "common/editor/heightScripts";

function tab_Blend::reset(%this)
{
   blend_option.clear();
   blend_option.add("Add", 0);
   blend_option.add("Subtract", 1);
   blend_option.add("Max", 2);
   blend_option.add("Min", 3);
   blend_option.add("Multiply", 4);
}

function tab_fBm::reset(%this)
{
   fBm_detail.clear();
   fBm_detail.add("Very Low", 0);
   fBm_detail.add("Low", 1);
   fBm_detail.add("Normal", 2);
   fBm_detail.add("High", 3);
   fBm_detail.add("Very High", 4);
}

function tab_RMF::reset(%this)
{
   rmf_detail.clear();
   rmf_detail.add("Very Low", 0);
   rmf_detail.add("Low", 1);
   rmf_detail.add("Normal", 2);
   rmf_detail.add("High", 3);
   rmf_detail.add("Very High", 4);
}

function tab_terrainFile::reset(%this)
{
   // update tab controls..
   terrainFile_textList.clear();

   %filespec = $TerraformerHeightfieldDir @ "/*.ter";
   for(%file = findFirstFile(%filespec); %file !$= ""; %file = findNextFile(%filespec))
      terrainFile_textList.addRow(%i++, fileBase(%file) @ fileExt(%file));
}

function tab_canyon::reset()
{
}

function tab_smooth::reset()
{
}

function tab_smoothWater::reset()
{
}

function tab_smoothRidge::reset()
{
}

function tab_filter::reset()
{
}

function tab_turbulence::reset()
{
}

function tab_thermal::reset()
{
}

function tab_hydraulic::reset()
{
}

function tab_general::reset()
{
}

function tab_bitmap::reset()
{
}

function tab_sinus::reset()
{
}


//--------------------------------------

function Heightfield::resetTabs()
{
   tab_terrainFile.reset();
   tab_fbm.reset();
   tab_rmf.reset();
   tab_canyon.reset();
   tab_smooth.reset();
   tab_smoothWater.reset();
   tab_smoothRidge.reset();
   tab_filter.reset();
   tab_turbulence.reset();
   tab_thermal.reset();
   tab_hydraulic.reset();
   tab_general.reset();
   tab_bitmap.reset();
   tab_blend.reset();
   tab_sinus.reset();
}

//--------------------------------------
function TerraformerInit()
{
   Heightfield_options.clear();   
   Heightfield_options.setText("Operation");   
   Heightfield_options.add("fBm Fractal",0);
   Heightfield_options.add("Rigid MultiFractal",1);
   Heightfield_options.add("Canyon Fractal",2);
   Heightfield_options.add("Sinus",3);
   Heightfield_options.add("Bitmap",4);
   Heightfield_options.add("Turbulence",5);
   Heightfield_options.add("Smoothing",6);
   Heightfield_options.add("Smooth Water",7);
   Heightfield_options.add("Smooth Ridges/Valleys", 8);
   Heightfield_options.add("Filter",9);
   Heightfield_options.add("Thermal Erosion",10);
   Heightfield_options.add("Hydraulic Erosion",11);
   Heightfield_options.add("Blend",12);
   Heightfield_options.add("Terrain File",13);

   Heightfield::resetTabs();

   %script = Terrain.getHeightfieldScript();
   if(%script !$= "")
      Heightfield::loadFromScript(%script,true);

   if (Heightfield_operation.rowCount() == 0)
   {
      Heightfield_operation.clear();
      %id1 = Heightfield::add("General\tTab_general\tgeneral_min_height\t50\tgeneral_scale\t300\tgeneral_water\t0.000\tgeneral_centerx\t0\tgeneral_centery\t0");
      Heightfield_operation.setSelectedById(%id1);
   }

   Heightfield::resetTabs();
   Heightfield::preview();
}   

//--------------------------------------
function Heightfield_options::onSelect(%this, %_id, %text)
{
   Heightfield_options.setText("Operation");
   %id = -1;

   %rowCount = Heightfield_operation.rowCount();

   // FORMAT
   //  item name
   //  tab name
   //    control name 
   //    control value
   switch$(%text)
   {
      case "Terrain File":
         %id = HeightField::add("Terrain File\ttab_terrainFile\tterrainFile_terrFileText\tterrains/terr1.ter\tterrainFile_textList\tterr1.ter");

      case "fBm Fractal":
         %id = Heightfield::add("fBm Fractal\ttab_fBm\tfbm_interval\t9\tfbm_rough\t0.000\tfBm_detail\tNormal\tfBm_seed\t" @ terraformer.generateSeed());

      case "Rigid MultiFractal":
         %id = Heightfield::add("Rigid MultiFractal\ttab_RMF\trmf_interval\t4\trmf_rough\t0.000\trmf_detail\tNormal\trmf_seed\t" @ terraformer.generateSeed());

      case "Canyon Fractal":
         %id = Heightfield::add("Canyon Fractal\ttab_Canyon\tcanyon_freq\t5\tcanyon_factor\t0.500\tcanyon_seed\t" @ terraformer.generateSeed());
   
      case "Sinus":
         %id = Heightfield::add("Sinus\ttab_Sinus\tsinus_filter\t1 0.83333 0.6666 0.5 0.33333 0.16666 0\tsinus_seed\t" @ terraformer.generateSeed());
   
      case "Bitmap":
         %id = Heightfield::add("Bitmap\ttab_Bitmap\tbitmap_name\t");
         Heightfield::setBitmap();
   }


   if (Heightfield_operation.rowCount() >= 1)
   {
      switch$(%text)
      {
         case "Smoothing":
            %id = Heightfield::add("Smoothing\ttab_Smooth\tsmooth_factor\t0.500\tsmooth_iter\t0");
   
         case "Smooth Water":
            %id = Heightfield::add("Smooth Water\ttab_SmoothWater\twatersmooth_factor\t0.500\twatersmooth_iter\t0");

         case "Smooth Ridges/Valleys":
            %id = Heightfield::add("Smooth Ridges/Valleys\ttab_SmoothRidge\tridgesmooth_factor\t0.8500\tridgesmooth_iter\t1");
   
         case "Filter":
            %id = Heightfield::add("Filter\ttab_Filter\tfilter\t0 0.16666667 0.3333333 0.5 0.6666667 0.8333333 1");
   
         case "Turbulence":
            %id = Heightfield::add("Turbulence\ttab_Turbulence\tturbulence_factor\t0.250\tturbulence_radius\t10");
   
         case "Thermal Erosion":
            %id = Heightfield::add("Thermal Erosion\ttab_Thermal\tthermal_slope\t30\tthermal_cons\t80.0\tthermal_iter\t0");
   
         case "Hydraulic Erosion":
            %id = Heightfield::add("Hydraulic Erosion\ttab_Hydraulic\thydraulic_iter\t0\thydraulic_filter\t0 0.16666667 0.3333333 0.5 0.6666667 0.8333333 1");
      }
   }

   if (Heightfield_operation.rowCount() >= 2)
   {
      if("Blend" $= %text)
         %id = Heightfield::add("Blend\ttab_Blend\tblend_factor\t0.500\tblend_srcB\t" @ %rowCount-2 @"\tblend_option\tadd");
   }

   
   // select it
   if (%id != -1)
      Heightfield_operation.setSelectedById(%id);
}   


//--------------------------------------
function Heightfield::eval(%id)
{
   if (%id == -1)   
      return;
   
   %data  = restWords(Heightfield_operation.getRowTextById(%id));
   %label = getField(%data,0);
   %row   = Heightfield_operation.getRowNumById(%id);
    
   echo("Heightfield::eval:" @ %row @ "  " @ %label );

   switch$(%label)
   {
      case "General":
         if (Terrain.squareSize>0) %size = Terrain.squareSize;
         else %size = 8;
         terraformer.setTerrainInfo( 256, %size, getField(%data,3), getField(%data,5), getField(%data,7) );
         terraformer.setShift( getField(%data,9), getField(%data,11) );
         terraformer.terrainData(%row);

      case "Terrain File":
         terraformer.terrainFile(%row, getField(%data,3));

      case "fBm Fractal":
         terraformer.fBm( %row, getField(%data,3), getField(%data,5), getField(%data,7), getField(%data,9) );

      case "Sinus":
         terraformer.sinus( %row, getField(%data,3), getField(%data,5) );
    
      case "Rigid MultiFractal":
         terraformer.rigidMultiFractal( %row, getField(%data,3), getField(%data,5), getField(%data,7), getField(%data,9) );
    
      case "Canyon Fractal":
         terraformer.canyon( %row, getField(%data,3), getField(%data,5), getField(%data,7) );
   
      case "Smoothing":
         terraformer.smooth( %row-1, %row, getField(%data,3), getField(%data,5) );
       
      case "Smooth Water":
         terraformer.smoothWater( %row-1, %row, getField(%data,3), getField(%data,5) );
       
      case "Smooth Ridges/Valleys":
         terraformer.smoothRidges( %row-1, %row, getField(%data,3), getField(%data,5) );

      case "Filter":
         terraformer.filter( %row-1, %row, getField(%data,3) );
       
      case "Turbulence":
         terraformer.turbulence( %row-1, %row, getField(%data,3), getField(%data,5) );
       
      case "Thermal Erosion":
         terraformer.erodeThermal( %row-1, %row, getField(%data,3), getField(%data,5),getField(%data,7) );
       
      case "Hydraulic Erosion":
         terraformer.erodeHydraulic( %row-1, %row, getField(%data,3), getField(%data,5) );
       
      case "Bitmap":
         terraformer.loadGreyscale(%row, getField(%data,3));

      case "Blend":
         %rowCount = Heightfield_operation.rowCount();
         if(%rowCount > 2) 
         {
            %a = Heightfield_operation.getRowNumById(%id)-1;
            %b = getField(%data, 5);
            echo("Blend: " @ %data);
            echo("Blend: " @ getField(%data,3) @ "  " @ getField(%data,7));
            if(%a < %rowCount || %a > 0 || %b < %rowCount || %b > 0 ) 
               terraformer.blend(%a, %b, %row, getField(%data,3), getField(%data,7) );
            else
               echo("Heightfield Editor: Blend parameters out of range.");
         }
   }

}   

//--------------------------------------
function Heightfield::add(%entry)
{
   Heightfield::saveTab();
   Heightfield::hideTab();

   %id = $NextOperationId++;
   if ($selectedOperation != -1)
   {
      %row = Heightfield_operation.getRowNumById($selectedOperation) + 1;
      %entry = %row @ " " @ %entry;
      Heightfield_operation.addRow(%id, %entry, %row); // insert

      // adjust row numbers
      for(%i = %row+1; %i < Heightfield_operation.rowCount(); %i++)
      {
         %id = Heightfield_operation.getRowId(%i);
         %text = Heightfield_operation.getRowTextById(%id);
         %text = setWord(%text, 0, %i);
         Heightfield_operation.setRowById(%id, %text);
      }
   }
   else
   {
      %entry = Heightfield_operation.rowCount() @ " " @ %entry;
      Heightfield_operation.addRow(%id, %entry);   // add to end
   }

   %row = Heightfield_operation.getRowNumById(%id);
   if (%row <= $HeightfieldDirtyRow)
      $HeightfieldDirtyRow = %row;
   Heightfield::save();
   return %id;
}   


//--------------------------------------
function Heightfield::onDelete(%id)
{
   if (%id $= "")
      %id = $selectedOperation;

   %row = Heightfield_operation.getRowNumById(%id);
   
   // don't delete the first entry
   if (%row == 0)
      return;

   Heightfield_operation.removeRow(%row);
   
   // adjust row numbers
   for(%i = %row; %i < Heightfield_operation.rowCount(); %i++)
   {
      %id2 = Heightfield_operation.getRowId(%i);
      %text = Heightfield_operation.getRowTextById(%id2);
      %text = setWord(%text, 0, %i);
      Heightfield_operation.setRowById(%id2, %text);
   }

   // adjust the Dirty Row position
   if ($HeightfieldDirtyRow >= %row)
      $HeightfieldDirtyRow = %row;   
   
   // find the next row to select
   %rowCount = Heightfield_operation.rowCount()-1;
   if (%row > %rowCount)
      %row = %rowCount;

   if (%id == $selectedOperation)
      $selectedOperation = -1;

   %id = Heightfield_operation.getRowId(%row);
   Heightfield_operation.setSelectedById(%id);
   Heightfield::save();
}   


//--------------------------------------
function Heightfield_operation::onSelect(%this, %id, %text)
{
   Heightfield::saveTab();
   Heightfield::hideTab();

   $selectedOperation = %id; 
   Heightfield::restoreTab($selectedOperation);
   Heightfield::showTab($selectedOperation);
   Heightfield::preview($selectedOperation);
}   


//--------------------------------------
function Heightfield::restoreTab(%id)
{
   if (%id == -1)   
      return;

   Heightfield::hideTab();
   
   %data = restWords(Heightfield_operation.getRowTextById(%id));

   %fieldCount = getFieldCount(%data);
   for (%field=2; %field<%fieldCount; %field += 2)
   {
      %obj = getField(%data, %field);
      %obj.setValue( getField(%data, %field+1) );
   }
   Heightfield::save();
}  

 
//--------------------------------------
function Heightfield::saveTab()
{
   if ($selectedOperation == -1)   
      return;
   
   %data = Heightfield_operation.getRowTextById($selectedOperation);

   %rowNum = getWord(%data, 0);
   %data = restWords(%data);   
   %newdata = getField(%data,0) @ "\t" @ getField(%data,1);

   %fieldCount = getFieldCount(%data);
   for (%field=2; %field < %fieldCount; %field += 2)
   {
      %obj = getField(%data, %field);
      %newdata = %newdata @ "\t" @ %obj @ "\t" @ %obj.getValue();
   }
   // keep track of the top-most dirty operation
   // so we know who to evaluate later
   if (%data !$= %newdata)
   {
      %row = Heightfield_operation.getRowNumById($selectedOperation);
      if (%row <= $HeightfieldDirtyRow && %row > 0)
         $HeightfieldDirtyRow = %row;
   }

   Heightfield_operation.setRowById($selectedOperation, %rowNum @ " " @ %newdata);
   Heightfield::save();
}  


//--------------------------------------
function Heightfield::preview(%id)
{
   %rowCount = Heightfield_operation.rowCount();
   if (%id $= "")
      %id = Heightfield_operation.getRowId(%rowCount-1);

   %row = Heightfield_operation.getRowNumById(%id);

   Heightfield::refresh(%row);
   terraformer.previewScaled(HeightfieldPreview, %row);
}   


//--------------------------------------
function Heightfield::refresh(%last)
{
   if (%last $= "")   
      %last = Heightfield_operation.rowCount()-1;

   // always update the general info
   Heightfield::eval(Heightfield_operation.getRowId(0));

   for( 0; $HeightfieldDirtyRow<=%last; $HeightfieldDirtyRow++)
   {
      %id = Heightfield_operation.getRowId($HeightfieldDirtyRow);
      Heightfield::eval(%id);
   }
   Heightfield::save();
}   


//--------------------------------------
function Heightfield::apply(%id)
{
   %rowCount = Heightfield_operation.rowCount();
   if (%rowCount < 1)
      return;
   if (%id $= "")
      %id = Heightfield_operation.getRowId(%rowCount-1);

   %row = Heightfield_operation.getRowNumById(%id);

   HeightfieldPreview.setRoot();
   Heightfield::refresh(%row);
   terraformer.setTerrain(%row);

   terraformer.setCameraPosition(0,0,0); 
   ETerrainEditor.isDirty = true;
}   

//--------------------------------------
$TerraformerSaveRegister = 0;
function Heightfield::saveBitmap(%name)
{
   if(%name $= "")
      getSaveFilename("*.png", "Heightfield::doSaveBitmap",
         $TerraformerHeightfieldDir @ "/" @ fileBase($Client::MissionFile) @ ".png");
   else
      Heightfield::doSaveBitmap(%name);
}

function Heightfield::doSaveBitmap(%name)
{        
   terraformer.saveGreyscale($TerraformerSaveRegister, %name);
}

//--------------------------------------

function Heightfield::save()
{
   %script = "";
   %rowCount = Heightfield_operation.rowCount();
   for(%row = 0; %row < %rowCount; %row++)
   {
      if(%row != 0)
         %script = %script @ "\n";
      %data = restWords(Heightfield_operation.getRowText(%row));
      %script = %script @ expandEscape(%data);
   }
   terrain.setHeightfieldScript(%script);
   ETerrainEditor.isDirty = true;
}

//--------------------------------------
function Heightfield::import()
{
   getLoadFilename("*.ter", "Heightfield::doLoadHeightfield");
}   


//--------------------------------------
function Heightfield::loadFromScript(%script,%leaveCamera)
{
   echo(%script);

   Heightfield_operation.clear();
   $selectedOperation = -1;
   $HeightfieldDirtyRow = -1;

   // zero out all shifting
   HeightfieldPreview.reset();

   for(%rec = getRecord(%script, %i); %rec !$= ""; %rec = getRecord(%script, %i++))
      Heightfield::add(collapseEscape(%rec));

   if (Heightfield_operation.rowCount() == 0)
   {
      // if there was a problem executing the script restore
      // the operations list to a known state
      Heightfield_operation.clear();
      Heightfield::add("General\tTab_general\tgeneral_min_height\t50\tgeneral_scale\t300\tgeneral_water\t0.000\tgeneral_centerx\t0\tgeneral_centery\t0");
   }
   %data = restWords(Heightfield_operation.getRowText(0));
   %x = getField(%data,7); 
   %y = getField(%data,9); 
   HeightfieldPreview.setOrigin(%x, %y);
   Heightfield_operation.setSelectedById(Heightfield_operation.getRowId(0));

   // Move the control object to the specified position
   if (!%leaveCamera)
      terraformer.setCameraPosition(%x,%y); 
}   

//--------------------------------------
function strip(%stripStr, %strToStrip)
{
   %len = strlen(%stripStr);
   if(strcmp(getSubStr(%strToStrip, 0, %len), %stripStr) == 0)
      return getSubStr(%strToStrip, %len, 100000);
   return %strToStrip;
}

function Heightfield::doLoadHeightfield(%name)
{
   // ok, we're getting a terrain file...

   %newTerr = new TerrainBlock() // unnamed - since we'll be deleting it shortly:
   {
      position = "0 0 -1000";
      terrainFile = strip("terrains/", %name);
      squareSize = 8;
      visibleDistance = 100;
   };
   if(isObject(%newTerr))
   {
      %script = %newTerr.getHeightfieldScript();
      if(%script !$= "")
         Heightfield::loadFromScript(%script);
      %newTerr.delete();
   }   
}   


//--------------------------------------
function Heightfield::setBitmap()
{
   getLoadFilename($TerraformerHeightfieldDir @ "/*.png", "Heightfield::doSetBitmap");
}   

//--------------------------------------
function Heightfield::doSetBitmap(%name)
{
   bitmap_name.setValue(%name);
   Heightfield::saveTab();
   Heightfield::preview($selectedOperation);
}   


//--------------------------------------
function Heightfield::hideTab()
{
   tab_terrainFile.setVisible(false);
   tab_fbm.setvisible(false);
   tab_rmf.setvisible(false);
   tab_canyon.setvisible(false);
   tab_smooth.setvisible(false);
   tab_smoothWater.setvisible(false);
   tab_smoothRidge.setvisible(false);
   tab_filter.setvisible(false);
   tab_turbulence.setvisible(false);
   tab_thermal.setvisible(false);
   tab_hydraulic.setvisible(false);
   tab_general.setvisible(false);
   tab_bitmap.setvisible(false);
   tab_blend.setvisible(false);
   tab_sinus.setvisible(false);
}


//--------------------------------------
function Heightfield::showTab(%id)
{
   Heightfield::hideTab();
   %data = restWords(Heightfield_operation.getRowTextById(%id));
   %tab  = getField(%data,1);
   echo("Tab data: " @ %data @ " tab: " @ %tab);
   %tab.setVisible(true);
}


//--------------------------------------
function Heightfield::center()
{
   %camera = terraformer.getCameraPosition(); 
   %x = getWord(%camera, 0);
   %y = getWord(%camera, 1);

   HeightfieldPreview.setOrigin(%x, %y);

   %origin = HeightfieldPreview.getOrigin();
   %x = getWord(%origin, 0);
   %y = getWord(%origin, 1);

   %root = HeightfieldPreview.getRoot();
   %x += getWord(%root, 0);
   %y += getWord(%root, 1);

   general_centerx.setValue(%x);
   general_centery.setValue(%y);
   Heightfield::saveTab();
}   

function ExportHeightfield::onAction()
{
   error("Time to export the heightfield...");
   if (Heightfield_operation.getSelectedId() != -1) {
      $TerraformerSaveRegister = getWord(Heightfield_operation.getValue(), 0);
      Heightfield::saveBitmap("");
   }
}

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------

function TerrainEditor::onGuiUpdate(%this, %text)
{
   %mouseBrushInfo = " (Mouse Brush) #: " @ getWord(%text, 0) @ "  avg: " @ getWord(%text, 1);
   %selectionInfo = " (Selection) #: " @ getWord(%text, 2) @ "  avg: " @ getWord(%text, 3);
   
   TEMouseBrushInfo.setValue(%mouseBrushInfo);
   TEMouseBrushInfo1.setValue(%mouseBrushInfo);
   TESelectionInfo.setValue(%selectionInfo);
   TESelectionInfo1.setValue(%selectionInfo);
}

function TerrainEditor::offsetBrush(%this, %x, %y)
{
   %curPos = %this.getBrushPos();
   %this.setBrushPos(getWord(%curPos, 0) + %x, getWord(%curPos, 1) + %y);
}

function TerrainEditor::swapInLoneMaterial(%this, %name)
{
   // swapped?
   if(%this.baseMaterialsSwapped $= "true")
   {
      %this.baseMaterialsSwapped = "false";
      tEditor.popBaseMaterialInfo();
   }
   else
   {
      %this.baseMaterialsSwapped = "true";
      %this.pushBaseMaterialInfo();
      %this.setLoneBaseMaterial(%name);
   }
      
   //
   flushTextureCache();
}

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------


function TELoadTerrainButton::onAction(%this)
{
   getLoadFilename("terrains/*.ter", %this @ ".gotFileName");
}

function TELoadTerrainButton::gotFileName(%this, %name)
{
   //
   %pos = "0 0 0";
   %squareSize = "8";
   %visibleDistance = "1200";

   // delete current
   if(isObject(terrain))
   {
      %pos = terrain.position;
      %squareSize = terrain.squareSize;
      %visibleDistance = terrain.visibleDistance;

      terrain.delete();
   }

   // create new
   new TerrainBlock(terrain)
   {
      position = %pos;
      terrainFile = %name;
      squareSize = %squareSize;
      visibleDistance = %visibleDistance;
   };

   ETerrainEditor.attachTerrain();
}

function TerrainEditorSettingsGui::onWake(%this)
{
   TESoftSelectFilter.setValue(ETerrainEditor.softSelectFilter);
}

function TerrainEditorSettingsGui::onSleep(%this)
{
   ETerrainEditor.softSelectFilter = TESoftSelectFilter.getValue();
}

function TESettingsApplyButton::onAction(%this)
{
   ETerrainEditor.softSelectFilter = TESoftSelectFilter.getValue();
   ETerrainEditor.resetSelWeights(true);
   ETerrainEditor.processAction("softSelect");
}

function getPrefSetting(%pref, %default)
{
   // 
   if(%pref $= "")
      return(%default);
   else
      return(%pref);
}

//------------------------------------------------------------------------------

function Editor::open(%this)
{
   %this.prevContent = Canvas.getContent();

   Canvas.setContent(EditorGui);
}

function Editor::close(%this)
{
   if(%this.prevContent == -1 || %this.prevContent $= "")
      %this.prevContent = "PlayGui";

   Canvas.setContent(%this.prevContent);

   MessageHud.close();
}

//------------------------------------------------------------------------------
