// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation; either version 2 of the License, or
//   (at your option) any later version.
//  
//   This program is distributed in the hope that it will be useful, but
//   WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//   General Public License for more details.
// 
//   You should have received a copy of the GNU General Public License
//   along with this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;

#include "../uijunk/widget.h"
#include "../uijunk/widgetcontainer.h"
#include "../uijunk/widgetbutton.h"
#include "../uijunk/widgettext.h"
#include "../uijunk/widgetpaddedbox.h"
#include "../uijunk/widgetradiogroup.h"
#include "../uijunk/widgetselectchild.h"
#include "../uijunk/widgetscrollable.h"
#include "../uijunk/widgetslider.h"
#include "../uijunk/widgetalignedbox.h"

#include "../texturemanager/texturemanager.h"
#include "../texturemanager/texture.h"

#include "../filesystem/filesystem.h"

#include "../string/string.h"

#include "../console/console.h"
using namespace Console;

#include "filewindow.h"
#include "world.h"
#include "junkeditor.h"
#include "editorui.h"

// This is so we can make sure mouse events don't escape the JunkUI.
static bool mouseEnterOrLeaveEvent(Widget *w, void *junkEditor) {
	JunkEditor *realEditor = (JunkEditor*)junkEditor;
	
	if(w->mouseWasOverMe) {
		realEditor->mouseOverAWidget = true;
	} else {
		realEditor->mouseOverAWidget = false;
	}
	
	return false;
}

static bool consoleKeyDown(Widget *w, void *data) {

	JunkEditor *editor = (JunkEditor*)data;
	WidgetText *textWidget = dynamic_cast<WidgetText*>(w);

	const WidgetEvent *event = widgetGetEvent();
	
	if(event) {
		
		if(event->keyboard.keyCode == WIDGET_KEY_UP || event->keyboard.keyCode == WIDGET_KEY_DOWN) {
			
			// Console history.
			
			if(event->keyboard.keyCode == WIDGET_KEY_UP) {
				editor->historyPosition--;
				if(editor->historyPosition < 0) editor->historyPosition = 0;
			} else {
				editor->historyPosition++;
				if(editor->historyPosition > (int)editor->consoleHistory.size()) editor->historyPosition = (int)editor->consoleHistory.size();
			}

			if(editor->historyPosition >= (int)editor->consoleHistory.size()) {
				textWidget->setText("");
			} else {
				textWidget->setText(editor->consoleHistory[editor->historyPosition]);
			}
			
			return true;
		}
		
	}
	
	return false;
}

static bool consoleTextChanged(Widget *w, void *data) {

	JunkEditor *editor = (JunkEditor*)data;
	WidgetText *textWidget = dynamic_cast<WidgetText*>(w);
	
	if(textWidget) {
		
		string line = textWidget->getText();
		
		if(line.size() && line[line.size() - 1] == '\n') {
			
			// Done entering command. User entered a newline.
			
			// Strip off that last LF.
			string realLine = line.substr(0, line.size() - 1);
			
			// Execute command.
			editor->addConsoleCommand(line);
			
			// Add it to the history.
			editor->consoleHistory.push_back(realLine);
			editor->historyPosition = editor->consoleHistory.size();
			
			// Clear the entry.
			textWidget->setText("");
		}
	
	}
	
	return false;
}

// Callback for all entity palette buttons.
static bool entAddCallback(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	WidgetButton *button = dynamic_cast<WidgetButton*>(w);
	
	if(button) {
		
		editor->nextEntName = button->getLabel();
	}
	
	return false;

}

// Tile file name entry callback.
static bool tileFilenameChanged(Widget *w, void *data) {

	JunkEditor *editor = (JunkEditor*)data;
	WidgetText *textWidget = dynamic_cast<WidgetText*>(w);
	
	editor->newTilesFile = textWidget->getText();
	
	return false;
}

// Callback for tile size input.
static bool tileSizeChanged(Widget *w, void *data) {

	JunkEditor *editor = (JunkEditor*)data;
	WidgetText *textWidget = dynamic_cast<WidgetText*>(w);
	
	int fixedValue = atoi(textWidget->getText().c_str());
	
	// Make sure it's a power of two.
	bool foundIt = false;
	for(int i = 4; i < 10; i++) { // Min tile size is 16.
		if(fixedValue == 1 << i) {
			foundIt = true;
			break;
		}
	}
	
	// I have no idea what the user entered. Drop to default.
	if(!foundIt) {
		fixedValue = 32;
	}

	// Set the text widget.
	ostringstream str;
	str << fixedValue;
	textWidget->setText(str.str());
	
	// Set the value.
	editor->tileSize = fixedValue;
	
	return false;
}

// Some reasonable defaults for buttons, for lack of default setting
// sanity in the JunkUI system.
void setJunkEditorButtonDefaults(WidgetButton *button) {
	
	// Old - But might go back to this.
	//button->setBackgroundImage("editordata/1pxbox1.ninepatch");
	//button->setBackgroundDefault("editordata/1pxbox1.ninepatch");
	//button->setBackgroundMouseOver("editordata/1pxbox3.ninepatch");
	//button->setBackgroundActive("editordata/1pxbox2.ninepatch");
	
	button->setBackgroundImage("editordata/transparentbutton1.ninepatch");
	button->setBackgroundDefault("editordata/transparentbutton1.ninepatch");
	button->setBackgroundActive("editordata/transparentbutton1_md.ninepatch");
	button->setBackgroundMouseOver("editordata/transparentbutton1_mo.ninepatch");
}

void setJunkEditorSliderDefaults(WidgetSlider *slider) {
	slider->setThingyImage("editordata/transparentbutton1.ninepatch");
	slider->setBackgroundImage("editordata/transparentbutton1_md.ninepatch");
	slider->setMinWidth(16);
	slider->setMinHeight(16);
	slider->setThingySize(32);
}

void setJunkEditorCheckboxDefaults(WidgetButton *button) {

    button->setBackgroundImage("editordata/checked.tga");
    button->setBackgroundDefault("editordata/unchecked.tga");
    button->setBackgroundActive("editordata/checked.tga");
    button->setBackgroundMouseOver("editordata/checking.tga");

    button->setLabel("");
    button->setToggleable(true);
    button->setMinWidth(16);
    button->setMinHeight(16);
    button->setLabelPadding(0);

}

static bool newButtonConfirmed(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	editor->wantClearData = true;
	editor->levelFileName = "";
	
	// Pop the confirm dialog.
	editor->rootWidgetStack.erase(editor->rootWidgetStack.end() - 1);

	return false;
}

static bool popDialog(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	editor->rootWidgetStack.erase(editor->rootWidgetStack.end() - 1);
	return false;
}

static bool newButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	editor->rootWidgetStack.push_back(editor->newFileConfirm);

	return false;
}

// Load button callback.
static bool loadButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	vector<string> fileNames;
	vector<string> unfilteredNames;

	// FIXME: Include common assets?
	FileSystem::getNondirectories(string("games/") + editor->gameName + "/levels/", unfilteredNames);
	
	sort(fileNames.begin(), fileNames.end());
	
	FileSystem::filterFileListByType("xml", unfilteredNames, fileNames);

	editor->loadWindow->setFileList(fileNames);
	editor->loadWindow->setDefaultFileName(editor->levelFileName);
	editor->rootWidgetStack.push_back(editor->loadWindow->getWidget());

	return false;
}

// Save as button callback.
static bool saveAsButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	vector<string> fileNames;
	vector<string> unfilteredNames;

	// FIXME: Include common assets?
	FileSystem::getNondirectories(string("games/") + editor->gameName + "/levels/", unfilteredNames);
	
	sort(fileNames.begin(), fileNames.end());
	
	FileSystem::filterFileListByType("xml", unfilteredNames, fileNames);
	
	editor->saveWindow->setFileList(fileNames);
	editor->saveWindow->setDefaultFileName(editor->levelFileName);
	editor->rootWidgetStack.push_back(editor->saveWindow->getWidget());

	return false;
}

// Save button callback.
static bool saveButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	if(!editor->levelFileName.size()) {
		
		// If we don't have a level file name, treat it as a "save 
		// button click instead.
		return saveAsButtonClicked(w, data);
	}
	
	//editor->nextSaveName = string("levels/") + editor->levelFileName;
	
	if(editor->gameName.size()) {
		editor->nextSaveName = string("games/") + editor->gameName + "/levels/" + editor->levelFileName;
	} else {
		editor->nextSaveName = string("games/common/levels/") + editor->levelFileName;
	}

	return false;
}

// Save window confirm button callback.
static bool saveAsButtonReturned(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;

	//editor->nextSaveName = string("levels/") + editor->saveWindow->getSelectedFile();
	
	if(editor->gameName.size()) {
		editor->nextSaveName = string("games/") + editor->gameName + "/levels/" + editor->saveWindow->getSelectedFile();
	} else {
		editor->nextSaveName = string("games/common/levels/") + editor->saveWindow->getSelectedFile();
	}
	
	if(!strEndsWith(".xml", editor->nextSaveName)) {
		editor->nextSaveName = editor->nextSaveName + ".xml";
	}
	
	editor->levelFileName = editor->saveWindow->getSelectedFile();
	
	popDialog(w, data);

	return false;
}

