//	Draw4DContentView.swift
//
//	© 2025 by Jeff Weeks
//	See TermsOfUse.txt

import SwiftUI
import simd


enum PanelType {
	case noPanel
	case optionsPanel
	case rotationPanel
	case exportPanel
	case helpMenuPanel
	case helpHowToDrawPanel
	case helpIdeasPanel
	case contactPanel
	case translatorsPanel
}


struct Draw4DContentView: View {

	@Environment(\.undoManager) var defaultUndoManager

	@State var document: Draw4DDocument
	let fileURL: URL?

	@State var renderer: Draw4DRenderer? = Draw4DRenderer()

	@State var itsActivePanel: PanelType = .noPanel
	
	@AppStorage("snap-to-grid") var itsSnapToGridIsEnabled: Bool = true
	@AppStorage("show selected point's coordinates") var itsShowCoordinates: Bool = false

	//	Let's give our control panels a background color which,
	//	in dark mode, isn't quite black, to provide some contrast
	//	against the main view's pure black background.
	//
	//		Note: itsModifiedBackgroundColor will change on the fly,
	//		if the player switches between light mode and dark mode.
	//
	@State var itsModifiedBackgroundColor = Color("Modified Background Color")
	
	@GestureState var itsDragState: Draw4DDragState = Draw4DDragState()
	@GestureState var itsPreviousAngle: Double = 0.0	//	in radians


