#include "3dmodelio/TextureAtlasData.h"
#include "gamemath/MouseCoordinateTransforms.h"
#include "gamemath/Scalar.h"
#include "gamemath/TextureAtlas.h"
#include "font/BitmapFont.h"
#include "imageio/ImageIO.h"
#include "jsonserialization/JSONDeserializationContext.h"
#include "renderer/Renderable.h"
#include "renderer/Renderer.h"
#include "renderer/Texture.h"
#include "shadercollection/ShaderCollection.h"
#include "shadercollection/ShaderConfiguration2DTexture.h"
#include "shell/Shell.h"
#include "shell/ShellCallbacks.h"
#include "shell/ShellKeyCodes.h"
#include "uitoolkit/UIAppearance.h"
#include "uitoolkit/UIButton.h"
#include "uitoolkit/UICheckbox.h"
#include "uitoolkit/UIContainer.h"
#include "uitoolkit/UIContinuousSlider.h"
#include "uitoolkit/UIDrawingInterface2DTexture.h"
#include "uitoolkit/UIEditText.h"
#include "uitoolkit/UIGraphicalButton.h"
#include "uitoolkit/UILabel.h"
#include "uitoolkit/UIMenuBar.h"
#include "uitoolkit/UIModalConfirmationDialog.h"
#include "uitoolkit/UIPopUpMenu.h"
#include "uitoolkit/UIPopUpView.h"
#include "uitoolkit/UIRadioButton.h"
#include "uitoolkit/UIRadioGroup.h"
#include "uitoolkit/UIScrollContainer.h"
#include "uitoolkit/UISlider.h"
#include "uitoolkit/UIStepper.h"
#include "uitoolkit/UITextListView.h"
#include "uitoolkit/UIToolkitAppearance.h"
#include "uitoolkit/UIToolkitContext.h"
#include "uitoolkit/UIToolkitCursor.h"
#include "uitoolkit/UIToolkitDrawing.h"
#include "uitoolkit/UITooltipRoot.h"
#include "uitoolkit/UITypeface_BitmapFont.h"
#include "uitoolkit/UIWindowRoot.h"
#include "uitoolkit/UIWindowView.h"
#include "utilities/AutoFreePool.h"
#include "utilities/IOUtilities.h"

#if defined(STEM_PLATFORM_macosx)
#include "nsopenglshell/NSOpenGLShell.h"
#include "nsopenglshell/NSOpenGLTarget.h"
#elif defined(STEM_PLATFORM_iphonesimulator) || defined(STEM_PLATFORM_iphoneos)
#include "eaglshell/EAGLShell.h"
#include "eaglshell/EAGLTarget.h"
#elif defined(STEM_PLATFORM_windows)
#include "wglshell/WGLShell.h"
#include "wglshell/WGLTarget.h"
#elif defined(STEM_PLATFORM_linux)
#include "glxshell/GLXShell.h"
#include "glxshell/GLXTarget.h"
#elif defined(STEM_PLATFORM_android)
#include "eglshell/EGLShell.h"
#include "eglshell/EGLTarget.h"
#else
#error Unsupported platform
#endif

#include "stem_core.h"
#include <stdio.h>
#include <unistd.h>

static Renderer * renderer;
static RenderLayer * renderLayer;
static ShaderConfiguration2DTexture * shaderConfiguration;
static unsigned int viewWidth = 1280, viewHeight = 720;
static float viewRatio = 16.0f / 9.0f;
static float scaleFactor = 1.0f;
static UIElement * rootElement;
static UIDrawingInterface2DTexture * drawingInterface;
static UIToolkitContext uiContext;
static UITypeface_BitmapFont * typeface;
static UIAppearance appearance;
static Texture * texture;
static TextureAtlas * atlas;
static BitmapFont * font;
static Renderable * renderable;
static Rect4f alternatingRowBoxRect = {320.0f, 620.0f, 10.0f, 310.0f};
static float rowHeight = 35.0f;
static bool draggingAlternatingRowBox, draggingRowHeight;
static Vector2f lastMousePosition;
static UIMenuBar * menuBar;
static UIWindowRoot * windowRoot;
static UIWindowView * window1, * window2;
static UIPopUpView * popUpView;
static UICheckbox * checkbox;
static UIScrollContainer * scrollContainer;

#define ROW_HEIGHT_MIN 2.0f
#define ROW_HEIGHT_MAX 200.0f

static bool Target_draw(double referenceTime, double activeDrawDelta) {
	double currentTime = Shell_getCurrentTime();
	Renderer_clear(renderer, COLOR4f(1.0f, 1.0f, 1.0f, 0.0f));
	Renderer_drawLayer(renderer, renderLayer, currentTime, activeDrawDelta);
	if (call_virtual(needsRedraw, rootElement)) {
		Shell_redisplay();
	}
	AutoFreePool_empty();
	return true;
}