// Load window confirm button callback.
static bool loadButtonReturned(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	//editor->nextLoadName = string("levels/") + editor->loadWindow->getSelectedFile();
	
	if(editor->gameName.size()) {
		editor->nextLoadName = string("games/") + editor->gameName + "/levels/" + editor->loadWindow->getSelectedFile();
	} else {
		editor->nextLoadName = string("games/common/levels/") + editor->loadWindow->getSelectedFile();
	}
	
	editor->levelFileName = editor->loadWindow->getSelectedFile();
	
	popDialog(w, data);
	
	return false;
}

// Browse button callback from the tile pane.
static bool tileFileButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	vector<string> fileNames;
	vector<string> unfilteredNames;
	//FileSystem::getNondirectories("gamedata/data", unfilteredNames);
	
	FileSystem::getNondirectories(string("games/") + editor->gameName + "/tilesets", unfilteredNames);
	FileSystem::getNondirectories(string("games/common/tilesets"), unfilteredNames);
	
	sort(fileNames.begin(), fileNames.end());

	FileSystem::filterFileListByType("tga,metatex", unfilteredNames, fileNames);
	
	editor->tileFileWindow->setFileList(fileNames);
	
	if(editor->tab_tileFilename->getText().size() > 5) {
		editor->tileFileWindow->setDefaultFileName(editor->tab_tileFilename->getText().c_str() + 5);
	} else {
		editor->tileFileWindow->setDefaultFileName("");
	}
	
	editor->rootWidgetStack.push_back(editor->tileFileWindow->getWidget());
	
	return false;
}

// Tile file window confirm button callback.
static bool tileFileButtonReturned(Widget *w, void *data) {

	JunkEditor *editor = (JunkEditor*)data;
	
	editor->newTilesFile = editor->tileFileWindow->getSelectedFile();
	
	editor->tab_tileFilename->setText(editor->newTilesFile);

	editor->tileSize = 32;

	popDialog(w, data);

	return false;
}

static bool lightsChanged(Widget *w, void *data) {

    JunkEditor *editor = (JunkEditor*)data;
    editor->lightsDirty = true;

    return false;
}

static bool editorAlternateToggle(Widget *w, void *data) {
	
	// FIXME: This feels really hacky. JunkEditor probably needs a
	//   function for doing this very thing.
	
	JunkEditor *editor = (JunkEditor*)data;
	
	Widget *tmp = editor->hiddenRoot;
	editor->hiddenRoot = editor->getTopWidget();
	editor->rootWidgetStack.erase(editor->rootWidgetStack.end() - 1);
	editor->rootWidgetStack.push_back(tmp);
	
	editor->mouseOverAWidget = editor->getTopWidget() == editor->getRootWidget();
	
	return false;
}

static void setupLightSlider(WidgetSlider *slider, JunkEditor *editor) {
    
    setJunkEditorSliderDefaults(slider);

    slider->setVertical(false);
    slider->setMaxValue(1);
    slider->setSmallStep(0.01);
    slider->setBigStep(0.1);
    slider->setNativeEventHandler("onValueChanged", lightsChanged, editor);
}

static WidgetAlignedBox *makeAlignedBoxAround(Widget *w) {
    
    WidgetAlignedBox *newBox = new WidgetAlignedBox();

    //newBox->setHAlign(1);
    newBox->setChild(w);

    return newBox;
}

static bool toggleLayerVisibility(Widget *w, void *data) {

    World *world = (World*)data;
    WidgetButton *button = dynamic_cast<WidgetButton*>(w);

    vector<string> tokens;
    stringTokenize(w->getName(), "_", tokens);

    int layerNum = atoi(tokens[2].c_str());
    bool visible = button->getToggleValue();

    world->setLayerVisible(layerNum, visible);

    return false;
}

static bool layer_swapCurrentPrev(Widget *w, void *data) {
    
    World *world = (World*)data;
    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    world->swapLayers(currentLayer, currentLayer - 1);

    // Add undo actions!
    world->getEditor()->addUndoAction(
        "Layer move up",
        boost::bind(
            &World::swapLayers,
            world,
            currentLayer,
            currentLayer - 1));

    if(currentLayer > 0) currentLayer--;
    world->getEditor()->junkInterface.setActiveLayer(currentLayer);

    world->forceEditorUpdateLayerList();

    return false;
}

static bool layer_swapCurrentNext(Widget *w, void *data) {

    World *world = (World*)data;
    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    world->swapLayers(currentLayer, currentLayer + 1);

    // Add undo actions!
    world->getEditor()->addUndoAction(
        "Layer move down",
        boost::bind(
            &World::swapLayers,
            world,
            currentLayer,
            currentLayer + 1));

    if(currentLayer < world->getNumLayers() - 1) currentLayer++;
    world->getEditor()->junkInterface.setActiveLayer(currentLayer);

    world->forceEditorUpdateLayerList();

    // FIXME: Add undo actions!

    return false;
}

static bool layer_setName(Widget *w, void *data) {

    WidgetText *textBox = dynamic_cast<WidgetText*>(w);
    World *world = (World*)data;

    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    world->setLayerName(currentLayer, textBox->getText());

    return false;
}

static bool layer_setCamScale(Widget *w, void *data) {

    WidgetText *textBox = dynamic_cast<WidgetText*>(w);
    World *world = (World*)data;

    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    world->setCamScaleForLayer(currentLayer, atof(textBox->getText().c_str()));

    return false;
}

static bool layer_addNewLayer(Widget *w, void *data) {

    World *world = (World*)data;
    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    int totalLayers = world->getNumLayers();

    world->createLayer();

    // Move the layer into place.
    for(int i = totalLayers; i != currentLayer; i--) {

        world->getEditor()->addUndoAction(
            "New layer shifting",
            boost::bind(
                &World::swapLayers,
                world,
                i,
                i - 1));

        world->swapLayers(i, i-1);
    }

    return false;

}

static bool layer_deleteLayerButtonClicked(Widget *w, void *data) {

    World *world = (World*)data;
    
    JunkEditor *editor = &(world->getEditor()->junkInterface);

    editor->rootWidgetStack.push_back(editor->layerDestroyConfirm);

    return false;
}

static bool layer_deleteLayerConfirmed(Widget *w, void *data) {

    World *world = (World*)data;

    if(world->getNumLayers() <= 1) {
        out("error") << "Can't have less than one layer." << endl;
        return false;
    }
    
    int currentLayer = world->getEditor()->junkInterface.getActiveLayer();
    world->deleteLayer(currentLayer);

    JunkEditor *editor = &(world->getEditor()->junkInterface);

    // TODO: If we ever add a layer restore functionality, take this
    // out.
    world->getEditor()->clearUndoActions();

    popDialog(w, editor);

    return false;
}

static bool layer_lightingToggled(WidgetButton *w, World *world, JunkEditor *editor) {
    world->setLayerLighting(editor->getActiveLayer(), w->getToggleValue());
    return false;
}

static bool layer_fullbrightsToggled(WidgetButton *w, World *world, JunkEditor *editor) {
    world->setLayerFullbrightLights(editor->getActiveLayer(), w->getToggleValue());
    return false;
}

static bool layer_combineToggled(WidgetButton *w, World *world, JunkEditor *editor) {
    world->setLayerCombineWithPrevious(editor->getActiveLayer(), w->getToggleValue());
    return false;
}

static bool layer_tilesAsLightsToggled(WidgetButton *w, World *world, JunkEditor *editor) {
    world->setLayerTilesAsLightMap(editor->getActiveLayer(), w->getToggleValue());
    return false;
}