	var body: some View {
		
		//	Our Draw4DDocument is a ReferenceFileDocument
		//	which, when we close the document, will save its contents
		//	iff there are un-doable changes sitting on the UndoManager
		//	that it passes to us as an @Environment variable.
		//	So it's essential that our document use that default UndoManager
		//	and not one that we allocate ourselves.
		if let theDefaultUndoManager = defaultUndoManager {
			document.itsUndoManager = theDefaultUndoManager
		} else {
#if os(iOS)
			//	When running on iOS, SwiftUI calls this body() function
			//	a total of four times for each drawing that I open.
			//	The defaultUndoManager is non-nil in all four calls.
			assertionFailure("The defaultUndoManager is missing")
#endif
#if os(macOS)
			//	When running on macOS, SwiftUI calls this body() function
			//	three times for each drawing that I open. On the first call
			//	the defaultUndoManager is still nil, but then on the second
			//	and third calls it's non-nil, so everything works fine.
#endif
		}

#if os(iOS)
		//	On iOS, it looks good to underlap the nav bar.
		let theIgnoredSafeAreaEdges: Edge.Set = .all
#endif
#if os(macOS)
		//	On macOS, we don't want to underlap the window's title bar.
		let theIgnoredSafeAreaEdges: Edge.Set = .bottom
#endif

		let theTranslatorThanks = [
			GeometryGamesTranslatorThanks(pre: "grazie a", name: "Daniela, Isabella Eva e Davide Bigatti", post: nil, lang: "it"),
			GeometryGamesTranslatorThanks(pre: "obrigado a", name: "Nuno Fernandes", post: nil, lang: "pt")
		]

		if gMakeScreenshots {

			setOrientationForScreenshot(
				document: document,
				fileURL: fileURL)
		}
		
		//	This top-level ZStack lets an optional panel overlay the main view.
		return ZStack(alignment: .bottom) {

			//	Main animation view
			if let theRenderer = renderer {

				GeometryReader() { geometryReaderProxy in

					GeometryGamesViewRep(
						modelData: document,
						renderer: theRenderer
					)
					//
					//	Gesture order matters:
					//		SwiftUI considers each Gesture only after
					//		all preceding gestures have failed.
					//
					.gesture(
						draw4DDragGesture(
							modelData: document,
							viewSize: geometryReaderProxy.size,
							snapToGridIsEnabled: itsSnapToGridIsEnabled,
							dragState: $itsDragState))
					.gesture(
						draw4DRotateGesture(
							modelData: document,
							previousAngle: $itsPreviousAngle))
					.gesture(
						draw4DTapGesture(
							modelData: document,
							viewSize: geometryReaderProxy.size,
							activePanel: $itsActivePanel))
				}
				.ignoresSafeArea(edges: theIgnoredSafeAreaEdges)
			}
			
			//	Controls
			VStack() {

				ZStack() {

					VStack(alignment: .center) {

						//	Controls along the top edge
						//
						//	Use a ZStack so that the Undo/Redo buttons may be centered.
						//
						ZStack(alignment: .center) {

							if !document.itsContentIsLocked {
								HStack() {
									UndoButton(document: document)
									RedoButton(document: document)
								}
							}
							
							LockButton(
								document: document,
								sourceDocumentURL: fileURL)
							.frame(maxWidth: .infinity, alignment: .trailing)
							.onChange(of: document.itsContentIsLocked) {
							
								itsActivePanel = .noPanel
								
								//	We don't want to put Lock/Unlock operations
								//	onto to Undo/Redo stacks. Among other reasons,
								//	if the user undid as far as a locked state,
								//	the Undo/Redo buttons would disappear.
								//	But if the user locks or unlocks a drawing
								//	and then closes it, we want to encourage SwiftUI
								//	to re-save the drawing. So let's put a null
								//	operation onto the Undo stack. This doesn't
								//	guarantee that the new lock/unlock status
								//	will get saved (for example, the user could
								//	use Undo to remove the null operation), but
								//	at least in the typical case this will do
								//	the trick. Another disadvantage to be aware of
								//	is that putting this null operation onto
								//	the Undo stack will have the side effect
								//	of clearing the Redo stack, but at least
								//	all the Undo operations will still be available.
								document.changeNothing()
							}
						}

						if let theSelectedPoint = document.itsSelectedPoint,
						   itsShowCoordinates
						{
							CoordinatesView(selectedPoint: theSelectedPoint)
						}
					}
					.frame(maxHeight: .infinity, alignment: .top)

					Group() {
					
						//	Note:  Some of the panels get leading-aligned, others trailing-aligned.
						switch itsActivePanel {
						
						case .noPanel:
							Spacer()
							
						case .optionsPanel:
							OptionsView(
								document: document,
								snapToGridIsEnabled: $itsSnapToGridIsEnabled,
								showCoordinates: $itsShowCoordinates)
							.frame(maxWidth: .infinity, alignment: .leading)
							
						case .rotationPanel:
							RotationView(document: document)
							.frame(maxWidth: .infinity, alignment: .leading)
							
						case .exportPanel:
							let theDrawingName = fileURL?.deletingPathExtension().lastPathComponent ?? "Untitled"
							if let theRenderer = renderer {
								GeometryGamesExportView(
									modelData: document,
									exportRenderer: theRenderer,
									caption: theDrawingName,
									modifiedBackgroundColor: itsModifiedBackgroundColor)
								.frame(maxWidth: .infinity, alignment: .trailing)
							} else {
								Text("Renderer not available")
							}
						
						case .helpMenuPanel:
							HelpMenuView(activePanel: $itsActivePanel)
							.frame(maxWidth: .infinity, alignment: .trailing)
							
						case .helpHowToDrawPanel:
							Draw4DHelpHowView()
							.frame(maxWidth: .infinity, alignment: .trailing)
							
						case .helpIdeasPanel:
							Draw4DHelpIdeasView()
							.frame(maxWidth: .infinity, alignment: .trailing)
							
						case .contactPanel:
							GeometryGamesContactView(
								modifiedBackgroundColor: itsModifiedBackgroundColor)
							.frame(maxWidth: .infinity, alignment: .trailing)
							
						case .translatorsPanel:
							GeometryGamesTranslatorsView(
								theTranslatorThanks,
								modifiedBackgroundColor: itsModifiedBackgroundColor)
							.frame(maxWidth: .infinity, alignment: .trailing)
						}
					}
					.padding(EdgeInsets(
								top: geometryGamesPanelMargin,
								leading: geometryGamesPanelMargin,
								bottom: 0.0,	//	OK to sit close to buttons
								trailing: geometryGamesPanelMargin))
					.frame(maxHeight: .infinity, alignment: .bottom)
				}
				
				//	Controls along the bottom edge
				HStack(alignment: .bottom) {

					//	The buttons already have their own tappable padding,
					//	so the AdaptiveStack doesn't need to provide any extra spacing.
					AdaptiveStack(spacing: 0) {
						OptionsButton(activePanel: $itsActivePanel)
						RotationButton(activePanel: $itsActivePanel)
							.disabled(!document.itCanRotateQuarterTurns)
					}

					Spacer()

					TouchModePicker(
						touchMode: $document.itsTouchMode,
						canMovePoint: $document.itCanMovePoint,
						canAddPoint: $document.itCanAddPoint,
						canDeletePoint: $document.itCanDeletePoint,
						canAddEdge: $document.itCanAddEdge,
						canDeleteEdge: $document.itCanDeleteEdge
					)
					
					Spacer()

					//	The buttons already have their own tappable padding,
					//	so the AdaptiveStack doesn't need to provide any extra spacing.
					AdaptiveStack(spacing: 0) {
						ExportButton(activePanel: $itsActivePanel)
						HelpMenuButton(activePanel: $itsActivePanel)
					}
				}
			}
		}
		.modifier(buttonStyleOnMacOS())
		.onAppear() {

			document.changeCount += 1
			
			if gMakeScreenshots {
				itsActivePanel = setPanelForScreenshot(fileURL: fileURL)
			}
		}
	}
}