static void Target_keyDown(unsigned int charCode, unsigned int keyCode, unsigned int modifiers, bool isRepeat, double referenceTime) {
	if (keyCode == KEY_CODE_ENTER && (modifiers & MODIFIER_ANY_ALT_BIT)) {
		if (Shell_isFullScreen()) {
			Shell_exitFullScreen();
		} else {
			Shell_enterFullScreen(Shell_getDisplayIndexFromWindow(), false);
		}
		
	} else if (keyCode == KEY_CODE_Q && (modifiers & MODIFIER_PLATFORM_MENU_COMMAND_BIT)) {
		exit(EXIT_SUCCESS);
		
	} else {
		bool handled = call_virtual(keyDown, rootElement, charCode, keyCode, modifiers, isRepeat, false, referenceTime);
		if (!handled) {
			switch (keyCode) {
				case KEY_CODE_LEFT_ARROW:
				case KEY_CODE_A:
					handled = call_virtual(menuDirectionDown, rootElement, UI_LEFT, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_RIGHT_ARROW:
				case KEY_CODE_D:
					handled = call_virtual(menuDirectionDown, rootElement, UI_RIGHT, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_UP_ARROW:
				case KEY_CODE_W:
					handled = call_virtual(menuDirectionDown, rootElement, UI_UP, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_DOWN_ARROW:
				case KEY_CODE_S:
					handled = call_virtual(menuDirectionDown, rootElement, UI_DOWN, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_TAB:
					handled = call_virtual(tabNavigate, rootElement, modifiers, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_SPACE:
				case KEY_CODE_ENTER:
				case KEY_CODE_Z:
					handled = call_virtual(menuActionDown, rootElement, 0, isRepeat, referenceTime);
					break;
					
				case KEY_CODE_ESCAPE:
				case KEY_CODE_X:
					handled = call_virtual(menuActionDown, rootElement, 1, isRepeat, referenceTime);
					if (!handled) {
						call_virtual(setFocusedElement, rootElement, NULL, NULL, UI_NONE);
						handled = true;
					}
					break;
					
				case KEY_CODE_C:
					handled = call_virtual(menuActionDown, rootElement, 2, isRepeat, referenceTime);
					break;
			}
		}
		if (handled) {
			Shell_redisplay();
		}
	}
}

static void Target_keyUp(unsigned int keyCode, unsigned int modifiers, double referenceTime) {
	bool handled = call_virtual(keyUp, rootElement, keyCode, modifiers, referenceTime);
	if (!handled) {
		switch (keyCode) {
			case KEY_CODE_LEFT_ARROW:
				handled = call_virtual(menuDirectionUp, rootElement, UI_LEFT, referenceTime);
				break;
				
			case KEY_CODE_RIGHT_ARROW:
				handled = call_virtual(menuDirectionUp, rootElement, UI_RIGHT, referenceTime);
				break;
				
			case KEY_CODE_UP_ARROW:
				handled = call_virtual(menuDirectionUp, rootElement, UI_UP, referenceTime);
				break;
				
			case KEY_CODE_DOWN_ARROW:
				handled = call_virtual(menuDirectionUp, rootElement, UI_DOWN, referenceTime);
				break;
				
			case KEY_CODE_SPACE:
			case KEY_CODE_ENTER:
			case KEY_CODE_Z:
				handled = call_virtual(menuActionUp, rootElement, 0, referenceTime);
				break;
				
			case KEY_CODE_ESCAPE:
			case KEY_CODE_X:
				handled = call_virtual(menuActionUp, rootElement, 1, referenceTime);
				break;
				
			case KEY_CODE_C:
				handled = call_virtual(menuActionUp, rootElement, 2, referenceTime);
				break;
		}
	}
	if (handled) {
		Shell_redisplay();
	}
}

static void Target_keyModifiersChanged(unsigned int modifiers, unsigned int lastModifiers, double referenceTime) {
	if (call_virtual(keyModifiersChanged, rootElement, modifiers, lastModifiers, referenceTime)) {
		Shell_redisplay();
	}
}

static Vector2f transformMousePosition(float x, float y) {
	return VECTOR2f(x / scaleFactor, (viewHeight - y) / scaleFactor);
}

static void Target_mouseDown(unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, double referenceTime) {
	Vector2f position = transformMousePosition(x, y);
	if (call_virtual(mouseDown, rootElement, buttonNumber, buttonMask, position.x, position.y, modifiers, false, referenceTime)) {
		Shell_redisplay();
	} else {
		if (modifiers & MODIFIER_SHIFT_BIT) {
			draggingRowHeight = true;
		} else {
			draggingAlternatingRowBox = true;
		}
	}
	lastMousePosition = position;
}

static void Target_mouseUp(unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, double referenceTime) {
	Vector2f position = transformMousePosition(x, y);
	if (!draggingAlternatingRowBox) {
		if (call_virtual(mouseUp, rootElement, buttonNumber, buttonMask, position.x, position.y, modifiers, referenceTime)) {
			Shell_redisplay();
		}
	}
	rowHeight = clampf(rowHeight, ROW_HEIGHT_MIN, ROW_HEIGHT_MAX);
	draggingAlternatingRowBox = false;
	lastMousePosition = position;
}

static void Target_mouseMoved(float x, float y, float deltaX, float deltaY, unsigned int modifiers, double referenceTime) {
	Vector2f position = transformMousePosition(x, y);
	if (call_virtual(mouseMoved, rootElement, position.x, position.y, deltaX / scaleFactor, deltaY / scaleFactor, modifiers, referenceTime)) {
		Shell_redisplay();
	}
	Shell_setCursor(call_virtual(getCursorAtPosition, rootElement, position.x, position.y));
	lastMousePosition = position;
}

static void Target_mouseDragged(unsigned int buttonMask, float x, float y, float deltaX, float deltaY, unsigned int modifiers, double referenceTime) {
	Vector2f position = transformMousePosition(x, y);
	if (draggingAlternatingRowBox) {
		alternatingRowBoxRect.xMax += position.x - lastMousePosition.x;
		alternatingRowBoxRect.yMin += position.y - lastMousePosition.y;
		Shell_redisplay();
		
	} else if (draggingRowHeight) {
		rowHeight += position.y - lastMousePosition.y;
		Shell_redisplay();
		
	} else {
		if (call_virtual(mouseDragged, rootElement, buttonMask, position.x, position.y, deltaX / scaleFactor, deltaY / scaleFactor, modifiers, referenceTime)) {
			Shell_redisplay();
		}
	}
	lastMousePosition = position;
}

static void Target_mouseLeave(unsigned int modifiers, double referenceTime) {
	if (call_virtual(mouseLeave, rootElement, modifiers, referenceTime)) {
		Shell_redisplay();
	}
}

static void Target_scrollWheel(float x, float y, int deltaX, int deltaY, unsigned int buttonMask, unsigned int modifiers, double referenceTime) {
	Vector2f position = transformMousePosition(x, y);
	if (call_virtual(scrollWheel, rootElement, position.x, position.y, deltaX, deltaY, buttonMask, modifiers, false, referenceTime)) {
		Shell_redisplay();
	}
	lastMousePosition = position;
}

static void updateUIBounds(void) {
	setAppearanceRect4f(&appearance, UIToolkit_uiBounds, RECT4f(0, viewWidth / scaleFactor, 0, viewHeight / scaleFactor));
	setAppearanceRect4f(&appearance, UIToolkit_safeDisplayBounds, RECT4f(10, viewWidth / scaleFactor - 10, 10, viewHeight / scaleFactor - 40));
}

static void Target_resized(unsigned int newWidth, unsigned int newHeight, double referenceTime) {
	viewWidth = newWidth;
	viewHeight = newHeight;
	viewRatio = (float) newWidth / newHeight;
	scaleFactor = Shell_getDisplayScaleFactor(Shell_getDisplayIndexFromWindow());
	if (renderer != NULL) {
		Renderer_setViewport(renderer, 0, 0, viewWidth, viewHeight, NULL);
		call_virtual(setProjectionMatrix, shaderConfiguration, Matrix4x4f_ortho(MATRIX4x4f_IDENTITY, 0.0f, viewWidth / scaleFactor, 0.0f, viewHeight / scaleFactor, -1.0f, 1.0f));
		drawingInterface->scaleFactor = scaleFactor;
		updateUIBounds();
		menuBar->position.y = viewHeight / scaleFactor;
		menuBar->width = viewWidth / scaleFactor;
	}
}

static void Target_backgrounded(double referenceTime) {
}

static void Target_foregrounded(double referenceTime) {
}

static void writeUIVertices(Renderable * sprite, VertexIO * vertexIO, void * context) {
	UIElement * selectedElement = call_virtual(getFocusedElement, rootElement);
	if (selectedElement != NULL) {
		Rect4f focusBounds = call_virtual(getFocusBounds, selectedElement);
		call_virtual(drawSlicedQuad3x3, drawingInterface, Rect4f_inset(focusBounds, VECTOR2f(-3, -3)),
		                                                  TextureAtlas_lookup(atlas, HashTable_stringKey("highlight_box")),
		                                                  SLICE_GRID_3x3(5, 1, 5, 5, 1, 5),
		                                                  COLOR4f(1.0f, 1.0f, 1.0f, 1.0f),
		                                                  vertexIO);
	}
	
	call_virtual(drawSlicedQuad3x3WithAlternatingRowColors, drawingInterface, Rect4f_round(alternatingRowBoxRect),
	                                                                          TextureAtlas_lookup(atlas, HashTable_stringKey("radio_up")),
	                                                                          SLICE_GRID_3x3(10, 2, 10, 10, 2, 10),
	                                                                          8.0f,
	                                                                          roundpositivef(clampf(rowHeight, ROW_HEIGHT_MIN, ROW_HEIGHT_MAX)),
	                                                                          COLOR4f(1.0f, 1.0f, 1.0f, 1.0f),
	                                                                          COLOR4f(0.8f, 0.9f, 1.0f, 1.0f),
	                                                                          vertexIO);
}

static void button1ActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	printf("Button 1 action (0x%X, %f)\n", modifiers, referenceTime);
}

static void button2ActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	printf("Button 2 action (0x%X, %f)\n", modifiers, referenceTime);
}

static void window1ButtonActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	if (window1->visible) {
		call_virtual(hideWindow, window1);
	} else {
		call_virtual(showWindow, window1);
		call_virtual(bringToFront, window1);
		UIContainer_setFocusedElement((UIContainer *) rootElement, window1, NULL, UI_NONE);
	}
}

static void window2ButtonActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	if (window2->visible) {
		call_virtual(hideWindow, window2);
	} else {
		call_virtual(showWindow, window2);
		call_virtual(bringToFront, window2);
		UIContainer_setFocusedElement((UIContainer *) rootElement, window2, NULL, UI_NONE);
	}
}

static void dialogCallback(UIModalConfirmationDialog * dialog, unsigned int buttonIndex, void * context1, void * context2) {
	printf("Dialog option %u (%p, %p)\n", buttonIndex, context1, context2);
	UIWindowRoot_removeWindow(windowRoot, dialog);
}

static void dialog1ButtonActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	UIModalConfirmationDialog * dialog = UIModalConfirmationDialog_create(STRL("Save before closing"), STRL("Test save before closing dialog"), dialogCallback, (void *) 0x1, (void *) 0x2, windowRoot, appearance, "Save", KEY_SHORTCUT(KEY_CODE_ENTER, 0), "Cancel", KEY_SHORTCUT(KEY_CODE_ESCAPE, 0), "Don't save", KEY_SHORTCUT(KEY_CODE_D, MODIFIER_PLATFORM_MENU_COMMAND_BIT), NULL);
	UIWindowRoot_addWindow(windowRoot, dialog, true);
	call_virtual(setFocusedElement, rootElement, dialog, NULL, UI_NONE);
}