JunkEditor::JunkEditor(World *world, bool enableSaves) {

	///////////////////////////////////////////////////////////////////
	// TODO
	///////////////////////////////////////////////////////////////////
	// 
	// A lot of this insanity could be averted with a system to set up
	// Widget hierarchies like FLTK. For example, start a section,
	// record all Widgets created in that section, then at the end, add
	// them all as children. Make it like a stack, so it only adds to
	// the most recent Widget with an open section.
	// 
	///////////////////////////////////////////////////////////////////
	
	readjustConsoleSliderAfterUpdate = true;
	dataDirty = false;
	mouseOverAWidget = false;
	clearTiles = false;
	numAttributes = 0;
	saveDialogOpen = false;
	loadDialogOpen = false;
	wantClearData = false;
	visible = true;
	tilesGroupSelected = false;
	historyPosition = -1;
	tileSize = 32;
	this->gameName = world->getGameName();
    lightsDirty = false;

	// This is a minimalist UI so we can hide the main one.
	WidgetContainer *alternateContainer = new WidgetContainer();
	hiddenRoot = alternateContainer;
	
	alternateContainer->setMinWidth(64);
	alternateContainer->setMinHeight(64);
	alternateContainer->setNumRows(2);
	alternateContainer->setNumCols(2);
	alternateContainer->setStretchableCol(-1);
	alternateContainer->setStretchableRow(-1);
	
	WidgetPaddedBox *alternateBox = new WidgetPaddedBox();
	alternateBox->setBackgroundImage("editordata/np_ff2.ninepatch");
	alternateContainer->addChild(alternateBox);
	alternateBox->setMinWidth(32);
	alternateBox->setMinHeight(32);
	alternateBox->setNativeEventHandler("onMouseEnter", mouseEnterOrLeaveEvent, this);
	alternateBox->setNativeEventHandler("onMouseExit", mouseEnterOrLeaveEvent, this);
	
	WidgetButton *alternateButton = new WidgetButton();
	setJunkEditorButtonDefaults(alternateButton);
	alternateButton->setLabel("+");
	alternateButton->setMinWidth(16);
	alternateButton->setMinHeight(16);
	alternateButton->setNativeEventHandler("onClick", editorAlternateToggle, this);
	alternateBox->setChild(alternateButton);
	
	//hiddenRoot = alternateButton;
	
	
	// This handles the entire editor screen. It includes the left
	// panel and the right empty area.
	WidgetContainer *mainContainer = new WidgetContainer();
	
	mainContainer->setMinWidth(16);
	mainContainer->setMinHeight(16);
	mainContainer->setNumCols(2);
	mainContainer->setNumRows(1);
	mainContainer->setStretchableCol(1);
	mainContainer->setStretchableRow(0);
	rootContainer = mainContainer;
	rootWidgetStack.push_back(mainContainer);
	
	// ----------------------------------------------------------------
	//  Left panel (everything useful is under this)
	// ----------------------------------------------------------------
	
	WidgetPaddedBox *leftPaddedBox = new WidgetPaddedBox();
	mainContainer->addChild(leftPaddedBox);
	leftPaddedBox->setPadding(16);
	leftPaddedBox->setBackgroundImage("editordata/np_ff2.ninepatch");
	leftPaddedBox->setNativeEventHandler("onMouseEnter", mouseEnterOrLeaveEvent, this);
	leftPaddedBox->setNativeEventHandler("onMouseExit", mouseEnterOrLeaveEvent, this);
	
	// Leftpanel will house the separate groups for layer selection,
	// tab rows, and the tab pane.
	WidgetContainer *leftPanel = new WidgetContainer();
	leftPaddedBox->setChild(leftPanel);
	leftPanel->setMinWidth(320);
	leftPanel->setNumRows(4);
	leftPanel->setNumCols(1);
	leftPanel->setCellSpacing(4);
	leftPanel->setStretchableCol(0);
	leftPanel->setStretchableRow(3);
	
	// ----------------------------------------------------------------
	//  File save/load/whatever
	// ----------------------------------------------------------------

	WidgetContainer *mainMenu = new WidgetContainer();
	mainMenu->setNumRows(1);
	mainMenu->setNumCols(6);
	mainMenu->setStretchableCol(4);
	mainMenu->setStretchableRow(0);
	mainMenu->setCellSpacing(2);
	leftPanel->addChild(mainMenu);
	
	WidgetButton *saveButton = new WidgetButton();
	setJunkEditorButtonDefaults(saveButton);
	saveButton->setLabel("Save");
	saveButton->setNativeEventHandler("onClick", saveButtonClicked, this);
	mainMenu->addChild(saveButton);
	
	WidgetButton *saveAsButton = new WidgetButton();
	setJunkEditorButtonDefaults(saveAsButton);
	saveAsButton->setLabel("Save As");
	saveAsButton->setNativeEventHandler("onClick", saveAsButtonClicked, this);
	mainMenu->addChild(saveAsButton);

	WidgetButton *loadButton = new WidgetButton();
	setJunkEditorButtonDefaults(loadButton);
	loadButton->setLabel("Load");
	loadButton->setNativeEventHandler("onClick", loadButtonClicked, this);
	mainMenu->addChild(loadButton);

	WidgetButton *newButton = new WidgetButton();
	setJunkEditorButtonDefaults(newButton);
	newButton->setLabel("New");
	newButton->setNativeEventHandler("onClick", newButtonClicked, this);
	mainMenu->addChild(newButton);
	
	mainMenu->addChild(NULL);

	WidgetButton *minimizeButton = new WidgetButton();
	setJunkEditorButtonDefaults(minimizeButton);
	minimizeButton->setLabel("-");
	minimizeButton->setNativeEventHandler("onClick", editorAlternateToggle, this);
	mainMenu->addChild(minimizeButton);

	// ----------------------------------------------------------------
	// Layers
	// ----------------------------------------------------------------
	
	WidgetRadioGroup *layerRadioGroup = new WidgetRadioGroup();
	leftPanel->addChild(layerRadioGroup);
	
	layerSelection = new WidgetContainer();
	layerRadioGroup->setChild(layerSelection);
	layerSelection->setNumCols(3);
	layerSelection->setStretchableCol(2);
	layerSelection->setStretchableRow(0);
	layerSelection->setCellSpacing(4);

	// ----------------------------------------------------------------
	//  Tabs
	// ----------------------------------------------------------------
	
	// Radio group for tabs.
	WidgetRadioGroup *tabRadioGroup = new WidgetRadioGroup();
	leftPanel->addChild(tabRadioGroup);
	
	float tabSpacing = 2;
	
	WidgetContainer *tabRows = new WidgetContainer();
	tabRows->setNumCols(1);
	tabRows->setNumRows(2);
	tabRows->setCellSpacing(tabSpacing);
	tabRadioGroup->setChild(tabRows);
	
	// Tab rows.
	WidgetContainer *tabRow1 = new WidgetContainer();
	tabRow1->setMinHeight(16);
	tabRow1->setMinWidth(16);
	tabRow1->setNumCols(2);
	tabRow1->setNumRows(1);
	tabRow1->setStretchableCol(0);
	tabRow1->setCellSpacing(tabSpacing);
	tabRows->addChild(tabRow1);
	
	WidgetContainer *tabRow2 = new WidgetContainer();
	tabRow2->setMinHeight(16);
	tabRow2->setMinWidth(16);
	tabRow2->setNumCols(2);
	tabRow2->setNumRows(1);
	tabRow2->setStretchableCol(0);
	tabRow2->setCellSpacing(tabSpacing);
	tabRows->addChild(tabRow2);
	
	// ----------------------------------------------------------------
	//  Tab pane
	// ----------------------------------------------------------------
	
	// scrollableView will own the scrollable parent of the tab pane
	// and the scrollbar itself.
	WidgetContainer *scrollableView = new WidgetContainer();
	scrollableView->setNumRows(1);
	scrollableView->setNumCols(2);
	scrollableView->setStretchableCol(0);
	scrollableView->setStretchableRow(0);
	leftPanel->addChild(scrollableView);
	
	WidgetScrollable *scrollableTabPane = new WidgetScrollable();
	scrollableView->addChild(scrollableTabPane);
	
	WidgetSlider *paneSlider = new WidgetSlider();
	setJunkEditorSliderDefaults(paneSlider);
	paneSlider->setVertical(true);
	paneSlider->setSmallStep(32);
	scrollableView->addChild(paneSlider);
	scrollableTabPane->setVerticalScrollBar(paneSlider);
	
	tabPane = new WidgetSelectChild();
	//tabPane->setBackgroundImage("editordata/np_ff1.ninepatch");
	scrollableTabPane->setChild(tabPane);
	
	// ----------------------------------------------------------------
	//  Individual tabs
	// ----------------------------------------------------------------
	
	// Separate tab panes...
	
	// Console.
	WidgetContainer *tab_consoleContainer = new WidgetContainer();
	tab_consoleContainer->setBackgroundImage("editordata/np_ff2.ninepatch");
	tab_consoleContainer->setNumRows(2);
	tab_consoleContainer->setNumCols(1);
	tab_consoleContainer->setStretchableCol(0);
	tab_consoleContainer->setStretchableRow(0);
	tabPane->addChild(tab_consoleContainer);
	
	WidgetContainer *tab_consoleTextBoxView = new WidgetContainer();
	tab_consoleTextBoxView->setNumRows(1);
	tab_consoleTextBoxView->setNumCols(2);
	tab_consoleTextBoxView->setStretchableCol(0);
	
	WidgetScrollable *tab_consoleTextBoxScroll = new WidgetScrollable();
	tab_consoleTextBoxScroll->setMinHeight(32);
	tab_consoleTextBoxView->addChild(tab_consoleTextBoxScroll);

	WidgetSlider *tab_consoleTextBoxSlider = new WidgetSlider();
	setJunkEditorSliderDefaults(tab_consoleTextBoxSlider);
	tab_consoleTextBoxSlider->setSmallStep(32);
	tab_consoleTextBoxView->addChild(tab_consoleTextBoxSlider);
	tab_consoleTextBoxScroll->setVerticalScrollBar(tab_consoleTextBoxSlider);
	consoleSlider = tab_consoleTextBoxSlider;
	
	WidgetPaddedBox *tab_consoleTextBox = new WidgetPaddedBox();
	tab_consoleTextBox->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_consoleTextBox->setPadding(4);
	tab_consoleTextBox->setMinHeight(20);
	tab_consoleTextBoxScroll->setChild(tab_consoleTextBox);
	
	WidgetText *tab_consoleText = new WidgetText();
	tab_consoleText->setWordWrap(true);
	consoleOutput = tab_consoleText;
	tab_consoleTextBox->setChild(tab_consoleText);	
	
	WidgetPaddedBox *tab_consoleEntryBox = new WidgetPaddedBox();
	tab_consoleEntryBox->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_consoleEntryBox->setPadding(4);
	tab_consoleEntryBox->setMinHeight(24);

	WidgetText *tab_consoleEntry = new WidgetText();
	tab_consoleEntry->setEditable(true);
	tab_consoleEntry->setWordWrap(true);
	tab_consoleEntry->setNativeEventHandler("onTextChanged", consoleTextChanged, this);
	tab_consoleEntry->setNativeEventHandler("WIDGETEVENT_KEYDOWN", consoleKeyDown, this);
	
	tab_consoleEntryBox->setChild(tab_consoleEntry);
	tab_consoleContainer->addChild(tab_consoleTextBoxView);
	tab_consoleContainer->addChild(tab_consoleEntryBox);
	
	// Ent palette.
	tab_entContainer = new WidgetContainer();
	tab_entContainer->setNumCols(1);
	tab_entContainer->setStretchableRow(-1);
    tab_entContainer->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tabPane->addChild(tab_entContainer);
	
	// Tiles.
	WidgetContainer *tilePaneView = new WidgetContainer();
	tilePaneView->setNumRows(2);
	tilePaneView->setNumCols(2);
	tilePaneView->setStretchableCol(0);
	tilePaneView->setStretchableRow(0);
	
	WidgetSlider *tilePaneSliderV = new WidgetSlider();
	tilePaneSliderV->setVertical(true);
	tilePaneSliderV->setSmallStep(16);
	setJunkEditorSliderDefaults(tilePaneSliderV);
	
	WidgetSlider *tilePaneSliderH = new WidgetSlider();
	tilePaneSliderH->setVertical(false);
	tilePaneSliderH->setSmallStep(16);
	setJunkEditorSliderDefaults(tilePaneSliderH);
	
	tab_tileContainerGrid = new WidgetContainer();
	tab_tileContainerGrid->setBackgroundImage("editordata/1pxbox1.ninepatch");

	WidgetScrollable *tab_tileContainerGridScroll = new WidgetScrollable();
	tab_tileContainerGridScroll->setChild(tab_tileContainerGrid);
	tab_tileContainerGridScroll->setVerticalScrollBar(tilePaneSliderV);
	tab_tileContainerGridScroll->setHorizontalScrollBar(tilePaneSliderH);
	tab_tileContainerGridScroll->setScrollHorizontally(true);
	
	tab_tileContainer = new WidgetContainer();
	tab_tileContainer->setNumRows(2);
	tab_tileContainer->setStretchableRow(0);
	tab_tileContainer->setNumCols(1);
	tab_tileContainer->setStretchableCol(0);
	tab_tileContainer->addChild(tilePaneView);
	tabPane->addChild(tab_tileContainer);
	
	tilePaneView->addChild(tab_tileContainerGridScroll);
	tilePaneView->addChild(tilePaneSliderV);
	tilePaneView->addChild(tilePaneSliderH);
	
	WidgetPaddedBox *statsBox = new WidgetPaddedBox();
	statsBox->setPadding(4);
	statsBox->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_tileContainer->addChild(statsBox);
	
	WidgetContainer *tab_tileStats = new WidgetContainer();
	tab_tileStats->setCellSpacing(4);
	tab_tileStats->setNumRows(2);
	tab_tileStats->setStretchableRow(-1);
	tab_tileStats->setNumCols(2);
	tab_tileStats->setStretchableCol(1);
	statsBox->setChild(tab_tileStats);
	
	WidgetText *tileFileNameLabel = new WidgetText();
	tileFileNameLabel->setText("Filename");
	tab_tileStats->addChild(tileFileNameLabel);
	
	WidgetContainer *tab_tileFileNameContainer = new WidgetContainer();
	tab_tileFileNameContainer->setNumRows(1);
	tab_tileFileNameContainer->setStretchableRow(0);
	tab_tileFileNameContainer->setNumCols(2);
	tab_tileFileNameContainer->setStretchableCol(0);
	tab_tileStats->addChild(tab_tileFileNameContainer);

	tab_tileFilename = new WidgetText();
	tab_tileFilename->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_tileFilename->setEditable(true);
	tab_tileFilename->setNativeEventHandler("WIDGETEVENT_FOCUSLEAVE", tileFilenameChanged, this);
	tab_tileFileNameContainer->addChild(tab_tileFilename);
	
	WidgetButton *tab_tileFileNameBrowser = new WidgetButton();
	setJunkEditorButtonDefaults(tab_tileFileNameBrowser);
	tab_tileFileNameBrowser->setLabel("Browse...");
	tab_tileFileNameBrowser->setLabelPadding(2);
	tab_tileFileNameBrowser->setNativeEventHandler("onClick", tileFileButtonClicked, this);
	tab_tileFileNameContainer->addChild(tab_tileFileNameBrowser);
	
	WidgetText *tileSizeLabel = new WidgetText();
	tileSizeLabel->setText("Size");
	tab_tileStats->addChild(tileSizeLabel);

	tab_tileSize = new WidgetText();
	tab_tileSize->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_tileSize->setEditable(true);
	tab_tileSize->setNumberOnly(true);
	tab_tileSize->setNativeEventHandler("WIDGETEVENT_FOCUSLEAVE", tileSizeChanged, this);
	tab_tileSize->setText("32");
	tab_tileStats->addChild(tab_tileSize);
	
	// Inspector.
	tab_inspectorContainer = new WidgetContainer();
	tab_inspectorContainer->setBackgroundImage("editordata/1pxbox1.ninepatch");
	tab_inspectorContainer->setNumCols(1);
	tab_inspectorContainer->setStretchableCol(0);
	tabPane->addChild(tab_inspectorContainer);
	
	tab_inspectorContainer_lastGroup = NULL;
	
    // Lighting editor.
    {
        tab_lighting = new WidgetContainer();
        tab_lighting->setNumCols(2);
        tab_lighting->setStretchableCol(1);

        tabPane->addChild(tab_lighting);

        // Light settings...

        WidgetText *lighting_settingsLabel = new WidgetText();
        lighting_settingsLabel->setText("Settings");
        tab_lighting->addChild(lighting_settingsLabel);
        tab_lighting->addChild(NULL);

        // ---

        WidgetText *lighting_settings_linkLayersLabel = new WidgetText();
        lighting_settings_linkLayersLabel->setText("  Change all layers");

        lighting_settings_linkLayersButton = new WidgetButton();
        setJunkEditorCheckboxDefaults(lighting_settings_linkLayersButton);
        lighting_settings_linkLayersButton->setNativeEventHandler("onClick", lightsChanged, this);

        tab_lighting->addChild(lighting_settings_linkLayersLabel);
        tab_lighting->addChild(makeAlignedBoxAround(lighting_settings_linkLayersButton));

        // --

        WidgetText *lighting_settings_disableLabel = new WidgetText();
        lighting_settings_disableLabel->setText("  Temp disable all");

        lighting_settings_disableButton = new WidgetButton();
        setJunkEditorCheckboxDefaults(lighting_settings_disableButton);
        lighting_settings_disableButton->setNativeEventHandler("onClick", lightsChanged, this);

        tab_lighting->addChild(lighting_settings_disableLabel);
        tab_lighting->addChild(makeAlignedBoxAround(lighting_settings_disableButton));

        // --

        WidgetText *lighting_settings_tintInactiveLabel = new WidgetText();
        lighting_settings_tintInactiveLabel->setText("  Tint inactive layers");

        lighting_settings_tintInactiveButton = new WidgetButton();
        setJunkEditorCheckboxDefaults(lighting_settings_tintInactiveButton);
        lighting_settings_tintInactiveButton->setNativeEventHandler("onClick", lightsChanged, this);

        tab_lighting->addChild(lighting_settings_tintInactiveLabel);
        tab_lighting->addChild(makeAlignedBoxAround(lighting_settings_tintInactiveButton));

        // Settings that actually get saved...

        WidgetText *lighting_settings_retroEffectsLabel = new WidgetText();
        lighting_settings_retroEffectsLabel->setText("  Retro lights/fade");

        lighting_settings_retroEffectsButton = new WidgetButton();
        setJunkEditorCheckboxDefaults(lighting_settings_retroEffectsButton);
        lighting_settings_retroEffectsButton->setNativeEventHandler("onClick", lightsChanged, this);

        tab_lighting->addChild(lighting_settings_retroEffectsLabel);
        tab_lighting->addChild(makeAlignedBoxAround(lighting_settings_retroEffectsButton));

        // Light values...

        // Label for ambient section.

        WidgetText *lighting_ambientLabel = new WidgetText();
        lighting_ambientLabel->setText("Ambient");
        tab_lighting->addChild(lighting_ambientLabel);
        tab_lighting->addChild(NULL);

        // Labels for each ambient channel.

        WidgetText *lighting_ambient_redLabel = new WidgetText();
        WidgetText *lighting_ambient_greenLabel = new WidgetText();
        WidgetText *lighting_ambient_blueLabel = new WidgetText();

        lighting_ambient_redLabel->setText("  Red");
        lighting_ambient_greenLabel->setText("  Green");
        lighting_ambient_blueLabel->setText("  Blue");

        // Sliders for each ambient channel.

        lighting_ambient_redSlider = new WidgetSlider();
        lighting_ambient_greenSlider = new WidgetSlider();
        lighting_ambient_blueSlider = new WidgetSlider();

        setupLightSlider(lighting_ambient_redSlider, this);
        setupLightSlider(lighting_ambient_greenSlider, this);
        setupLightSlider(lighting_ambient_blueSlider, this);
    
        // Put it all together to make the ambient section.
    
        tab_lighting->addChild(lighting_ambient_redLabel);
        tab_lighting->addChild(lighting_ambient_redSlider);
        tab_lighting->addChild(lighting_ambient_greenLabel);
        tab_lighting->addChild(lighting_ambient_greenSlider);
        tab_lighting->addChild(lighting_ambient_blueLabel);
        tab_lighting->addChild(lighting_ambient_blueSlider);

        // Finally, set the rows based on all that crap we just added.

        tab_lighting->setNumRows(tab_lighting->getNumChildren() / 2 + 1);
        tab_lighting->setStretchableRow(tab_lighting->getNumRows() - 1);
    }

    // Layer stuff.
    WidgetContainer *tab_layer = new WidgetContainer();
    tabPane->addChild(tab_layer);    

    {
        WidgetButton *tab_layer_moveBackButton = new WidgetButton();
        setJunkEditorButtonDefaults(tab_layer_moveBackButton);
        tab_layer_moveBackButton->setLabel("Move backward");
        tab_layer_moveBackButton->setNativeEventHandler("onClick", layer_swapCurrentPrev, world);
        tab_layer->addChild(tab_layer_moveBackButton);

        WidgetButton *tab_layer_moveForwardButton = new WidgetButton();
        setJunkEditorButtonDefaults(tab_layer_moveForwardButton);
        tab_layer_moveForwardButton->setLabel("Move forward");
        tab_layer_moveForwardButton->setNativeEventHandler("onClick", layer_swapCurrentNext, world);
        tab_layer->addChild(tab_layer_moveForwardButton);

        WidgetButton *tab_layer_insertButton = new WidgetButton();
        setJunkEditorButtonDefaults(tab_layer_insertButton);
        tab_layer_insertButton->setLabel("Insert new layer");
        tab_layer->addChild(tab_layer_insertButton);
        tab_layer_insertButton->setNativeEventHandler("onClick", layer_addNewLayer, world);

        WidgetButton *tab_layer_deleteButton = new WidgetButton();
        setJunkEditorButtonDefaults(tab_layer_deleteButton);
        tab_layer_deleteButton->setLabel("Delete selected layer");
        tab_layer->addChild(tab_layer_deleteButton);
        tab_layer_deleteButton->setNativeEventHandler("onClick", layer_deleteLayerButtonClicked, world);

        WidgetPaddedBox *valuesPadding = new WidgetPaddedBox();
        valuesPadding->setPadding(8);
        tab_layer->addChild(valuesPadding);

        WidgetContainer *tab_layer_valuesContainer = new WidgetContainer();
        tab_layer_valuesContainer->setNumCols(2);
        tab_layer_valuesContainer->setStretchableRow(-1);
        tab_layer_valuesContainer->setStretchableCol(1);
        tab_layer_valuesContainer->setCellSpacing(8);
        valuesPadding->setChild(tab_layer_valuesContainer);

        // Layer specific values.
        WidgetText *layer_nameLabel = new WidgetText();
        layer_nameLabel->setText("Name");
        tab_layer_valuesContainer->addChild(layer_nameLabel);
        
        layer_nameEntry = new WidgetText();
        layer_nameEntry->setEditable(true);
        layer_nameEntry->setBackgroundImage("editordata/1pxbox1.ninepatch");
        layer_nameEntry->setNativeEventHandler("onTextChanged", layer_setName, world);
        tab_layer_valuesContainer->addChild(layer_nameEntry);

        // Parallax amount.
        WidgetText *layer_camScaleLabel = new WidgetText();
        layer_camScaleLabel->setText("Parallax");
        tab_layer_valuesContainer->addChild(layer_camScaleLabel);
        
        layer_camScaleEntry = new WidgetText();
        layer_camScaleEntry->setBackgroundImage("editordata/1pxbox1.ninepatch");
        layer_camScaleEntry->setNumberOnly(true);
        layer_camScaleEntry->setEditable(true);
        layer_camScaleEntry->setNativeEventHandler("onTextChanged", layer_setCamScale, world);
        tab_layer_valuesContainer->addChild(layer_camScaleEntry);

        // Lighting toggle.
        WidgetText *layer_lightToggleLabel = new WidgetText();
        layer_lightToggleLabel->setText("Lighting");
        tab_layer_valuesContainer->addChild(layer_lightToggleLabel);

        layer_lightToggle = new WidgetButton();
        setJunkEditorCheckboxDefaults(layer_lightToggle);
        tab_layer_valuesContainer->addChild(makeAlignedBoxAround(layer_lightToggle));
        layer_lightToggle->addNativeBindEventHandler("onClick", boost::bind(&layer_lightingToggled, layer_lightToggle, world, this));

        // Layer affected by fullbright lights toggle.
        WidgetText *layer_fullbrightToggleLabel = new WidgetText();
        layer_fullbrightToggleLabel->setText("Cross-layer lighting");
        tab_layer_valuesContainer->addChild(layer_fullbrightToggleLabel);

        layer_fullbrightToggle = new WidgetButton();
        setJunkEditorCheckboxDefaults(layer_fullbrightToggle);
        tab_layer_valuesContainer->addChild(makeAlignedBoxAround(layer_fullbrightToggle));
        layer_fullbrightToggle->addNativeBindEventHandler("onClick", boost::bind(&layer_fullbrightsToggled, layer_fullbrightToggle, world, this));

        // Layer draw/lighting pass combine.
        WidgetText *layer_combineToggleLabel = new WidgetText();
        layer_combineToggleLabel->setText("Combine with previous\nlayer for rendering");
        tab_layer_valuesContainer->addChild(layer_combineToggleLabel);

        layer_combineToggle = new WidgetButton();
        setJunkEditorCheckboxDefaults(layer_combineToggle);
        tab_layer_valuesContainer->addChild(makeAlignedBoxAround(layer_combineToggle));
        layer_combineToggle->addNativeBindEventHandler("onClick", boost::bind(&layer_combineToggled, layer_combineToggle, world, this));

        // Layer tiles as lightmap toggle.
        WidgetText *layer_tilesAsLightMapToggleLabel = new WidgetText();
        layer_tilesAsLightMapToggleLabel->setText("Tiles render to lightmap only");
        tab_layer_valuesContainer->addChild(layer_tilesAsLightMapToggleLabel);

        layer_tilesAsLightsToggle = new WidgetButton();
        setJunkEditorCheckboxDefaults(layer_tilesAsLightsToggle);
        tab_layer_valuesContainer->addChild(makeAlignedBoxAround(layer_tilesAsLightsToggle));
        layer_tilesAsLightsToggle->addNativeBindEventHandler("onClick", boost::bind(&layer_tilesAsLightsToggled, layer_tilesAsLightsToggle, world, this));



        tab_layer_valuesContainer->setNumRows(tab_layer_valuesContainer->getNumChildren() / 2 + 1);

        tab_layer->setNumRows(tab_layer->getNumChildren());
        tab_layer->setStretchableRow(-1);
    }
    

	// ----------------------------------------------------------------
	//  Tab buttons themselves.
	// ----------------------------------------------------------------
	
	for(int i = 0; i < 6; i++) {
		
		const char *text = "";
		
		WidgetContainer *tabRow = tabRow1;
		if(i > 2) tabRow = tabRow2;
		
		WidgetButton *tab = new WidgetButton();
		Widget *tabContents = NULL;
		
		// Add before setting up so the radio group gets the right
		// message.
		tabRow->addChild(tab);
        tabRow->setNumCols(tabRow->getNumChildren());
		
		tab->setMinWidth(16);
		tab->setMinHeight(32);
		tab->setToggleable(true);
		tab->setIsRadio(true);
		setJunkEditorButtonDefaults(tab);

		if(i == 0) {
			tab->setToggleValue(true);
		} else {
			tab->setToggleValue(false);
		}
		
		switch(i) {
        case 0:
            tabContents = tab_entContainer;
            text = "Ent Palette";
            break;
        case 1:
            tabContents = tab_layer;
            text = "Layer";
            break;
        case 2:
            tabContents = tab_inspectorContainer;
            text = "Inspector";
            break;
        case 3:
            tabContents = tab_tileContainer;
            tileButton = tab;
            text = "Tiles";
            break;
        case 4:
            tabContents = tab_consoleContainer;
            text = "Console";
            break;
        case 5:
            tabContents = tab_lighting;
            text = "Lighting";
            break;
		}
		
		tab->setLabel(text);
		tabPane->mapRadioToChild(tab, tabContents);
	}

	// New file confirmation dialog.
	{
		WidgetAlignedBox *newFileConfirmRoot = new WidgetAlignedBox();
		
		WidgetPaddedBox *box = new WidgetPaddedBox();
		newFileConfirmRoot->setChild(box);
		
		box->setBackgroundImage("editordata/np_ff2.ninepatch");
		box->setPadding(32);
		
		WidgetContainer *container = new WidgetContainer();
		box->setChild(container);
		
		container->setNumRows(2);
		container->setNumCols(1);
		container->setStretchableCol(0);
		container->setStretchableRow(0);
		
		WidgetText *confirmText = new WidgetText();
		confirmText->setWordWrap(false);
		confirmText->setText("Destroy everything and\nruin all your wonderful\nwork?");
		container->addChild(confirmText);
		
		WidgetContainer *buttonContainer = new WidgetContainer();
		buttonContainer->setNumCols(3);
		buttonContainer->setNumRows(1);
		buttonContainer->setStretchableCol(1);
		container->addChild(buttonContainer);
		
		WidgetButton *noButton = new WidgetButton();
		noButton->setLabel("Nope");
		noButton->setNativeEventHandler("onClick", popDialog, this);
		setJunkEditorButtonDefaults(noButton);

		WidgetButton *yesButton = new WidgetButton();
		yesButton->setLabel("Yup");
		yesButton->setNativeEventHandler("onClick", newButtonConfirmed, this);
		setJunkEditorButtonDefaults(yesButton);

		buttonContainer->addChild(noButton);
		buttonContainer->addChild(NULL);
		buttonContainer->addChild(yesButton);

		newFileConfirm = newFileConfirmRoot;
	}

    // Layer deletion confirmation. Yeah, sorry. Lots of copy+paste here.
    {
		WidgetAlignedBox *layerDestroyConfirmRoot = new WidgetAlignedBox();
		
		WidgetPaddedBox *box = new WidgetPaddedBox();
		layerDestroyConfirmRoot->setChild(box);
		
		box->setBackgroundImage("editordata/np_ff2.ninepatch");
		box->setPadding(32);
		
		WidgetContainer *container = new WidgetContainer();
		box->setChild(container);
		
		container->setNumRows(2);
		container->setNumCols(1);
		container->setStretchableCol(0);
		container->setStretchableRow(0);
		
		WidgetText *confirmText = new WidgetText();
		confirmText->setWordWrap(false);
		confirmText->setText("Are you sure you want to delete the\ncurrently selected layer?\n(There is no undo for this.)");
		container->addChild(confirmText);
		
		WidgetContainer *buttonContainer = new WidgetContainer();
		buttonContainer->setNumCols(3);
		buttonContainer->setNumRows(1);
		buttonContainer->setStretchableCol(1);
		container->addChild(buttonContainer);
		
		WidgetButton *noButton = new WidgetButton();
		noButton->setLabel("Nope");
		noButton->setNativeEventHandler("onClick", popDialog, this);
		setJunkEditorButtonDefaults(noButton);

		WidgetButton *yesButton = new WidgetButton();
		yesButton->setLabel("Yup");
		yesButton->setNativeEventHandler("onClick", layer_deleteLayerConfirmed, world);
		setJunkEditorButtonDefaults(yesButton);

		buttonContainer->addChild(noButton);
		buttonContainer->addChild(NULL);
		buttonContainer->addChild(yesButton);

		layerDestroyConfirm = layerDestroyConfirmRoot;
    }
	
	// File selector windows.
	loadWindow = new FileWindow(loadButtonReturned, popDialog, this);
	saveWindow = new FileWindow(saveAsButtonReturned, popDialog, this);
	tileFileWindow = new FileWindow(tileFileButtonReturned, popDialog, this);;

    // Finish setting up layer list.
    if(world) {
        updateLayerList(world);
    }
}