struct CoordinatesView: View {

	let selectedPoint: Draw4DPoint

	@State var modifiedBackgroundColor = Color("Modified Background Color")
	
	var body: some View {

		let p = selectedPoint.itsPosition.vector

		Text( "( \(fn(p.x)), \(fn(p.y)), \(fn(p.z)), \(fn(p.w)) )" )
		.monospacedDigit()
		.padding()
		.background(modifiedBackgroundColor)
		.cornerRadius(8.0)
	}
	
	func fn(	//	fn = formatted number
		_ c: Double
	) -> String {
		
		let theSign: String
		if c > 0.0 {
			theSign = "+"
		} else if c < 0.0 {
			theSign = "−" // an actual Unicode minus sign, not a hyphen or dash!
		} else {
			theSign = " " // a figure-width space, same width as "−" and "+"
		}

		let theMagnitude = abs(c)
		
		return theSign + theMagnitude.formatted(.number.precision(.fractionLength(2)))
	}
}


struct UndoButton: View {

	var document: Draw4DDocument
	
	@State var canUndo: Bool = false

	var body: some View {

		Button {
		
			document.itsUndoManager?.undo()
			document.updateCapabilityFlags()

		} label: {
			Image(systemName: "arrowshape.turn.up.backward.circle")
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
		.disabled(!canUndo)
		.onChange(of: document.itsUndoRedoCount, initial: true) {
			canUndo = document.itsUndoManager?.canUndo ?? false
				   || gMakeScreenshots
		}
	}
}

struct RedoButton: View {

	var document: Draw4DDocument

	@State var canRedo: Bool = false

	var body: some View {

		Button {
		
			document.itsUndoManager?.redo()
			document.updateCapabilityFlags()

		} label: {
			Image(systemName: "arrowshape.turn.up.forward.circle")
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
		.disabled(!canRedo)
		.onChange(of: document.itsUndoRedoCount, initial: true) {
			canRedo = document.itsUndoManager?.canRedo ?? false
				   || gMakeScreenshots
		}
	}
}


struct LockButton: View {
	
	var document: Draw4DDocument
	let sourceDocumentURL: URL?

	@State var showLockView: Bool = false

	var body: some View {

		let theFileName = String(sourceDocumentURL?.deletingPathExtension().lastPathComponent ?? "")

		Button() {
			showLockView.toggle()
		} label: {
			Image(systemName: document.itsContentIsLocked ?
					"lock.fill" : "lock.open.fill")
			.font(.title)
			.padding(8.0)
			.modifier(applyForegroundAccentColorOnMacOS())
			.background(geometryGamesTappableClearColor)
			.cornerRadius(geometryGamesCornerRadius)
		}
		.popover(isPresented: $showLockView) {
			LockView(
				document: document,
				fileName: theFileName)
		}
	}
}

struct LockView: View {

	var document: Draw4DDocument
	let fileName: String

	@Environment(\.dismiss) var dismiss

	var body: some View {

		Button(role: document.itsContentIsLocked ? .destructive : nil ) {
						
			document.itsContentIsLocked.toggle()
			document.updateCapabilityFlags()

			dismiss()
			
		} label: {
		
			Label(
				String(
					format: Bundle.main.localizedString(
								forKey: document.itsContentIsLocked ?
											"UnlockFigure" : "LockFigure",
								value: nil,
								table: nil),
					fileName),
				systemImage: document.itsContentIsLocked ?
								"lock.open.fill" : "lock.fill"
			)
			.padding(16.0)
		}
		.presentationCompactAdaptation(.popover)
	}
}


struct OptionsButton: View {

	@Binding var activePanel: PanelType

	var body: some View {

		Button {
			activePanel = activePanel == .optionsPanel ? .noPanel : .optionsPanel
		} label: {
			Image(systemName: "switch.2")	//	or "slider.horizontal.3"
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
	}
}

struct OptionsView: View {

	@Bindable var document: Draw4DDocument
	@Binding var snapToGridIsEnabled: Bool
	@Binding var showCoordinates: Bool

	@State var modifiedBackgroundColor = Color("Modified Background Color")