static void dialog2ButtonActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	UIModalConfirmationDialog * dialog = UIModalConfirmationDialog_create(STRL("Confirm"), STRL("Test yes/no dialog"), dialogCallback, (void *) 0x3, (void *) 0x4, windowRoot, appearance, "Yes", KEY_SHORTCUT_MULTIPLE(KEY_CODE_ENTER, 0, KEY_CODE_Y, 0, NULL), "No", KEY_SHORTCUT_MULTIPLE(KEY_CODE_ESCAPE, 0, KEY_CODE_N, 0, NULL), NULL);
	UIWindowRoot_addWindow(windowRoot, dialog, true);
	call_virtual(setFocusedElement, rootElement, dialog, NULL, UI_NONE);
}

static void button3ActionCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	printf("Button 3 action (0x%X, %f)\n", modifiers, referenceTime);
}

static void popUpViewButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	UIPopUpView_setInvokerBounds(popUpView, call_virtual(getBounds, button));
	popUpView->visible = true;
}

static void insidePopUpViewButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	UIPopUpView_setSidePreference(popUpView, (popUpView->sidePreference + 1) % 4);
}

static void scrollContainerButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	call_virtual(scrollToInnerRect, scrollContainer, call_virtual2(getBounds, button));
}

static void closePopUpCallback(UIPopUpView * popUpView, void * context) {
	popUpView->visible = false;
}

static void checkboxActionCallback(UICheckbox * checkbox, bool checked, unsigned int modifiers, double referenceTime, void * context) {
	printf("Checkbox action (%schecked, 0x%X, %f)\n", checked ? "" : "not ", modifiers, referenceTime);
}

static void mixButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) {
	checkbox->mixed = !checkbox->mixed;
}

static void radioActionCallback(UIRadioButton * radioButton, unsigned int modifiers, double referenceTime, void * context) {
	printf("Radio button action for button %p (0x%X, %f)\n", radioButton, modifiers, referenceTime);
}

static bool singleLineEditTextNewlineCallback(UIEditText * editText, unsigned int modifiers, double referenceTime, void * context) {
	printf("Edit text action for %p\n", editText);
	return false;
}

static void singleLineEditTextChangeCallback(UIEditText * editText, double referenceTime, void * context) {
	printf("Edit text change for %p\n", editText);
}

static bool singleLineEditTextChangeCompleteCallback(UIEditText * editText, double referenceTime, void * context) {
	printf("Edit text change complete for %p\n", editText);
	return true;
}

static bool singleLineEditTextChangeCanceledCallback(UIEditText * editText, double referenceTime, void * context) {
	printf("Edit text change canceled for %p\n", editText);
	call_virtual(revertText, editText);
	UIElement_unfocus(editText);
	return false;
}

static void sliderChangeCallback(UISlider * slider, float value, unsigned int modifiers, double referenceTime, void * context) {
	printf("Slider %p changed to %f (modifiers 0x%X)\n", slider, value, modifiers);
}

static void sliderChangeCompleteCallback(UISlider * slider, float value, unsigned int modifiers, double referenceTime, void * context) {
	printf("Slider %p changes complete (modifiers 0x%X)\n", slider, modifiers);
}

static void popUpMenuCallback(UIPopUpMenu * popUpMenu, unsigned int itemIndex, int itemIdentifier, unsigned int modifiers, double referenceTime, void * context) {
	printf("Pop-up menu %p selection changed to %u (identifier %d, modifiers 0x%X)\n", popUpMenu, itemIndex, itemIdentifier, modifiers);
}

static void listViewCallback(UIListViewBase * listView, double referenceTime, void * context) {
	printf("List view %p item action for %u (identifier %d)\n", listView, listView->selectedLineIndex, UITextListView_getSelectedItemIdentifier((UITextListView *) listView));
}

static void listViewSelectionChangedCallback(UIListViewBase * listView, double referenceTime, void * context) {
	printf("List view %p selection changed\n", listView);
}

static void listViewDeleteLineCallback(UIListViewBase * listView, unsigned int modifiers, bool isRepeat, double referenceTime, void * context) {
	printf("List view %p delete line callback (modifiers = 0x%X, isRepeat = %s)\n", listView, modifiers, isRepeat ? "true" : "false");
}

static void stepper1Callback(UIStepper * stepper, int change, unsigned int modifiers, double referenceTime, void * context) {
	printf("Stepper %p action %d with modifiers 0x%X\n", stepper, change, modifiers);
}

static void stepperCompleteCallback(UIStepper * stepper, double referenceTime, void * context) {
	printf("Stepper %p complete\n", stepper);
}

static void stepper2Callback(UIStepper * stepper, int change, unsigned int modifiers, double referenceTime, void * context) {
	UIStepper * stepper1 = context;
	if (change == -1) {
		stepper1->downEnabled = !stepper1->downEnabled;
	} else if (change == 1) {
		stepper1->upEnabled = !stepper1->upEnabled;
	}
}

static void menuItemActionCallback(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, unsigned int modifiers, double referenceTime, void * context) {
	printf("Menu %u item %u action with modifiers 0x%X\n", menuIdentifier, menuItemIdentifier, modifiers);
	UIMenuBar_setItemChecked(menuBar, menuIdentifier, menuItemIdentifier, !UIMenuBar_getItemChecked(menuBar, menuIdentifier, menuItemIdentifier));
}

static void validateMenuItemCallback(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, UIMenuItemProperties * properties, void * context) {
	printf("Menu %u item %u (\"%s\") validation\n", menuIdentifier, menuItemIdentifier, properties->title);
	if (menuItemIdentifier == 5) {
		properties->enabled = !properties->enabled;
		properties->checked = !properties->checked;
		snprintf_safe(properties->title, sizeof(properties->title), "%sabled submenu", properties->enabled ? "En" : "Dis");
	} else if (menuItemIdentifier == 2) {
		snprintf_safe(properties->title, sizeof(properties->title), "Submenu %d", rand());
	}
}

static void contextMenuCallback(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, UIMenuBar_displayContextMenuCallback displayContextMenu, void * menuBarContext, void * context) {
	if (menuIdentifier == 0 && menuItemIdentifier == 0) {
		UIMenuItem contextMenuItems[2] = {
			MENU_ITEM(STRL("Context menu item 1"), 100, MENU_NO_SHORTCUT),
			MENU_ITEM(STRL("Context menu item 2"), 101, MENU_NO_SHORTCUT)
		};
		displayContextMenu(sizeof_count(contextMenuItems), contextMenuItems, menuBarContext);
	}
}