JunkEditor::~JunkEditor(void) {
	delete rootContainer;
	delete newFileConfirm;
    delete layerDestroyConfirm;
	delete loadWindow;
	delete saveWindow;
	delete tileFileWindow;
}

void JunkEditor::clearAttributes(void) {
	tab_inspectorContainer->clearChildren();
	tab_inspectorContainer->setNumRows(1);
	valueWidgets.clear();
}

static bool editorValueChanged(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	
	editor->flagDataDirty();
	
	return false;
}

void JunkEditor::addAttribute(const std::string &name, InspectorDataType type) {
	
	// Attributes are divided up with dividers. Between dividers are
	// containers that hold all the attributes. Otherwise we can't have
	// dual-columns and have the dividers stretch across both.
	
	if(type == INSPECTOR_DIVIDER) {
		
		WidgetPaddedBox *labelBox = new WidgetPaddedBox();
		labelBox->setPadding(4);
		labelBox->setBackgroundImage("editordata/1pxbox3.ninepatch");
		
		WidgetText *label = new WidgetText();
		label->setText(name);
		label->setScale(0.5);
		label->setWordWrap(true);
		label->setFontName("editordata/orangething2.tga");
		
		labelBox->setChild(label);
		
		tab_inspectorContainer->addChild(labelBox);
		tab_inspectorContainer->setNumRows(tab_inspectorContainer->getNumChildren() + 1);
		tab_inspectorContainer->setStretchableRow(tab_inspectorContainer->getNumChildren());
		
		// Clear the group. Will make a new one if there's still none
		// by the time we get to the next attribute.
		tab_inspectorContainer_lastGroup = NULL;
		
	} else {
	
		if(!tab_inspectorContainer_lastGroup) {
			
			// No group (last thing created was probably a divider). We
			// need one!
			
			WidgetPaddedBox *newGroupBox = new WidgetPaddedBox();
			newGroupBox->setPadding(4);
			
			tab_inspectorContainer_lastGroup = new WidgetContainer();
			tab_inspectorContainer_lastGroup->setNumCols(2);
			tab_inspectorContainer_lastGroup->setStretchableCol(1);
			
			newGroupBox->setChild(tab_inspectorContainer_lastGroup);
			tab_inspectorContainer->addChild(newGroupBox);
			
			tab_inspectorContainer->setNumRows(tab_inspectorContainer->getNumChildren() + 1);
			tab_inspectorContainer->setStretchableRow(tab_inspectorContainer->getNumChildren());
		}

		WidgetPaddedBox *labelBox = new WidgetPaddedBox();
		labelBox->setPadding(4);
		
		WidgetText *label = new WidgetText();
		label->setText(name);
		labelBox->setChild(label);
		
		tab_inspectorContainer_lastGroup->setNumRows(tab_inspectorContainer->getNumRows() + 1);
		tab_inspectorContainer_lastGroup->addChild(labelBox);
		
		switch(type) {
			
			case INSPECTOR_BOOL: {
				
				WidgetAlignedBox *alignBox = new WidgetAlignedBox();
				alignBox->setHAlign(1);
				
				WidgetButton *checkBox = new WidgetButton();
				checkBox->setLabel("");
				checkBox->setLabelPadding(0);
				checkBox->setMinWidth(12);
				checkBox->setMinHeight(12);
				checkBox->setToggleable(true);
				checkBox->setBackgroundImage("editordata/unchecked.tga");
				checkBox->setBackgroundDefault("editordata/unchecked.tga");
				checkBox->setBackgroundActive("editordata/checked.tga");
				checkBox->setBackgroundMouseOver("editordata/checking.tga");
				
				checkBox->setNativeEventHandler("onClick", editorValueChanged, this);
				
				alignBox->setChild(checkBox);
				
				valueWidgets[name] = checkBox;
				
				tab_inspectorContainer_lastGroup->addChild(alignBox);
				
			} break;
			
			case INSPECTOR_DOUBLE:
			case INSPECTOR_INT:
			case INSPECTOR_READONLYSTRING:
			case INSPECTOR_STRING: {
				
				WidgetPaddedBox *box = new WidgetPaddedBox();
				box->setPadding(4);
				
				WidgetText *textBox = new WidgetText();
				
				if(type == INSPECTOR_READONLYSTRING) {
					
				} else {
					box->setBackgroundImage("editordata/1pxbox1.ninepatch");
					textBox->setEditable(true);
				}
				
				if(type == INSPECTOR_DOUBLE || type == INSPECTOR_INT) {
					textBox->setNumberOnly(true);
				}
				
				textBox->setNativeEventHandler("WIDGETEVENT_FOCUSLEAVE", editorValueChanged, this);
				
				textBox->setWordWrap(true);
				
				valueWidgets[name] = textBox;
				
				box->setChild(textBox);
				tab_inspectorContainer_lastGroup->addChild(box);
				
			} break;
			
			default: {
				
				WidgetText *junk = new WidgetText();
				junk->setText("(junk)");
				tab_inspectorContainer_lastGroup->addChild(junk);
				
			} break;
			
		}
		
		tab_inspectorContainer_lastGroup->setNumRows(tab_inspectorContainer_lastGroup->getNumChildren() + 1);
		tab_inspectorContainer_lastGroup->setStretchableRow(tab_inspectorContainer_lastGroup->getNumChildren());
	}
}