	var body: some View {

		VStack(alignment: .leading) { // Toggles will align on both sides on iOS

			Toggle(isOn: $document.itsBoxIsEnabled) {
				Text("Box")
			}

			Toggle(isOn: $snapToGridIsEnabled) {
				Text("SnapToGrid")
			}

			Toggle(isOn: $document.itsInertiaIsEnabled) {
				Text("Inertia")
			}
			.onChange(of: document.itsInertiaIsEnabled) {
				document.itsIncrement = nil
			}

			Toggle(isOn: $showCoordinates) {
				Text("Coordinates")
			}
		}
		.fixedSize()
		.padding(geometryGamesPanelPadding)
		.background(modifiedBackgroundColor)
		.cornerRadius(geometryGamesCornerRadius)
	}
}


struct RotationButton: View {

	@Binding var activePanel: PanelType

	var body: some View {

		Button {
			activePanel = activePanel == .rotationPanel ? .noPanel : .rotationPanel
		} label: {
			Image(systemName: "arrow.triangle.2.circlepath.circle")
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
	}
}

struct RotationView: View {

	var document: Draw4DDocument

	@State var modifiedBackgroundColor = Color("Modified Background Color")
	
	let theAnimationDurationSlow = 4.0	//	seconds
	let theAnimationDurationFast = 2.0	//	seconds

	var body: some View {

		VStack(spacing: 16.0) {

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationFast,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(0.0, 0.0, +1.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(0.0, 0.0, -1.0))
				
			} label: { Text("Rotate \("X → Y")") }

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationFast,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(+1.0, 0.0, 0.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(-1.0, 0.0, 0.0))
				
			} label: { Text("Rotate \("Y → Z")") }

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationFast,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(0.0, +1.0, 0.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(0.0, -1.0, 0.0))
				
			} label: { Text("Rotate \("Z → X")") }

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationSlow,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(+1.0, 0.0, 0.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(+1.0, 0.0, 0.0))
				
			} label: { Text("Rotate \("W → X")") }

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationSlow,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(0.0, +1.0, 0.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(0.0, +1.0, 0.0))
				
			} label: { Text("Rotate \("W → Y")") }

			Button {
				document.itsAnimatedRotation = AnimatedRotation(
					itsTotalDuration: theAnimationDurationSlow,
					itsTotalAngle: 0.5 * Double.pi,
					itsStartTime: CFAbsoluteTimeGetCurrent(),
					itsLeftImaginaryUnitVector:  SIMD3<Double>(0.0, 0.0, +1.0),
					itsRightImaginaryUnitVector: SIMD3<Double>(0.0, 0.0, +1.0))
				
			} label: { Text("Rotate \("W → Z")") }
		}
		.fixedSize()
		.padding(geometryGamesPanelPadding)
		.background(modifiedBackgroundColor)
		.cornerRadius(geometryGamesCornerRadius)
		.modifier(applyForegroundAccentColorOnMacOS())
		.disabled(!document.itCanRotateQuarterTurns)
	}
}


struct TouchModePicker: View {

	@Binding var touchMode: TouchMode
	@Binding var canMovePoint: Bool
	@Binding var canAddPoint: Bool
	@Binding var canDeletePoint: Bool
	@Binding var canAddEdge: Bool
	@Binding var canDeleteEdge: Bool

	var body: some View {

		ZStack() {
		
			Rectangle()
			.foregroundStyle(Color(white: 0.75))
			.cornerRadius(8.0)
		
			Picker(
				"Touch Mode",	//	label not shown
				selection: $touchMode
			) {

				//	Note #1
				//	In principle we could use a loop to create the Picker's items
				//
				//		ForEach(TouchMode.allCases, id: \.self) {theTouchMode in
				//			Image(theTouchMode.imageName)
				//				.renderingMode(.template)
				//		}
				//
				//	but that would seem to make it more complicated
				//	to selectively enable/disable the items.
				//	So let's stick with manually listing the items.
				
				//	Note #2
				//	Textual labels like
				//
				//		Text(theTouchMode.nameKey)
				//
				//	look great, but alas there's not enough space for them all,
				//	not even on an iPad.  If some future version of SwiftUI
				//	supports the equivalent of UIKit's setApportionsSegmentWidthsByContent:NO,
				//	we could consider using textual labels in a "regular size class"
				//	and image labels in a "compact size class".

				//	Note #3
				//	The modifier .renderingMode(.template) asks SwiftUI to replace
				//	the image's colors with the accent color, which is exactly what
				//	we want.  (The red and green colors in the raw images would be
				//	a bit gaudy in this version of 4D Draw, and in any case
				//	invite confusion with the interpretation of any red or green edges
				//	in the drawing itself.)

				//	Neutral mode is always enabled
				Image(TouchMode.neutral.imageName)
					.renderingMode(.template)
					.tag(TouchMode.neutral)

				if canMovePoint {
					Image(TouchMode.movePoints.imageName)
						.renderingMode(.template)
						.tag(TouchMode.movePoints)
				}

				if canAddPoint {
					Image(TouchMode.addPoints.imageName)
						.renderingMode(.template)
						.tag(TouchMode.addPoints)
				}

				if canDeletePoint {
					Image(TouchMode.deletePoints.imageName)
						.renderingMode(.template)
						.tag(TouchMode.deletePoints)
				}

				if canAddEdge {
					Image(TouchMode.addEdges.imageName)
						.renderingMode(.template)
						.tag(TouchMode.addEdges)
				}

				if canDeleteEdge {
					Image(TouchMode.deleteEdges.imageName)
						.renderingMode(.template)
						.tag(TouchMode.deleteEdges)
				}
			}
			.colorMultiply(.blue)	//	No other way of setting the foreground or
									//	background color seems to work, without
									//	resorting to UISegmentedControl.appearance()
									//	which of course doesn't compile for macOS.
			.pickerStyle(.segmented)
			.labelsHidden()	//	needed on macOS, but iOS hides the label no matter what
			.fixedSize()
			.padding(4.0)
		}
		.fixedSize()
		.padding(geometryGamesControlPadding)	//	for spacing only, not to expand tappable area
	}
}