static void closeWindowCallback(UIWindowView * window, void * context) {
	window->visible = false;
}

static Rect4f resizeWindowCallback(UIWindowView * window, Rect4f newBounds, Vector2i resizeDirection, void * context) {
	if (Shell_getModifierKeys() & MODIFIER_SHIFT_BIT) {
		Vector2f newSize = {newBounds.xMax - newBounds.xMin, newBounds.yMax - newBounds.yMin};
		float constrainedSize = fminf(newSize.x, newSize.y);
		if (resizeDirection.x == -1) {
			newBounds.xMin = newBounds.xMax - constrainedSize;
		} else if (resizeDirection.x == 1) {
			newBounds.xMax = newBounds.xMin + constrainedSize;
		} else {
			newBounds.xMin = newBounds.xMax - newSize.y - ((newBounds.xMax - newBounds.xMin - newSize.y) / 2);
			newBounds.xMax = newBounds.xMin + newSize.y;
		}
		if (resizeDirection.y == -1) {
			newBounds.yMin = newBounds.yMax - constrainedSize;
		} else if (resizeDirection.y == 1) {
			newBounds.yMax = newBounds.yMin + constrainedSize;
		} else {
			newBounds.yMin = newBounds.yMax - newSize.x - ((newBounds.yMax - newBounds.yMin - newSize.x) / 2);
			newBounds.yMax = newBounds.yMin + newSize.x;
		}
	} else if (Shell_getModifierKeys() & MODIFIER_CONTROL_BIT) {
		printf("resizeWindowCallback(%p, {%f, %f, %f, %f}, {%d, %d}, %p)\n", window, newBounds.xMin, newBounds.xMax, newBounds.yMin, newBounds.yMax, resizeDirection.x, resizeDirection.y, context);
	}
	return newBounds;
}

static void continuousSliderChangeCallback(UIContinuousSlider * slider, Vector2f value, Vector2f offset, Vector2f totalOffset, double referenceTime, void * context) {
	printf("Continuous slider %p change: {%f, %f}, {%f, %f}, {%f, %f}\n", slider, value.x, value.y, offset.x, offset.y, totalOffset.x, totalOffset.y);
}

static void continuousSliderChangeCompleteCallback(UIContinuousSlider * slider, Vector2f value, Vector2f offset, Vector2f totalOffset, double referenceTime, void * context) {
	printf("Continuous slider %p change complete: {%f, %f}, {%f, %f}, {%f, %f}\n", slider, value.x, value.y, offset.x, offset.y, totalOffset.x, totalOffset.y);
}

static void cursorUpdatedCallback(void) {
	Shell_setCursor(call_virtual(getCursorAtPosition, rootElement, lastMousePosition.x, lastMousePosition.y));
}

static void registerShellCallbacks() {
	Shell_drawFunc(Target_draw);
	Shell_resizeFunc(Target_resized);
	Shell_keyDownFunc(Target_keyDown);
	Shell_keyUpFunc(Target_keyUp);
	Shell_keyModifiersChangedFunc(Target_keyModifiersChanged);
	Shell_mouseDownFunc(Target_mouseDown);
	Shell_mouseUpFunc(Target_mouseUp);
	Shell_mouseMovedFunc(Target_mouseMoved);
	Shell_mouseDraggedFunc(Target_mouseDragged);
	Shell_mouseLeaveFunc(Target_mouseLeave);
	Shell_scrollWheelFunc(Target_scrollWheel);
	Shell_backgroundedFunc(Target_backgrounded);
	Shell_foregroundedFunc(Target_foregrounded);
}

#if defined(STEM_PLATFORM_macosx)
void NSOpenGLTarget_configure(int argc, const char ** argv, struct NSOpenGLShellConfiguration * configuration) {
	configuration->windowTitle = STEM_HUMAN_READABLE_TARGET_NAME;
	configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0);
	configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0);
	configuration->useGLCoreProfile = true;
#elif defined(STEM_PLATFORM_iphonesimulator) || defined(STEM_PLATFORM_iphoneos)
void EAGLTarget_configure(int argc, char ** argv, struct EAGLShellConfiguration * configuration) {
#elif defined(STEM_PLATFORM_windows)
void WGLTarget_configure(void * instance, void * prevInstance, char * commandLine, int command, int argc, const char ** argv, struct WGLShellConfiguration * configuration) {
	configuration->windowTitle = STEM_HUMAN_READABLE_TARGET_NAME;
	configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0);
	configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0);
	configuration->useGLCoreProfile = true;
#elif defined(STEM_PLATFORM_linux)
void GLXTarget_configure(int argc, const char ** argv, struct GLXShellConfiguration * configuration) {
#include "IconData_stemapp.h"
	configuration->icon.data = STATIC_iconData_stemapp;
	configuration->icon.size = sizeof(STATIC_iconData_stemapp) / sizeof(STATIC_iconData_stemapp[0]);
	configuration->windowTitle = STEM_HUMAN_READABLE_TARGET_NAME;
	configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0);
	configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0);
	configuration->applicationName = STEM_HUMAN_READABLE_TARGET_NAME;
#elif defined(STEM_PLATFORM_android)
void EGLTarget_configure(struct EGLShellConfiguration * configuration) {
	readResourceFile = EGLShell_readResourceFile;
#else
#error Unsupported platform
#endif
	registerShellCallbacks();
}

static void listRenderablesCallback(RenderableIO * renderableIO, void * context) {
	call_virtual(listRenderables, rootElement, renderableIO, 0, RECT4i_EMPTY);
	RenderableIO_addRenderable(renderableIO, renderable, 0, RECT4i_EMPTY);
}