void JunkEditor::setStringAttribute(const std::string &name, const std::string &value) {
	
	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		textWidget->setText(value);
	}
	
}

void JunkEditor::setBoolAttribute(const std::string &name, bool value) {

	WidgetButton *buttonWidget = dynamic_cast<WidgetButton*>(valueWidgets[name]);
	
	if(buttonWidget) {
		buttonWidget->setToggleValue(value);
	}

}

void JunkEditor::setIntAttribute(const std::string &name, int value) {

	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		ostringstream str;
		str << value;
		textWidget->setText(str.str());
	}

}

void JunkEditor::setDoubleAttribute(const std::string &name, double value) {
	
	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		ostringstream str;
		str << value;
		textWidget->setText(str.str());
	}
	
}

std::string JunkEditor::getStringAttribute(const std::string &name) {

	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		return textWidget->getText();
	}

	return "";
}

bool JunkEditor::getBoolAttribute(const std::string &name) {
	
	WidgetButton *buttonWidget = dynamic_cast<WidgetButton*>(valueWidgets[name]);
	
	if(buttonWidget) {
		return buttonWidget->getToggleValue();
	}
	
	return false;
}

int JunkEditor::getIntAttribute(const std::string &name) {

	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		return atoi(textWidget->getText().c_str());
	}

	return 0;
}