struct ExportButton: View {

	@Binding var activePanel: PanelType

	var body: some View {

		Button {
			activePanel = activePanel == .exportPanel ? .noPanel : .exportPanel
		} label: {
			Image(systemName: "square.and.arrow.up")
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
	}
}


struct HelpMenuButton: View {

	@Binding var activePanel: PanelType

	var body: some View {

		Button {
			activePanel = activePanel == .helpMenuPanel ? .noPanel : .helpMenuPanel
		} label: {
			Image(systemName: "questionmark.circle")
			.font(.title)
			.padding(geometryGamesControlPadding)
			.background(geometryGamesTappableClearColor)
			.modifier(applyForegroundAccentColorOnMacOS())
		}
	}
}

struct HelpMenuView: View {

	@Binding var activePanel: PanelType
	
	var body: some View {

		VStack(alignment: .leading, spacing: 8.0) {

			Button() {
				activePanel = .helpHowToDrawPanel
			} label: {
				Label("How to draw", systemImage: "questionmark.circle")
			}
		
			Button() {
				activePanel = .helpIdeasPanel
			} label: {
				Label("Construction ideas", systemImage: "lightbulb")
			}
		
			Button() {
				activePanel = .contactPanel
			} label: {
				GeometryGamesHelpMenuContactItemLabel()
			}
			
			Button() {
				activePanel = .translatorsPanel
			} label: {
				GeometryGamesHelpMenuTranslatorsItemLabel()
			}
		}
		.modifier(helpMenuStyle())
	}
}


func setOrientationForScreenshot(
	document: Draw4DDocument,
	fileURL: URL?
) {

	let theFileName = String(fileURL?.deletingPathExtension().lastPathComponent ?? "")

	let theOrientation: simd_quatd
	switch theFileName {
	
	case "vertex-first hypercube (step 3)":
		theOrientation = simd_quatd(
			real: 0.957772,
			imag: SIMD3<Double>(-0.250343,  0.030159, -0.138172))

	case "vertex-first hypercube (step 1)":
		theOrientation = simd_quatd(
			real: 0.957772,
			imag: SIMD3<Double>(-0.250343,  0.030159, -0.138172))

	case "alternating vertices of hypercube":
		theOrientation = simd_quatd(
			real: 0.952200,
			imag: SIMD3<Double>(-0.223655, -0.203244,  0.044552))

	case "hypertetrahedron":
		theOrientation = simd_quatd(
			real: 0.966959,
			imag: SIMD3<Double>(-0.254932,  0.000000,  0.000000))

	default:
		theOrientation = gQuaternionIdentity

	}

	document.itsOrientation = theOrientation
}

func setPanelForScreenshot(
	fileURL: URL?
) -> PanelType {

	let theFileName = String(fileURL?.deletingPathExtension().lastPathComponent ?? "")

	let thePanelType: PanelType
	switch theFileName {
	
	case "alternating vertices of hypercube":
		thePanelType = .helpHowToDrawPanel

	case "hypertetrahedron":
		thePanelType = .helpIdeasPanel

	default:
		thePanelType = .noPanel
	}

	return thePanelType
}


//struct Draw4DContentView_Previews: PreviewProvider {
//	static var previews: some View {
//		Draw4DContentView(document: .constant(Draw4DDocument()))
//	}
//}