void Target_init() {
	chdir(Shell_getResourcePath());
	
	renderer = Renderer_create();
	renderLayer = RenderLayer_create(RENDER_LAYER_SORT_DRAW_ORDER_ONLY, listRenderablesCallback, NULL);
	
	JSONDeserializationContext * context = JSONDeserializationContext_createWithResourceFile("testappearance.atlas");
	if (context->status != SERIALIZATION_ERROR_OK) {
		fprintf(stderr, "Fatal error: Couldn't load testappearance.atlas (status %d)\n", context->status);
		exit(EXIT_FAILURE);
	}
	TextureAtlasData * atlasData = TextureAtlasData_deserialize(context);
	call_virtual(dispose, context);
	if (atlasData == NULL) {
		fprintf(stderr, "Fatal error: Couldn't deserialize testappearance.atlas (status %d)\n", context->status);
		exit(EXIT_FAILURE);
	}
	
	BitmapImage * image = ImageIO_readImageResourceFile("testappearance_atlas.png", BITMAP_PIXEL_FORMAT_RGBA_8888, true);
	if (image == NULL) {
		fprintf(stderr, "Fatal error: Couldn't load testappearance_atlas.png\n");
		exit(EXIT_FAILURE);
	}
	texture = Texture_createWithTexels2D(image->pixels, image->width, image->height, 0, 4, TEXEL_COMPONENT_UINT8_NORM, TEXEL_SWIZZLE_DEFAULT, TEXTURE_OPTION_MAGNIFY_NEAREST | TEXTURE_OPTION_MINIFY_NEAREST);
	atlas = TextureAtlasData_createTextureAtlas(atlasData, image->width, image->height);
	BitmapImage_dispose(image);
	TextureAtlasData_dispose(atlasData);
	
	context = JSONDeserializationContext_createWithResourceFile("15pt.bitmapfont");
	if (context->status != SERIALIZATION_ERROR_OK) {
		fprintf(stderr, "Fatal error: Couldn't load 15pt.bitmapfont (status %d)\n", context->status);
		exit(EXIT_FAILURE);
	}
	font = BitmapFont_deserialize(context);
	call_virtual(dispose, context);
	if (font == NULL) {
		fprintf(stderr, "Fatal error: Couldn't deserialize 15pt.bitmapfont (status %d)\n", context->status);
		exit(EXIT_FAILURE);
	}
	BitmapFont_readAtlasEntries(font, atlas);
	font->pointSize *= 2;
	
	shaderConfiguration = ShaderConfiguration2DTexture_create(ShaderCollection_get2DTextureShader());
	call_virtual(setProjectionMatrix, shaderConfiguration, Matrix4x4f_ortho(MATRIX4x4f_IDENTITY, 0.0f, viewWidth / scaleFactor, 0.0f, viewHeight / scaleFactor, -1.0f, 1.0f));
	call_virtual(setTexture, shaderConfiguration, 0, texture, false);
	
	drawingInterface = UIDrawingInterface2DTexture_create();
	drawingInterface->scaleFactor = scaleFactor;
	typeface = UITypeface_BitmapFont_create(font, TEXT_OPTION_PIXEL_SNAPPING);
	uiContext = UIToolkitContext_init(default2DRenderPipelineConfiguration(RENDER_BLEND_ALPHA_PREMULTIPLIED), shaderConfiguration, drawingInterface);
	UIToolkit_setContext(&uiContext);
	appearance = UIAppearance_init(NULL);
	UIToolkit_registerAppearanceParameters(&appearance, atlas, typeface, NULL);
	updateUIBounds();
	UIRadioGroup * radioGroup1 = UIRadioGroup_create();
	UIRadioGroup * radioGroup2 = UIRadioGroup_create();
	
	UIButton * button1 = UIButton_create(STRL("I'm a button"), VECTOR2f(20.0f, 20.0f), VECTOR2f(0.0f, 0.0f), 100.0f, OVERFLOW_RESIZE, button1ActionCallback, NULL, appearance);
	UIButton * button2 = UIButton_create(STRL("Hello"), VECTOR2f(20.0f, 60.0f), VECTOR2f(0.0f, 0.0f), 100.0f, OVERFLOW_RESIZE, button2ActionCallback, NULL, appearance);
	UIButton * button3 = UIButton_create(STRL("Window 1"), VECTOR2f(920.0f, 40.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, window1ButtonActionCallback, NULL, appearance);
	UIButton * button4 = UIButton_create(STRL("Window 2"), VECTOR2f(920.0f, 0.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, window2ButtonActionCallback, NULL, appearance);
	UIButton * button5 = UIButton_create(STRL("Dialog 1"), VECTOR2f(1120.0f, 40.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, dialog1ButtonActionCallback, NULL, appearance);
	UIButton * button6 = UIButton_create(STRL("Dialog 2"), VECTOR2f(1120.0f, 0.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, dialog2ButtonActionCallback, NULL, appearance);
	UIButton * button7 = UIButton_create(STRL("In container 2"), VECTOR2f(0.0f, 0.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, NULL, NULL, appearance);
	UIButton * button8 = UIButton_create(STRL("Scroll upper left"), VECTOR2f(0.0f, 200.0f), VECTOR2f(0.0f, 1.0f), 0.0f, OVERFLOW_RESIZE, scrollContainerButtonCallback, NULL, appearance);
	UIButton * button9 = UIButton_create(STRL("Scroll lower right"), VECTOR2f(300.0f, 0.0f), VECTOR2f(1.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, scrollContainerButtonCallback, NULL, appearance);
	UIButton * button10 = UIButton_create(STRL("Pop-up"), VECTOR2f(1040.0f, 310.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, popUpViewButtonCallback, NULL, appearance);
	UIButton * button11 = UIButton_create(STRL("Inside pop-up"), VECTOR2f(0.0f, 0.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, insidePopUpViewButtonCallback, NULL, appearance);
	button2->enabled = false;
	UIAppearance label1Appearance = UIAppearance_init(&appearance);
	setAppearanceColor4f(&label1Appearance, UILabel_textColor, COLOR4f(0.0f, 0.5f, 0.5f, 1.0f));
	UILabel * label1 = UILabel_create(STRL("I'm a label"), VECTOR2f(30.0f, 120.0f), VECTOR2f_ZERO, VECTOR2f(0.0f, 0.0f), ALIGN_LEFT, 0, OVERFLOW_RESIZE, OVERFLOW_RESIZE, label1Appearance);
	UILabel * label2 = UILabel_create(STRL("Label with text\naligned to the left"), VECTOR2f(370.0f, 370.0f), VECTOR2f_ZERO, VECTOR2f(0.5f, 1.0f), ALIGN_LEFT, WRAP_NEWLINE, OVERFLOW_RESIZE, OVERFLOW_RESIZE, appearance);
	UILabel * label3 = UILabel_create(STRL("Label with text\naligned in the center"), VECTOR2f(600.0f, 370.0f), VECTOR2f_ZERO, VECTOR2f(0.5f, 1.0f), ALIGN_CENTER, WRAP_NEWLINE, OVERFLOW_RESIZE, OVERFLOW_RESIZE, appearance);
	call_virtual(setTooltipString, label3, STRL("Hello I am a very long tooltip designed to be long enough to cause the text inside me to word wrap, testing UIToolkit_tooltipWidthMax"));
	UILabel * label4 = UILabel_create(STRL("Label with text\naligned to the right"), VECTOR2f(830.0f, 370.0f), VECTOR2f_ZERO, VECTOR2f(0.5f, 1.0f), ALIGN_RIGHT, WRAP_NEWLINE, OVERFLOW_RESIZE, OVERFLOW_RESIZE, appearance);
	checkbox = UICheckbox_create(STRL("Checkbox"), VECTOR2f(20.0f, 160.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, false, checkboxActionCallback, NULL, appearance);
	UIButton * mixButton = UIButton_create(STRL("Mix"), VECTOR2f(160.0f, 155.0f), VECTOR2f(0.0f, 0.0f), 0.0f, OVERFLOW_RESIZE, mixButtonCallback, NULL, appearance);
	UIRadioButton * group1Radio1 = UIRadioButton_create(STRL("Group 1 radio 1"), VECTOR2f(20.0f, 200.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, true, radioGroup1, radioActionCallback, NULL, appearance);
	UIRadioButton * group1Radio2 = UIRadioButton_create(STRL("Group 1 radio 2"), VECTOR2f(20.0f, 230.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, false, radioGroup1, radioActionCallback, NULL, appearance);
	UIRadioButton * group1Radio3 = UIRadioButton_create(STRL("Group 1 radio 3"), VECTOR2f(20.0f, 260.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, false, radioGroup1, radioActionCallback, NULL, appearance);
	UIRadioButton * group2Radio1 = UIRadioButton_create(STRL("Group 2 radio 1"), VECTOR2f(20.0f, 300.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, false, radioGroup2, radioActionCallback, NULL, appearance);
	UIRadioButton * group2Radio2 = UIRadioButton_create(STRL("Group 2 radio 2"), VECTOR2f(20.0f, 330.0f), VECTOR2f(0.0f, 0.0f), 50.0f, OVERFLOW_RESIZE, false, radioGroup2, radioActionCallback, NULL, appearance);
	UIGraphicalButton * graphicalButton = UIGraphicalButton_create(getAppearanceAtlasEntry(appearance, UIRadioButton_radioUp), getAppearanceAtlasEntry(appearance, UIRadioButton_radioDown), getAppearanceAtlasEntry(appearance, UIRadioButton_radioRollover), VECTOR2f(130.0f, 70.0f), VECTOR2f(0.0f, 0.0f), button3ActionCallback, NULL, appearance);
	call_virtual(setTooltipString, graphicalButton, STRL("Test tooltip"));
	UIEditText * editText1 = UIEditText_create(STRL("Edit text"), VECTOR2f(30.0f, 370.0f), VECTOR2f(200.0f, 0.0f), VECTOR2f(0.0f, 0.0f), ALIGN_LEFT, 0, OVERFLOW_TRUNCATE, OVERFLOW_RESIZE, singleLineEditTextNewlineCallback, singleLineEditTextChangeCallback, singleLineEditTextChangeCompleteCallback, singleLineEditTextChangeCanceledCallback, NULL, appearance);
	editText1->selectAllOnFocus = true;
	editText1->rightClickAction = UIEditText_action_ignore;
	editText1->underlayText = STRL("Underlay");
	UIEditText * editText2 = UIEditText_create(STRL("Multiline edit text\nLine 2\nLine 3 Line 3\nLine 4"), VECTOR2f(30.0f, 420.0f), VECTOR2f(360.0f, 184.0f), VECTOR2f(0.0f, 0.0f), ALIGN_LEFT, WRAP_DEFAULT, OVERFLOW_TRUNCATE, OVERFLOW_TRUNCATE, NULL, NULL, NULL, NULL, NULL, appearance);
	editText2->rightClickAction = UIEditText_action_focus;
	UIEditText * editText3 = UIEditText_create(STRL("Numbers only in here\nLine 2\nLine 3 Line 3\nLine 4"), VECTOR2f(420.0f, 420.0f), VECTOR2f(360.0f, 184.0f), VECTOR2f(0.0f, 0.0f), ALIGN_CENTER, WRAP_DEFAULT, OVERFLOW_TRUNCATE, OVERFLOW_TRUNCATE, NULL, NULL, NULL, NULL, NULL, appearance);
	call_virtual(setWhitelist, editText3, STRL("1234567890-+."));
	editText3->rightClickAction = UIEditText_action_selectAll;
	UIEditText * editText4 = UIEditText_create(STRL("Multiline edit text\nLine 2\nLine 3 Line 3\nLine 4"), VECTOR2f(810.0f, 420.0f), VECTOR2f(360.0f, 184.0f), VECTOR2f(0.0f, 0.0f), ALIGN_RIGHT, WRAP_DEFAULT, OVERFLOW_TRUNCATE, OVERFLOW_TRUNCATE, NULL, NULL, NULL, NULL, NULL, appearance);
	editText4->rightClickAction = UIEditText_action_clear;
	UISlider * slider1 = UISlider_create(0, 10, 5, VECTOR2f(630.0f, 0.0f), VECTOR2f(0.0f, 0.0f), SLIDER_OPTION_HORIZONTAL | SLIDER_OPTION_SNAP_TO_INTEGER | SLIDER_OPTION_RESET_ON_CONTROL_CLICK, 200, sliderChangeCallback, sliderChangeCompleteCallback, NULL, appearance);
	UISlider * slider2 = UISlider_create(-5, 5, 0, VECTOR2f(630.0f, 50.0f), VECTOR2f(0.0f, 0.0f), SLIDER_OPTION_VERTICAL | SLIDER_OPTION_SNAP_TO_INTEGER | SLIDER_OPTION_ALLOW_UNCLAMPED_DRAG | SLIDER_OPTION_ALLOW_PRECISE_DRAG, 120, sliderChangeCallback, sliderChangeCompleteCallback, NULL, appearance);
	UISlider * slider3 = UISlider_create(-5, 5, 0, VECTOR2f(660.0f, 50.0f), VECTOR2f(0.0f, 0.0f), SLIDER_OPTION_VERTICAL | SLIDER_OPTION_ALLOW_PRECISE_DRAG, 120, sliderChangeCallback, sliderChangeCompleteCallback, NULL, appearance);
	UIMenuItem popUpItems1[] = {
		MENU_ITEM(STRL("Pop-up menu test"), 0, KEY_SHORTCUT(KEY_CODE_A, 0)),
		MENU_ITEM(STRL("Menu item 2"), 1, KEY_SHORTCUT(KEY_CODE_B, MODIFIER_ALT_BIT)),
		MENU_ITEM(STRL("Menu item 3"), 2, KEY_SHORTCUT(KEY_CODE_C, MODIFIER_SHIFT_BIT)),
		MENU_ITEM(STRL("Menu item 4"), 3, MENU_SHORTCUT(KEY_CODE_D, MODIFIER_SHIFT_BIT)),
		MENU_ITEM(STRL("Item 5"), 4, MENU_NO_SHORTCUT),
		{STRL("Checked Menu Item"), 5, true, true, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL},
		{STRL("Disabled Menu Item"), 6, false, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL},
		{STRL("Icon Menu Item"), 7, true, false, getAppearanceAtlasEntry(appearance, UIWindowView_windowCloseUp), MENU_NO_SHORTCUT, 0, NULL},
		MENU_ITEM(STRL("Item 6 with identifier -1"), -1, MENU_NO_SHORTCUT)
	};
	struct UITextListView_item popUpItems2[] = {
		{STRL("Test menu 2"), 1},
		{STRL("Item 2"), 2},
		{STRL("Item 3"), 3},
		{STRL("Item 4"), 4},
		{STRL("Item 5"), 5},
		{STRL("Item 6"), 6},
		{STRL("Item 7"), 7},
		{STRL("Item 8"), 8},
		{STRL("Item 9"), 9},
		{STRL("Item 10"), 10},
		{STRL("Item 11"), 11},
		{STRL("Item 12"), 12},
		{STRL("Item 13"), 13},
		{STRL("Item 14"), 14},
		{STRL("Item 15"), 15},
		{STRL("Item 16"), 16},
		{STRL("Item 17"), 17},
		{STRL("Item 18"), 18},
		{STRL("Item 19"), 19},
		{STRL("Item 20"), 20},
		{STRL("Item 21"), 21},
		{STRL("Item 22"), 22},
		{STRL("Item 23"), 23},
		{STRL("Item 24"), 24},
		{STRL("Item 25"), 25}
	};
	UIPopUpMenu * popUpMenu1 = UIPopUpMenu_createWithMenuItems(sizeof_count(popUpItems1), popUpItems1, VECTOR2f(700.0f, 100.0f), VECTOR2f_ZERO, 0.0f, OVERFLOW_RESIZE, popUpMenuCallback, NULL, appearance);
	UIPopUpMenu * popUpMenu2 = UIPopUpMenu_create(sizeof_count(popUpItems2), popUpItems2, VECTOR2f(700.0f, 50.0f), VECTOR2f_ZERO, 0.0f, OVERFLOW_RESIZE, popUpMenuCallback, NULL, appearance);
	struct UITextListView_item listViewItems[] = {
		{STRL("Item 1"), 0},
		{STRL("Item 2"), 1},
		{STRL("Item 3"), 2},
		{STRL("Item 4"), 3},
		{STRL("Item 5"), 4},
		{STRL("Item 6"), 5},
		{STRL("Item 7"), 6},
		{STRL("Item 8"), 7}
	};
	UITextListView * listView1 = UITextListView_create(sizeof_count(listViewItems), listViewItems, VECTOR2f(700.0f, 150.0f), VECTOR2f_ZERO, 150.0f, 5, SELECT_MODE_SINGLE, listViewCallback, NULL, NULL, NULL, appearance);
	UITextListView * listView2 = UITextListView_create(sizeof_count(listViewItems), listViewItems, VECTOR2f(870.0f, 150.0f), VECTOR2f_ZERO, 150.0f, 5, SELECT_MODE_MULTIPLE, listViewCallback, listViewSelectionChangedCallback, listViewDeleteLineCallback, NULL, appearance);
	listView2->drawAlternatingColors = true;
	listView2->allowDrag = true;
	
	UIStepper * stepper1 = UIStepper_create(VECTOR2f(850.0f, 0.0f), VECTOR2f(0.0f, 0.0f), STEPPER_VERTICAL, true, false, stepper1Callback, stepperCompleteCallback, NULL, appearance);
	UIStepper * stepper2 = UIStepper_create(VECTOR2f(880.0f, 0.0f), VECTOR2f(0.0f, 0.0f), STEPPER_HORIZONTAL, false, false, stepper2Callback, stepperCompleteCallback, stepper1, appearance);
	
	UIContinuousSlider * continuousSlider1 = UIContinuousSlider_create(VECTOR2f(0.0f, 0.0f), VECTOR2f(630, 180), VECTOR2f(0.0f, 0.0f), VECTOR2f(60, 20), UIContinuousSlider_X, continuousSliderChangeCallback, continuousSliderChangeCompleteCallback, NULL, appearance);
	UIContinuousSlider * continuousSlider2 = UIContinuousSlider_create(VECTOR2f(0.0f, 0.0f), VECTOR2f(630, 210), VECTOR2f(0.0f, 0.0f), VECTOR2f(20, 60), UIContinuousSlider_Y, continuousSliderChangeCallback, continuousSliderChangeCompleteCallback, NULL, appearance);
	UIContinuousSlider * continuousSlider3 = UIContinuousSlider_create(VECTOR2f(0.0f, 0.0f), VECTOR2f(660, 210), VECTOR2f(0.0f, 0.0f), VECTOR2f(30, 30), UIContinuousSlider_XY, continuousSliderChangeCallback, continuousSliderChangeCompleteCallback, NULL, appearance);
	continuousSlider2->gridSpacing = 20.0f;
	continuousSlider3->gridSpacing = 24.0f;
	
	UIMenuItem submenu1Items[] = {
		{STRL("Subitem 1"), 3, true, true, UIAtlasEntry_none, MENU_SHORTCUT(KEY_CODE_EQUAL, 0), 0, NULL},
		{STRL("Subitem 2"), 4, false, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL}
	};
	UIMenuItem submenu2Items[] = {
		{STRL("Second submenu 1"), 8, true, true, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL},
		{STRL("Second submenu 2"), 9, false, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL}
	};
	UIMenuItem menuItems1[] = {
		{STRL("Item 1"), 0, true, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL},
		{STRL("Item 2"), 1, false, true, UIAtlasEntry_none, MENU_SHORTCUT(KEY_CODE_2, 0), 0, NULL},
		{STR_NULL, 0, false, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, 0, NULL},
		{STRL("Submenu"), 2, true, false, UIAtlasEntry_none, MENU_NO_SHORTCUT, sizeof_count(submenu1Items), submenu1Items},
		{STRL("Disabled submenu"), 5, false, true, UIAtlasEntry_none, MENU_NO_SHORTCUT, sizeof_count(submenu2Items), submenu2Items}
	};
	UIMenuItem menuItems2[] = {
		{STRL("Item 3"), 6, true, false, UIAtlasEntry_none, MENU_SHORTCUT(KEY_CODE_3, 0), 0, NULL},
		{STRL("Item 4"), 7, true, true, UIAtlasEntry_none, KEY_SHORTCUT_MULTIPLE(KEY_CODE_3, MODIFIER_PLATFORM_MENU_COMMAND_BIT | MODIFIER_SHIFT_BIT, KEY_CODE_3, MODIFIER_PLATFORM_MENU_COMMAND_BIT | MODIFIER_ALT_BIT, NULL), 0, NULL}
	};
	UIMenuItem menuItems3[] = {
		MENU_ITEM(STRL("Item 1"), 101, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 2"), 102, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 3"), 103, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 4"), 104, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 5"), 105, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 6"), 106, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 7"), 107, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 8"), 108, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 9"), 109, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 10"), 110, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 11"), 111, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 12"), 112, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 13"), 113, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 14"), 114, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 15"), 115, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 16"), 116, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 17"), 117, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 18"), 118, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 19"), 119, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 20"), 120, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 21"), 121, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 22"), 122, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 23"), 123, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 24"), 124, MENU_NO_SHORTCUT),
		MENU_ITEM(STRL("Item 25"), 125, MENU_NO_SHORTCUT),
	};
	UIMenu menus[] = {
		{STRL("Menu 1"), 0, sizeof_count(menuItems1), menuItems1},
		{STRL("Menu 2"), 1, sizeof_count(menuItems2), menuItems2},
		{STRL("Menu 3"), 2, sizeof_count(menuItems3), menuItems3}
	};
	menuBar = UIMenuBar_create(sizeof_count(menus), menus, VECTOR2f(0, viewHeight), VECTOR2f(0.0f, 1.0f), viewWidth, menuItemActionCallback, validateMenuItemCallback, contextMenuCallback, NULL, appearance);
	UIMenuBar_setItemAlternateDisplayString(menuBar, 1, 6, STRL("Item 3 shift"), MODIFIER_SHIFT_BIT);
	UIMenuBar_setItemAlternateDisplayString(menuBar, 1, 6, STRL("Item 3 alt"), MODIFIER_ALT_BIT);
	UIMenuBar_setItemAlternateDisplayString(menuBar, 1, 6, STRL("Item 3 shift+alt"), MODIFIER_SHIFT_BIT | MODIFIER_ALT_BIT);
	
	windowRoot = UIWindowRoot_create();
	UIAppearance window1Appearance = UIAppearance_init(&appearance);
	setAppearanceColor4f(&window1Appearance, UIWindowView_backgroundColor, COLOR4f(1.0f, 1.0f, 0.5f, 1.0f));
	setAppearanceColor4f(&window1Appearance, UIWindowView_titleColorBottom, COLOR4f(0.75f, 0.75f, 0.5f, 1.0f));
	setAppearanceColor4f(&window1Appearance, UIWindowView_titleColorTop, COLOR4f(0.875f, 0.875f, 0.75f, 1.0f));
	UIAppearance window2Appearance = UIAppearance_init(&appearance);
	setAppearanceColor4f(&window2Appearance, UIWindowView_backgroundColor, COLOR4f(0.5f, 1.0f, 1.0f, 1.0f));
	setAppearanceColor4f(&window2Appearance, UIWindowView_titleColorBottom, COLOR4f(0.5f, 0.75f, 0.75f, 1.0f));
	setAppearanceColor4f(&window2Appearance, UIWindowView_titleColorTop, COLOR4f(0.75f, 0.875f, 0.875f, 1.0f));
	UIWindowRoot_addWindow(windowRoot, window1 = UIWindowView_create(VECTOR2f(200, 400), VECTOR2f(0.0f, 0.0f), VECTOR2f(0.0f, 0.0f), VECTOR2f(200, 200), STRL("Window 1"), closeWindowCallback, NULL, NULL, windowRoot, window1Appearance), true);
	UIWindowRoot_addWindow(windowRoot, window2 = UIWindowView_create(VECTOR2f(300, 450), VECTOR2f(0.0f, 0.0f), VECTOR2f(0.0f, 0.0f), VECTOR2f(150, 180), STRL("Window 2"), closeWindowCallback, resizeWindowCallback, NULL, windowRoot, window2Appearance), true);
	
	UIContainer * rootContainer = UIContainer_create(VECTOR2f(0, 0), VECTOR2f_ZERO, VECTOR2f_ZERO, VECTOR2f_ZERO, false, appearance);
	UIContainer * container = UIContainer_create(VECTOR2f(20, 20), VECTOR2f_ZERO, VECTOR2f_ZERO, VECTOR2f_ZERO, false, appearance);
	UIContainer * container2 = UIContainer_create(VECTOR2f(1000.0f, 90.0f), VECTOR2f_ZERO, VECTOR2f_ZERO, VECTOR2f_ZERO, false, appearance);
	scrollContainer = UIScrollContainer_create(VECTOR2f(1040.0f, 150.0f), VECTOR2f_ZERO, VECTOR2f(150.0f, 150.0f), RECT4f(0.0f, 300.0f, 0.0f, 200.0f), appearance);
	popUpView = UIPopUpView_create(RECT4f_EMPTY, UISidePreference_right, VECTOR2f_ZERO, VECTOR2f_ZERO, false, closePopUpCallback, NULL, appearance);
	popUpView->visible = false;
	UIContainer_addElement(rootContainer, container, true);
	UIContainer_addElement(rootContainer, windowRoot, true);
	UIContainer_addElement(rootContainer, UITooltipRoot_create(appearance), true);
	UIContainer_addElement(container, button1, true);
	UIContainer_addElement(container, button2, true);
	UIContainer_addElement(container, button3, true);
	UIContainer_addElement(container, button4, true);
	UIContainer_addElement(container, button5, true);
	UIContainer_addElement(container, button6, true);
	UIContainer_addElement(container, container2, true);
	UIContainer_addElement(container2, button7, true);
	call_virtual(addElement, scrollContainer, button8, true);
	call_virtual(addElement, scrollContainer, button9, true);
	UIContainer_addElement(container, button10, true);
	call_virtual(addElement, popUpView, button11, true);
	call_virtual(addElement, container, popUpView, true);
	UIContainer_addElement(container, scrollContainer, true);
	UIContainer_addElement(container, label1, true);
	UIContainer_addElement(container, label2, true);
	UIContainer_addElement(container, label3, true);
	UIContainer_addElement(container, label4, true);
	UIContainer_addElement(container, checkbox, true);
	UIContainer_addElement(container, mixButton, true);
	UIContainer_addElement(container, group1Radio1, true);
	UIContainer_addElement(container, group1Radio2, true);
	UIContainer_addElement(container, group1Radio3, true);
	UIContainer_addElement(container, group2Radio1, true);
	UIContainer_addElement(container, group2Radio2, true);
	UIContainer_addElement(container, graphicalButton, true);
	UIContainer_addElement(container, editText1, true);
	UIContainer_addElement(container, editText2, true);
	UIContainer_addElement(container, editText3, true);
	UIContainer_addElement(container, editText4, true);
	UIContainer_addElement(container, slider1, true);
	UIContainer_addElement(container, slider2, true);
	UIContainer_addElement(container, slider3, true);
	UIContainer_addElement(container, continuousSlider1, true);
	UIContainer_addElement(container, continuousSlider2, true);
	UIContainer_addElement(container, continuousSlider3, true);
	UIContainer_addElement(container, popUpMenu1, true);
	UIContainer_addElement(container, popUpMenu2, true);
	UIContainer_addElement(container, listView1, true);
	UIContainer_addElement(container, listView2, true);
	UIContainer_addElement(container, stepper1, true);
	UIContainer_addElement(container, stepper2, true);
	UIContainer_addElement(rootContainer, menuBar, true);
	call_virtual(autosize, popUpView);
	rootElement = (UIElement *) rootContainer;
	
	UIElement_connect(button1, UI_UP, button2, true);
	UIElement_connect(button1, UI_RIGHT, slider1, true);
	UIElement_connect(button2, UI_RIGHT, graphicalButton, true);
	UIElement_connect(graphicalButton, UI_RIGHT, slider2, true);
	UIElement_connect(slider1, UI_UP, slider2, true);
	UIElement_connect(slider2, UI_RIGHT, slider3, true);
	UIElement_connect(slider3, UI_DOWN, slider1, false);
	UIElement_connect(button2, UI_UP, label1, true);
	UIElement_connect(label1, UI_UP, checkbox, true);
	UIElement_connect(graphicalButton, UI_DOWN, button1, false);
	UIElement_connect(graphicalButton, UI_UP, label1, false);
	UIElement_connect(checkbox, UI_UP, group1Radio1, true);
	UIElement_connect(group1Radio1, UI_UP, group1Radio2, true);
	UIElement_connect(group1Radio2, UI_UP, group1Radio3, true);
	UIElement_connect(group1Radio3, UI_UP, group2Radio1, true);
	UIElement_connect(group2Radio1, UI_UP, group2Radio2, true);
	UIElement_connect(group2Radio2, UI_UP, editText1, true);
	UIElement_connect(editText1, UI_UP, editText2, true);
	UIElement_connect(editText2, UI_UP, button1, true);
	UIElement_connect(editText2, UI_RIGHT, editText3, true);
	UIElement_connect(editText3, UI_RIGHT, editText4, true);
	UIElement_connect(editText3, UI_UP, button1, false);
	UIElement_connect(editText4, UI_UP, button1, false);
	
	UIElement_connect(button1, UI_NEXT, button2, true);
	UIElement_connect(button2, UI_NEXT, label1, true);
	UIElement_connect(label1, UI_NEXT, checkbox, true);
	UIElement_connect(checkbox, UI_NEXT, group1Radio1, true);
	UIElement_connect(group1Radio1, UI_NEXT, group1Radio2, true);
	UIElement_connect(group1Radio2, UI_NEXT, group1Radio3, true);
	UIElement_connect(group1Radio3, UI_NEXT, group2Radio1, true);
	UIElement_connect(group2Radio1, UI_NEXT, group2Radio2, true);
	UIElement_connect(group2Radio2, UI_NEXT, graphicalButton, true);
	UIElement_connect(graphicalButton, UI_NEXT, editText1, true);
	UIElement_connect(editText1, UI_NEXT, editText2, true);
	UIElement_connect(editText2, UI_NEXT, editText3, true);
	UIElement_connect(editText3, UI_NEXT, editText4, true);
	UIElement_connect(editText4, UI_NEXT, slider1, true);
	UIElement_connect(slider1, UI_NEXT, slider2, true);
	UIElement_connect(slider2, UI_NEXT, slider3, true);
	UIElement_connect(slider3, UI_NEXT, popUpMenu1, true);
	UIElement_connect(popUpMenu1, UI_NEXT, popUpMenu2, true);
	UIElement_connect(popUpMenu2, UI_NEXT, listView1, true);
	UIElement_connect(listView1, UI_NEXT, listView2, true);
	UIElement_connect(listView2, UI_NEXT, stepper1, true);
	UIElement_connect(stepper1, UI_NEXT, stepper2, true);
	UIElement_connect(stepper2, UI_NEXT, button3, true);
	UIElement_connect(button3, UI_NEXT, button4, true);
	UIElement_connect(button4, UI_NEXT, button5, true);
	UIElement_connect(button5, UI_NEXT, button6, true);
	UIElement_connect(button6, UI_NEXT, button1, true);
	
	UIElement_connect(rootElement, UI_NEXT, button1, false);
	UIElement_connect(rootElement, UI_PREVIOUS, button6, false);
	UIElement_connect(rootElement, UI_UP, button1, false);
	UIElement_connect(rootElement, UI_DOWN, editText2, false);
	UIElement_connect(rootElement, UI_RIGHT, editText2, false);
	UIElement_connect(rootElement, UI_LEFT, graphicalButton, false);
	
	//call_virtual(setFocusedElement, rootElement, button1, NULL, UI_NONE);
	
	renderable = Renderable_createWithCallback(PRIMITIVE_TRIANGLES, &uiContext.defaultRenderPipelineConfiguration, shaderConfiguration, writeUIVertices, NULL, NULL);
	
	UIToolkit_cursorChangeFunc(cursorUpdatedCallback);
	
	Shell_mainLoop();
}