double JunkEditor::getDoubleAttribute(const std::string &name) {

	WidgetText *textWidget = dynamic_cast<WidgetText*>(valueWidgets[name]);
	
	if(textWidget) {
		return atof(textWidget->getText().c_str());
	}

	return 0;
}

void JunkEditor::clearEntityPaletteList(void) {
	
	tab_entContainer->clearChildren();
	
}

void JunkEditor::addEntityPaletteItem(const std::string &name) {
	
	WidgetButton *entButton = new WidgetButton();
	entButton->setBackgroundImage("editordata/1pxbox1.ninepatch");
	entButton->setBackgroundDefault("editordata/1pxbox1.ninepatch");
	entButton->setBackgroundActive("editordata/1pxbox2.ninepatch");
	entButton->setBackgroundMouseOver("editordata/1pxbox3.ninepatch");
	
	entButton->setLabel(name);
	entButton->setNativeEventHandler("onClick", entAddCallback, this);
	
	entButton->setLabelPadding(2);
	entButton->setLabelHAlign(-1);
	
	tab_entContainer->addChild(entButton);
	tab_entContainer->setNumRows(tab_entContainer->getNumChildren());
}

void JunkEditor::removeEntityPaletteItem(const std::string &name) {
	// TODO: EDITORUI
}

std::string JunkEditor::getNewEntity(void) {
	string tmp = nextEntName;
	nextEntName = "";
	return tmp;
}

std::string JunkEditor::getSave(void) {
	string tmp = nextSaveName;
	nextSaveName = "";
	return tmp;
}

std::string JunkEditor::getLoad(void) {
	string tmp = nextLoadName;
	nextLoadName = "";
	return tmp;
}

bool JunkEditor::getNew(void) {
	bool tmp = wantClearData;
	wantClearData = false;
	return tmp;
}

void JunkEditor::update(float screenWidth, float screenHeight) {
	
	// This just kicks the width/height settings into making themselves
	// consistent across the hierarchy.
	rootContainer->setWidth(screenWidth);
	rootContainer->setHeight(screenHeight);
	
	if(readjustConsoleSliderAfterUpdate) {
		consoleSlider->setValue(consoleSlider->getMaxValue());
		readjustConsoleSliderAfterUpdate = false;
	}
	
	for(unsigned int i = 0; i < rootWidgetStack.size(); i++) {
		rootWidgetStack[i]->setWidth(screenWidth);
		rootWidgetStack[i]->setHeight(screenHeight);
	}
	
	tilesGroupSelected = tileButton->getToggleValue();
}

bool JunkEditor::attributesChanged(void) {

	bool ret = dataDirty;

	dataDirty = false;
	
	return ret;
}

bool JunkEditor::getVisible(void) const {
	// TODO: EDITORUI
	return true;
}

void JunkEditor::setVisible(bool vis) {
	// TODO: EDITORUI
}

bool JunkEditor::isLayerVisible(int layer) const {
	
	if(layer >= 0 && layer < int(layerVisButtons.size())) {
		WidgetButton *button = dynamic_cast<WidgetButton*>(layerVisButtons[layer]);
		return button && button->getToggleValue();
	}	
	
	return false;
}

int JunkEditor::getActiveLayer(void) const {
	
	for(unsigned int i = 0; i < layerButtons.size() && i < (unsigned int)layerSelection->getNumRows(); i++) {
		WidgetButton *button = dynamic_cast<WidgetButton*>(layerButtons[i]);
		if(button && button->getToggleValue()) {
			return i;
		}
	}

	return 3;
}

void JunkEditor::setActiveLayer(int layerNum) {
    
    int i;

    for(i = 0; i < int(layerButtons.size()) && i < layerSelection->getNumRows(); i++) {
        WidgetButton *button = dynamic_cast<WidgetButton*>(layerButtons[i]);
        button->setToggleValue(layerNum == i);
    }

    if(layerNum >= i || layerNum < 0) {

        // We went past the end. Set layer 0 active if event that exists.
        if(layerButtons.size()) {
            WidgetButton *button = dynamic_cast<WidgetButton*>(layerButtons[0]);
            button->setToggleValue(true);
        }
    }

}

static bool forceLayerDataUpdate(Widget *w, void *data) {
    
    World *world = (World*)data;

    world->forceEditorUpdateLayerList();

    return false;
}

void JunkEditor::updateLayerList(World *world) {

    int i;

    layerSelection->setNumRows(world->getNumLayers());

	for(i = 0; i < world->getNumLayers(); i++) {

		WidgetButton *button = NULL;
		WidgetButton *visButton = NULL;
		WidgetText *label = NULL;
		
        if(i >= layerSelection->getNumChildren() / 3) {
            
            // Radio buttons to control active layer selection.
            button = new WidgetButton();

            button->setBackgroundImage("editordata/radio_inactive.tga");
            button->setBackgroundDefault("editordata/radio_inactive.tga");
            button->setBackgroundActive("editordata/radio_active.tga");
		
            button->setLabel("");
            button->setIsRadio(true);
            button->setToggleable(true);
            button->setMinWidth(16);
            button->setMinHeight(16);
            button->setLabelPadding(0);

            button->setNativeEventHandler("onClick", forceLayerDataUpdate, world);

            layerSelection->addChild(button);

            layerButtons.push_back(button);

            // Check boxes to support layer visibility toggling.
            visButton = new WidgetButton();
            visButton->setBackgroundImage("editordata/checked.tga");
            visButton->setBackgroundDefault("editordata/unchecked.tga");
            visButton->setBackgroundActive("editordata/checked.tga");
            visButton->setBackgroundMouseOver("editordata/checking.tga");

            visButton->setLabel("");
            visButton->setToggleable(true);
            visButton->setMinWidth(16);
            visButton->setMinHeight(16);
            visButton->setLabelPadding(0);

            ostringstream visButtonName;
            visButtonName << "layer_vis_" << i;
            visButton->setName(visButtonName.str());
            visButton->addNativeBindEventHandler("onClick", boost::bind(&toggleLayerVisibility, visButton, world));

            layerSelection->addChild(visButton);
		
            layerVisButtons.push_back(visButton);

            // Layer name.
            label = new WidgetText();
            label->setFontName("editordata/defaultfont.tga");
            layerSelection->addChild(label);

        } else {

            button    = dynamic_cast<WidgetButton*>(layerSelection->getSlot(0, i));
            visButton = dynamic_cast<WidgetButton*>(layerSelection->getSlot(1, i));
            label     = dynamic_cast<WidgetText*>(layerSelection->getSlot(2, i));
        }
        
        string layerName = world->getLayerName(i);
        
        if(world->getLayerCombineWithPrevious(i)) {
            layerName = string(" | ") + layerName;
        }

        label->setText(layerName);
        visButton->setToggleValue(world->getLayerVisible(i));
	}

    layerSelection->setNumRows(world->getNumLayers());

    // TODO: Maybe remove the widgets off the end of the list for
    // layers that go beyond the max? (Doesn't really matter that
    // much.)
    
    // Spin the wheels a bit to make sure we have a valid layer
    // selected still.
    setActiveLayer(getActiveLayer());

    // Set values in the layer window.
    layer_nameEntry->setText(world->getLayerName(getActiveLayer()));

    ostringstream str;
    str << world->getCamScaleForLayer(getActiveLayer());
    layer_camScaleEntry->setText(str.str());

    // Fix up tile information.
    int tileSize = world->getLayerTileSize(getActiveLayer());
    string tileSetName = world->getLayerTileSet(getActiveLayer());

    rebuildTiles(tileSetName, tileSize);

    // Lighting info.
    layer_fullbrightToggle->setToggleValue(world->getLayerFullbrightLights(getActiveLayer()));
    layer_lightToggle->setToggleValue(world->getLayerLighting(getActiveLayer()));

    layer_combineToggle->setToggleValue(world->getLayerCombineWithPrevious(getActiveLayer()));
    layer_tilesAsLightsToggle->setToggleValue(world->getLayerTilesAsLightMap(getActiveLayer()));
}

void JunkEditor::appendConsoleOutput(const std::string &str) {
	
	if(consoleSlider->getMaxValue() == consoleSlider->getValue()) {
		
		// If we're scrolled to the end of the buffer, stay there.
		readjustConsoleSliderAfterUpdate = true;
	}
	
	consoleOutput->setText(consoleOutput->getText() + str);
}

void JunkEditor::unsetAllTileButtons(void) {
	
	for(int i = 0; i < tab_tileContainerGrid->getNumChildren(); i++) {
		
		WidgetButton *tileButton = dynamic_cast<WidgetButton*>(tab_tileContainerGrid->getChildInSlot(i));
		
		if(tileButton) {
			tileButton->setToggleValue(false);
		}
	}
}

static bool tileButtonClicked(Widget *w, void *data) {
	
	JunkEditor *editor = (JunkEditor*)data;
	WidgetButton *button = dynamic_cast<WidgetButton*>(w);	
	bool shiftHeld = false;
	int thisTile = -1;
	bool toggleValue = 0;

	if(button) {
		
		// Hacky way to determine if shift is held...
		SDL_PumpEvents();
		Uint8 *keyState = SDL_GetKeyState(NULL);
		if(keyState[SDLK_LSHIFT]) {
			shiftHeld = true;
		}

		thisTile = atoi(button->getName().c_str());
		toggleValue = button->getToggleValue();

		if(!shiftHeld) {
		
			// No multi-select. Clear everything.
		
			editor->currentTiles.clear();
		
			// Make sure all the other tile buttons deselect.
			
			editor->unsetAllTileButtons();
			button->setToggleValue(toggleValue);

		} else {
			
			// Multi-select. Just take this one out of the list.
			
			for(unsigned int i = 0; i < editor->currentTiles.size(); i++) {
				if(editor->currentTiles[i] == thisTile) {
					editor->currentTiles[i] = editor->currentTiles[editor->currentTiles.size() - 1];
					editor->currentTiles.erase(editor->currentTiles.end() - 1);
					break;
				}
			}
			
		}
		
		if(button->getToggleValue()) {
			editor->currentTiles.push_back(thisTile);
		}
		
		//cout << "Tiles now..." << endl;
		//for(unsigned int i = 0; i < editor->currentTiles.size(); i++) {
		//	cout << editor->currentTiles[i] << " " << endl;
		//}
	}
	
	return false;
}

void JunkEditor::addPickedTile(int tile) {
	
	bool foundIt = false;
	for(unsigned int i = 0; i < currentTiles.size(); i++) {
		if(currentTiles[i] == tile) {
			foundIt = true;
			break;
		}
	}
	
	if(!foundIt) {
		currentTiles.push_back(tile);
	}

	// And set the button.
	for(int i = 0; i < tab_tileContainerGrid->getNumChildren(); i++) {
		
		WidgetButton *tileButton = dynamic_cast<WidgetButton*>(tab_tileContainerGrid->getChildInSlot(i));
		
		if(tileButton) {
			if(atoi(tileButton->getName().c_str()) == tile) {
				tileButton->setToggleValue(true);
			}
		}
	}
	
}

void JunkEditor::clearPickedTiles(void) {
	
	currentTiles.clear();
	
	// Unset all buttons.
	unsetAllTileButtons();
}


void JunkEditor::rebuildTiles(const std::string &tileSet, int tileSize) {
	
	this->tileSize = tileSize;
	
	tab_tileContainerGrid->clearChildren();
	
	TextureManager *manager = TextureManager::get();
	
	Texture *tex = manager->getTextureByName(tileSet);
	
	// TODO: Texture directory hierarchies blah blah blah.

    // Replace full paths with just the names.

    string fixedName;
    vector<string> multiNames;
    ostringstream fixedNameStr;
    stringTokenize(tileSet, ":", multiNames, true);

    for(unsigned int i = 0; i < multiNames.size(); i++) {
        fixedNameStr << FileSystem::getBaseName(multiNames[i]);
        if(i + 1 < multiNames.size()) {
            fixedNameStr << ":";
        }
    }

    fixedName = fixedNameStr.str();

    // Set the widget text to that.

	tab_tileFilename->setText(fixedName);

    ostringstream sizeStr;
    sizeStr << tileSize;

    tab_tileSize->setText(sizeStr.str());
	
	if(tex) {

        Vector2D texSize = manager->getTextureSize(tex->getName());

		int rows = texSize.y / tileSize;
		int cols = texSize.x / tileSize;
		
		tab_tileContainerGrid->setNumRows(rows + 1);
		tab_tileContainerGrid->setNumCols(cols);
		tab_tileContainerGrid->setStretchableCol(-1);
		tab_tileContainerGrid->setStretchableRow(-1);
		
		// Clear tile.
		Widget *tileGraphic = new Widget();
		tileGraphic->setBackgroundImage("editordata/cleartile.tga");
		tileGraphic->setMinWidth(tileSize);
		tileGraphic->setMinHeight(tileSize);
		
		WidgetButton *tileButton = new WidgetButton();
		tileButton->setBackgroundImage("editordata/1pxbox1.ninepatch");
		tileButton->setBackgroundDefault("editordata/1pxbox1.ninepatch");
		tileButton->setBackgroundActive("editordata/1pxbox2.ninepatch");
		tileButton->setBackgroundMouseOver("editordata/1pxbox3.ninepatch");
		tileButton->setToggleable(true);
		tileButton->setLabelPadding(4);
		tileButton->replaceLabelWidget(tileGraphic);
		tileButton->setMinWidth(tileSize);
		tileButton->setMinHeight(tileSize);
		tileButton->setName("-1");
		tileButton->setNativeEventHandler("onClick", tileButtonClicked, this);
		
		tab_tileContainerGrid->addChild(tileButton);

		// Empty space on top row.
		for(int x = 1; x < cols; x++) {
			tab_tileContainerGrid->addChild(NULL);
		}
		
		int i = 0;
		
		for(int y = 0; y < rows; y++) {
			for(int x = 0; x < cols; x++) {
				
				Widget *tileGraphic = new Widget();
				tileGraphic->setBackgroundImage(tileSet);
				tileGraphic->setBackgroundOffset(x * tileSize, y * tileSize);
				tileGraphic->setMinWidth(tileSize);
				tileGraphic->setMinHeight(tileSize);
				
				WidgetButton *tileButton = new WidgetButton();
				tileButton->setBackgroundImage("editordata/1pxbox1.ninepatch");
				tileButton->setBackgroundDefault("editordata/1pxbox1.ninepatch");
				tileButton->setBackgroundActive("editordata/1pxbox2.ninepatch");
				tileButton->setBackgroundMouseOver("editordata/1pxbox3.ninepatch");
				tileButton->setToggleable(true);
				//tileButton->setBackgroundOffset(x * tileSize, y * tileSize);
				
				//tileButton->setLabel("");
				tileButton->setLabelPadding(4);
				tileButton->replaceLabelWidget(tileGraphic);
				
				//tileButton->setBackgroundImage("editordata/np_ff1.ninepatch");
				//tileButton->setBackgroundDefault("editordata/np_ff1.ninepatch");
				//tileButton->setBackgroundActive("editordata/np_ff1.ninepatch");
				
				tileButton->setMinWidth(tileSize);
				tileButton->setMinHeight(tileSize);
				
				tileButton->setNativeEventHandler("onClick", tileButtonClicked, this);
				
				ostringstream str;
				str << i++;
				tileButton->setName(str.str());
				
				tab_tileContainerGrid->addChild(tileButton);
			}
		}
	
	}
	
	//tab_tileContainerGrid->setBackgroundImage(tileSet);
	
}

int JunkEditor::getCurrentTile(void) {
	
	if(!currentTiles.size()) return -1;
	
	return currentTiles[rand() % currentTiles.size()];
	
}

Widget *JunkEditor::getRootWidget(void) {
	return rootContainer;
}

void JunkEditor::flagDataDirty(void) {
	dataDirty = true;
}

void JunkEditor::addConsoleCommand(const std::string &command) {
	consoleCommands.push_back(command);
}

Widget *JunkEditor::getTopWidget(void) {
	
	if(rootWidgetStack.size()) {
		return rootWidgetStack[rootWidgetStack.size() - 1];
	}
	
	return NULL;
}

int JunkEditor::getWidgetStackSize(void) {
	return (int)rootWidgetStack.size();
}


void JunkEditor::updateLightSliders(const Vector3D &ambient, bool retro, bool disable) {
    
    lighting_ambient_redSlider->setValue(ambient.x);
    lighting_ambient_greenSlider->setValue(ambient.y);
    lighting_ambient_blueSlider->setValue(ambient.z);

    lighting_settings_retroEffectsButton->setToggleValue(retro);
    lighting_settings_disableButton->setToggleValue(disable);

    // Uh... just pump these to make it pick the right image.
    lighting_settings_linkLayersButton->setToggleValue(
        lighting_settings_linkLayersButton->getToggleValue());

    lighting_settings_tintInactiveButton->setToggleValue(
        lighting_settings_tintInactiveButton->getToggleValue());

}

bool JunkEditor::getLightsDirty(void) {
    bool ret = lightsDirty;
    lightsDirty = false;
    return ret;
}

Vector3D JunkEditor::getAmbientLights(void) {
    Vector3D vec(
        lighting_ambient_redSlider->getValue(),
        lighting_ambient_greenSlider->getValue(),
        lighting_ambient_blueSlider->getValue());

    return vec;
}

bool JunkEditor::getRetro(void) {
    return lighting_settings_retroEffectsButton->getToggleValue();
}

bool JunkEditor::getLightsDisabled(void) {
    return lighting_settings_disableButton->getToggleValue();
}

bool JunkEditor::getLightLayersLinked(void) {
    return lighting_settings_linkLayersButton->getToggleValue();
}

bool JunkEditor::getTintInactiveLayers(void) {
    return lighting_settings_tintInactiveButton->getToggleValue();
}

