package imgui

// #cgo CXXFLAGS: -std=c++11
// #cgo CPPFLAGS: -DIMGUI_USE_WCHAR32 -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS
// #cgo windows CPPFLAGS: -DIMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
// #cgo windows LDFLAGS: -limm32
// #include "imguiWrapper.h"
import "C"
import (
	"math"
)

// Version returns a version string e.g. "1.23".
func Version() string {
	return C.GoString(C.iggGetVersion())
}

// CurrentIO returns access to the ImGui communication struct for the currently active context.
func CurrentIO() IO {
	return IO{handle: C.iggGetCurrentIO()}
}

// CurrentStyle returns the UI Style for the currently active context.
func CurrentStyle() Style {
	return Style(C.iggGetCurrentStyle())
}

// NewFrame starts a new ImGui frame, you can submit any command from this point until Render()/EndFrame().
func NewFrame() {
	C.iggNewFrame()
}

// Render ends the ImGui frame, finalize the draw data.
// After this method, call RenderedDrawData to retrieve the draw commands and execute them.
func Render() {
	C.iggRender()
}

// EndFrame ends the ImGui frame. Automatically called by Render(), so most likely don't need to ever
// call that yourself directly. If you don't need to render you may call EndFrame() but you'll have
// wasted CPU already. If you don't need to render, better to not create any imgui windows instead!
func EndFrame() {
	C.iggEndFrame()
}

func GetEventWaitingTime() float64 {
	return float64(C.iggGetEventWaitingTime())
}

// RenderedDrawData returns the created draw commands, which are valid after Render() and
// until the next call to NewFrame(). This is what you have to render.
func RenderedDrawData() DrawData {
	return DrawData(C.iggGetDrawData())
}

// ShowDemoWindow creates a demo/test window. Demonstrates most ImGui features.
// Call this to learn about the library! Try to make it always available in your application!
func ShowDemoWindow(open *bool) {
	openArg, openFin := wrapBool(open)
	defer openFin()
	C.iggShowDemoWindow(openArg)
}

// ShowUserGuide adds basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls).
func ShowUserGuide() {
	C.iggShowUserGuide()
}

// BeginV pushes a new window to the stack and start appending to it.
// You may append multiple times to the same window during the same frame.
// If the open argument is provided, the window can be closed, in which case the value will be false after the call.
//
// Returns false if the window is currently not visible.
// Regardless of the return value, End() must be called for each call to Begin().
func BeginV(id string, open *bool, flags int) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	openArg, openFin := wrapBool(open)
	defer openFin()
	return C.iggBegin(idArg, openArg, C.int(flags)) != 0
}

// Begin calls BeginV(id, nil, 0).
func Begin(id string) bool {
	return BeginV(id, nil, 0)
}

// End closes the scope for the previously opened window.
// Every call to Begin() must be matched with a call to End().
func End() {
	C.iggEnd()
}

// BeginChildV pushes a new child to the stack and starts appending to it.
// flags are the WindowFlags to apply.
func BeginChildV(id string, size Vec2, border bool, flags int) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	sizeArg, _ := size.wrapped()
	return C.iggBeginChild(idArg, sizeArg, castBool(border), C.int(flags)) != 0
}

// BeginChild calls BeginChildV(id, Vec2{0,0}, false, 0).
func BeginChild(id string) bool {
	return BeginChildV(id, Vec2{}, false, 0)
}

// EndChild closes the scope for the previously opened child.
// Every call to BeginChild() must be matched with a call to EndChild().
func EndChild() {
	C.iggEndChild()
}

// WindowPos returns the current window position in screen space.
// This is useful if you want to do your own drawing via the DrawList API.
func WindowPos() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggWindowPos(valueArg)
	valueFin()
	return value
}

// WindowSize returns the size of the current window.
func WindowSize() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggWindowSize(valueArg)
	valueFin()
	return value
}

// WindowWidth returns the width of the current window.
func WindowWidth() float32 {
	return float32(C.iggWindowWidth())
}

// WindowHeight returns the height of the current window.
func WindowHeight() float32 {
	return float32(C.iggWindowHeight())
}

// ContentRegionAvail returns the size of the content region that is available (based on the current cursor position).
func ContentRegionAvail() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggContentRegionAvail(valueArg)
	valueFin()
	return value
}

func IsWindowAppearing() bool {
	return C.iggIsWindowAppearing() != 0
}

func IsWindowCollapsed() bool {
	return C.iggIsWindowCollapsed() != 0
}

func IsWindowFocused(flags int) bool {
	return C.iggIsWindowFocused(C.int(flags)) != 0
}

func IsWindowHovered(flags int) bool {
	return C.iggIsWindowHovered(C.int(flags)) != 0
}

// SetNextWindowPosV sets next window position.
// Call before Begin(). Use pivot=(0.5,0.5) to center on given point, etc.
func SetNextWindowPosV(pos Vec2, cond Condition, pivot Vec2) {
	posArg, _ := pos.wrapped()
	pivotArg, _ := pivot.wrapped()
	C.iggSetNextWindowPos(posArg, C.int(cond), pivotArg)
}

// SetNextWindowPos calls SetNextWindowPosV(pos, 0, Vec{0,0})
func SetNextWindowPos(pos Vec2) {
	SetNextWindowPosV(pos, 0, Vec2{})
}

// SetNextWindowSizeV sets next window size.
// Set axis to 0.0 to force an auto-fit on this axis. Call before Begin().
func SetNextWindowSizeV(size Vec2, cond Condition) {
	sizeArg, _ := size.wrapped()
	C.iggSetNextWindowSize(sizeArg, C.int(cond))
}

// SetNextWindowSize calls SetNextWindowSizeV(size, 0)
func SetNextWindowSize(size Vec2) {
	SetNextWindowSizeV(size, 0)
}

// SetNextWindowContentSize sets next window content size (~ enforce the range of scrollbars).
// Does not include window decorations (title bar, menu bar, etc.).
// Set one axis to 0.0 to leave it automatic. This function must be called before Begin() to take effect.
func SetNextWindowContentSize(size Vec2) {
	sizeArg, _ := size.wrapped()
	C.iggSetNextWindowContentSize(sizeArg)
}

// SetNextWindowFocus sets next window to be focused / front-most. Call before Begin().
func SetNextWindowFocus() {
	C.iggSetNextWindowFocus()
}

// SetNextWindowBgAlpha sets next window background color alpha.
// Helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg.
func SetNextWindowBgAlpha(value float32) {
	C.iggSetNextWindowBgAlpha(C.float(value))
}

// PushFont adds the given font on the stack. Use DefaultFont to refer to the default font.
func PushFont(font Font) {
	C.iggPushFont(font.handle())
}

// PopFont removes the previously pushed font from the stack.
func PopFont() {
	C.iggPopFont()
}

// PushStyleColor pushes the current style color for given ID on a stack and sets the given one.
// To revert to the previous color, call PopStyleColor().
func PushStyleColor(id StyleColorID, color Vec4) {
	colorArg, _ := color.wrapped()
	C.iggPushStyleColor(C.int(id), colorArg)
}

// PopStyleColorV reverts the given amount of style color changes.
func PopStyleColorV(count int) {
	C.iggPopStyleColor(C.int(count))
}

// PopStyleColor calls PopStyleColorV(1).
func PopStyleColor() {
	PopStyleColorV(1)
}

// PushStyleVarFloat pushes a float value on the stack to temporarily modify a style variable.
func PushStyleVarFloat(id StyleVarID, value float32) {
	C.iggPushStyleVarFloat(C.int(id), C.float(value))
}

// PushStyleVarVec2 pushes a Vec2 value on the stack to temporarily modify a style variable.
func PushStyleVarVec2(id StyleVarID, value Vec2) {
	valueArg, _ := value.wrapped()
	C.iggPushStyleVarVec2(C.int(id), valueArg)
}

// PopStyleVarV reverts the given amount of style variable changes.
func PopStyleVarV(count int) {
	C.iggPopStyleVar(C.int(count))
}

// PopStyleVar calls PopStyleVarV(1).
func PopStyleVar() {
	PopStyleVarV(1)
}

// FontSize returns the current font size (= height in pixels) of the current font with the current scale applied.
func FontSize() float32 {
	return float32(C.iggGetFontSize())
}

// CalcTextSize calculate the size of the text
func CalcTextSize(text string, hideTextAfterDoubleHash bool, wrapWidth float32) Vec2 {
	CString := newStringBuffer(text)
	defer CString.free()

	var vec2 Vec2
	valueArg, returnFunc := vec2.wrapped()

	C.iggCalcTextSize((*C.char)(CString.ptr), C.int(CString.size), castBool(hideTextAfterDoubleHash), C.float(wrapWidth), valueArg)
	returnFunc()

	return vec2
}

// Get ColorU32 from Vec4
func GetColorU32(col Vec4) uint {
	valueArg, _ := col.wrapped()
	return uint(C.iggGetColorU32(*valueArg))
}

func BeginDisabled(disabled bool) {
	C.iggBeginDisabled(castBool(disabled))
}

func EndDisabled() {
	C.iggEndDisabled()
}

func StyleColorsDark() {
	C.iggStyleColorsDark()
}

func StyleColorsClassic() {
	C.iggStyleColorsClassic()
}

func StyleColorsLight() {
	C.iggStyleColorsLight()
}

// PushItemWidth sets width of items for the common item+label case, in pixels.
// 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels,
// <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side).
func PushItemWidth(width float32) {
	C.iggPushItemWidth(C.float(width))
}

// PopItemWidth must be called for each call to PushItemWidth().
func PopItemWidth() {
	C.iggPopItemWidth()
}

// CalcItemWidth returns the width of items given pushed settings and current cursor position.
func CalcItemWidth() float32 {
	return float32(C.iggCalcItemWidth())
}

// PushTextWrapPosV defines word-wrapping for Text() commands.
// < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrapPosX' position in window local space.
// Requires a matching call to PopTextWrapPos().
func PushTextWrapPosV(wrapPosX float32) {
	C.iggPushTextWrapPos(C.float(wrapPosX))
}

// PushTextWrapPos calls PushTextWrapPosV(0.0).
func PushTextWrapPos() {
	PushTextWrapPosV(0.0)
}

// PopTextWrapPos resets the last pushed position.
func PopTextWrapPos() {
	C.iggPopTextWrapPos()
}

// PushID pushes the given identifier into the ID stack. IDs are hash of the entire stack!
func PushID(id string) {
	idArg, idFin := wrapString(id)
	defer idFin()
	C.iggPushID(idArg)
}

// PopID removes the last pushed identifier from the ID stack.
func PopID() {
	C.iggPopID()
}

// Text adds formatted text. See PushTextWrapPosV() or PushStyleColorV() for modifying the output.
// Without any modified style stack, the text is unformatted.
func Text(text string) {
	textArg, textFin := wrapString(text)
	defer textFin()
	// Internally we use ImGui::TextUnformatted, for the most direct call.
	C.iggTextUnformatted(textArg)
}

// LabelText adds text+label aligned the same way as value+label widgets.
func LabelText(label, text string) {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	textArg, textFin := wrapString(text)
	defer textFin()
	C.iggLabelText(labelArg, textArg)
}

// ButtonV returning true if it is pressed.
func ButtonV(id string, size Vec2) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	sizeArg, _ := size.wrapped()
	return C.iggButton(idArg, sizeArg) != 0
}

// Button calls ButtonV(id, Vec2{0,0}).
func Button(id string) bool {
	return ButtonV(id, Vec2{})
}

func SmallButton(id string) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	return C.iggSmallButton(idArg) != 0
}

func InvisibleButton(id string, size Vec2) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	sizeArg, _ := size.wrapped()
	return C.iggInvisibleButton(idArg, sizeArg) != 0
}

func ArrowButton(id string, dir uint8) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	return C.iggArrowButton(idArg, C.uchar(dir)) != 0
}

func Bullet() {
	C.iggBullet()
}

// BulletText.
// Text with a little bullet aligned to the typical tree node.
func BulletText(text string) {
	textArg, textFin := wrapString(text)
	defer textFin()
	C.iggBulletText(textArg)
}

// ImageV adds an image based on given texture ID.
// Refer to TextureID what this represents and how it is drawn.
func ImageV(id TextureID, size Vec2, uv0, uv1 Vec2, tintCol, borderCol Vec4) {
	sizeArg, _ := size.wrapped()
	uv0Arg, _ := uv0.wrapped()
	uv1Arg, _ := uv1.wrapped()
	tintColArg, _ := tintCol.wrapped()
	borderColArg, _ := borderCol.wrapped()
	C.iggImage(id.handle(), sizeArg, uv0Arg, uv1Arg, tintColArg, borderColArg)
}

// Image calls ImageV(id, size, Vec2{0,0}, Vec2{1,1}, Vec4{1,1,1,1}, Vec4{0,0,0,0}).
func Image(id TextureID, size Vec2) {
	ImageV(id, size, Vec2{X: 0, Y: 0}, Vec2{X: 1, Y: 1}, Vec4{X: 1, Y: 1, Z: 1, W: 1}, Vec4{X: 0, Y: 0, Z: 0, W: 0})
}

// ImageButtonV adds a button with an image, based on given texture ID.
// Refer to TextureID what this represents and how it is drawn.
// <0 framePadding uses default frame padding settings. 0 for no padding.
func ImageButtonV(id TextureID, size Vec2, uv0, uv1 Vec2, framePadding int, bgCol Vec4, tintCol Vec4) bool {
	sizeArg, _ := size.wrapped()
	uv0Arg, _ := uv0.wrapped()
	uv1Arg, _ := uv1.wrapped()
	bgColArg, _ := bgCol.wrapped()
	tintColArg, _ := tintCol.wrapped()
	return C.iggImageButton(id.handle(), sizeArg, uv0Arg, uv1Arg, C.int(framePadding), bgColArg, tintColArg) != 0
}

// ImageButton calls ImageButtonV(id, size, Vec2{0,0}, Vec2{1,1}, -1, Vec4{0,0,0,0}, Vec4{1,1,1,1}).
func ImageButton(id TextureID, size Vec2) bool {
	return ImageButtonV(id, size, Vec2{X: 0, Y: 0}, Vec2{X: 1, Y: 1}, -1, Vec4{X: 0, Y: 0, Z: 0, W: 0}, Vec4{X: 1, Y: 1, Z: 1, W: 1})
}

// Checkbox creates a checkbox in the selected state.
// The return value indicates if the selected state has changed.
func Checkbox(id string, selected *bool) bool {
	idArg, idFin := wrapString(id)
	defer idFin()
	selectedArg, selectedFin := wrapBool(selected)
	defer selectedFin()
	return C.iggCheckbox(idArg, selectedArg) != 0
}

func RadioButton(label string, active bool) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	return C.iggRadioButton(labelArg, castBool(active)) != 0
}

// ProgressBarV creates a progress bar.
// size (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
func ProgressBarV(fraction float32, size Vec2, overlay string) {
	sizeArg, _ := size.wrapped()
	overlayArg, overlayFin := wrapString(overlay)
	defer overlayFin()
	C.iggProgressBar(C.float(fraction), sizeArg, overlayArg)
}

// ProgressBar calls ProgressBarV(fraction, Vec2{X: -1, Y: 0}, "").
func ProgressBar(fraction float32) {
	ProgressBarV(fraction, Vec2{X: -1, Y: 0}, "")
}

// BeginComboV creates a combo box with complete control over the content to the user.
// Call EndCombo() if this function returns true.
// flags are the ComboFlags to apply.
func BeginComboV(label, previewValue string, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	previewValueArg, previewValueFin := wrapString(previewValue)
	defer previewValueFin()
	return C.iggBeginCombo(labelArg, previewValueArg, C.int(flags)) != 0
}

// BeginCombo calls BeginComboV(label, previewValue, 0).
func BeginCombo(label, previewValue string) bool {
	return BeginComboV(label, previewValue, 0)
}

// EndCombo must be called if BeginComboV() returned true.
func EndCombo() {
	C.iggEndCombo()
}

// DragFloatV creates a draggable slider for floats.
func DragFloatV(label string, value *float32, speed, min, max float32, format string, power float32) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	valueArg, valueFin := wrapFloat(value)
	defer valueFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()
	return C.iggDragFloat(labelArg, valueArg, C.float(speed), C.float(min), C.float(max), formatArg, C.float(power)) != 0
}

// DragFloat calls DragFloatV(label, value, 1.0, 0.0, 0.0, "%.3f", 1.0).
func DragFloat(label string, value *float32) bool {
	return DragFloatV(label, value, 1.0, 0.0, 0.0, "%.3f", 1.0)
}

// DragIntV creates a draggable slider for integers.
func DragIntV(label string, value *int32, speed float32, min, max int32, format string) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	valueArg, valueFin := wrapInt32(value)
	defer valueFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()
	return C.iggDragInt(labelArg, valueArg, C.float(speed), C.int(min), C.int(max), formatArg) != 0
}

// DragInt calls DragIntV(label, value, 1.0, 0, 0, "%d").
func DragInt(label string, value *int32) bool {
	return DragIntV(label, value, 1.0, 0, 0, "%d")
}

// SliderFloatV creates a slider for floats.
func SliderFloatV(label string, value *float32, min, max float32, format string, power float32) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	valueArg, valueFin := wrapFloat(value)
	defer valueFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()
	return C.iggSliderFloat(labelArg, valueArg, C.float(min), C.float(max), formatArg, C.float(power)) != 0
}

// SliderFloat calls SliderIntV(label, value, min, max, "%.3f", 1.0).
func SliderFloat(label string, value *float32, min, max float32) bool {
	return SliderFloatV(label, value, min, max, "%.3f", 1.0)
}

// SliderFloat3V creates slider for a 3D vector.
func SliderFloat3V(label string, values *[3]float32, min, max float32, format string, power float32) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()
	cvalues := (*C.float)(&values[0])
	return C.iggSliderFloatN(labelArg, cvalues, 3, C.float(min), C.float(max), formatArg, C.float(power)) != 0
}

// SliderFloat3 calls SliderFloat3V(label, values, min, max, "%.3f", 1,0).
func SliderFloat3(label string, values *[3]float32, min, max float32) bool {
	return SliderFloat3V(label, values, min, max, "%.3f", 1.0)
}

// SliderIntV creates a slider for integers.
func SliderIntV(label string, value *int32, min, max int32, format string) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	valueArg, valueFin := wrapInt32(value)
	defer valueFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()
	return C.iggSliderInt(labelArg, valueArg, C.int(min), C.int(max), formatArg) != 0
}

// SliderInt calls SliderIntV(label, value, min, max, "%d").
func SliderInt(label string, value *int32, min, max int32) bool {
	return SliderIntV(label, value, min, max, "%d")
}

func VSliderIntV(label string, size Vec2, value *int32, min, max int32, format string, flags int) bool {
	labelArg, labelDeleter := wrapString(label)
	defer labelDeleter()

	sizeArg, _ := size.wrapped()

	valueArg, valueDeleter := wrapInt32(value)
	defer valueDeleter()

	formatArg, formatDeleter := wrapString(format)
	defer formatDeleter()

	return C.iggVSliderInt(labelArg, sizeArg, valueArg, C.int(min), C.int(max), formatArg, C.int(flags)) != 0
}

// InputText creates a text field for dynamic text input.
//
// Contrary to the original library, this wrapper does not limit the maximum number of possible characters.
// Dynamic resizing of the internal buffer is handled within the wrapper and the user will never be called for such requests.
//
// The provided callback is called for any of the requested InputTextFlagsCallback* flags.
//
// To implement a character limit, provide a callback that drops input characters when the requested length has been reached.
func InputTextWithHint(label, hint string, text *string, flags int, cb InputTextCallback) bool {
	if text == nil {
		panic("text can't be nil")
	}

	labelArg, labelFin := wrapString(label)
	defer labelFin()

	hintArg, hintFin := wrapString(hint)
	defer hintFin()

	state := newInputTextState(*text, cb)
	defer func() {
		*text = state.buf.toGo()
		state.release()
	}()

	return C.iggInputTextWithHint(labelArg, hintArg, (*C.char)(state.buf.ptr), C.uint(state.buf.size),
		C.int(flags|inputTextFlagsCallbackResize), state.key) != 0
}

func InputTextV(label string, text *string, flags int, cb InputTextCallback) bool {
	return InputTextWithHint(label, "", text, flags, cb)
}

// InputText calls InputTextV(label, string, 0, nil)
func InputText(label string, text *string) bool {
	return InputTextV(label, text, 0, nil)
}

// InputTextMultilineV provides a field for dynamic text input of multiple lines.
//
// Contrary to the original library, this wrapper does not limit the maximum number of possible characters.
// Dynamic resizing of the internal buffer is handled within the wrapper and the user will never be called for such requests.
//
// The provided callback is called for any of the requested InputTextFlagsCallback* flags.
//
// To implement a character limit, provide a callback that drops input characters when the requested length has been reached.
func InputTextMultilineV(label string, text *string, size Vec2, flags int, cb InputTextCallback) bool {
	if text == nil {
		panic("text can't be nil")
	}
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	sizeArg, _ := size.wrapped()
	state := newInputTextState(*text, cb)
	defer func() {
		*text = state.buf.toGo()
		state.release()
	}()

	return C.iggInputTextMultiline(labelArg, (*C.char)(state.buf.ptr), C.uint(state.buf.size), sizeArg,
		C.int(flags|inputTextFlagsCallbackResize), state.key) != 0
}

// InputTextMultiline calls InputTextMultilineV(label, text, Vec2{0,0}, 0, nil)
func InputTextMultiline(label string, text *string) bool {
	return InputTextMultilineV(label, text, Vec2{}, 0, nil)
}

func InputInt(label string, value *int32) bool {
	return InputIntV(label, value, 0, 100, 0)
}

func InputIntV(label string, value *int32, step, step_fast int, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()

	valueArg, valueFin := wrapInt32(value)
	defer valueFin()

	return C.iggInputInt(labelArg, valueArg, C.int(0), C.int(100), C.int(flags)) != 0
}

func InputFloat(label string, value *float32) bool {
	return InputFloatV(label, value, 0.0, 0.0, "%.3f", 0)
}

func InputFloatV(label string, value *float32, step, step_fast float32, format string, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	valueArg, valueFin := wrapFloat(value)
	defer valueFin()
	formatArg, formatFin := wrapString(format)
	defer formatFin()

	return C.iggInputFloat(labelArg, valueArg, C.float(step), C.float(step_fast), formatArg, C.int(flags)) != 0
}

// ColorEdit3 calls ColorEdit3V(label, col, 0)
func ColorEdit3(label string, col *[3]float32) bool {
	return ColorEdit3V(label, col, 0)
}

// ColorEdit3V will show a clickable little square which will open a color picker window for 3D vector (rgb format).
func ColorEdit3V(label string, col *[3]float32, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	ccol := (*C.float)(&col[0])
	return C.iggColorEdit3(labelArg, ccol, C.int(flags)) != 0
}

// ColorEdit4 calls ColorEdit4V(label, col, 0)
func ColorEdit4(label string, col *[4]float32) bool {
	return ColorEdit4V(label, col, 0)
}

// ColorEdit4V will show a clickable little square which will open a color picker window for 4D vector (rgba format).
func ColorEdit4V(label string, col *[4]float32, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	ccol := (*C.float)(&col[0])
	return C.iggColorEdit4(labelArg, ccol, C.int(flags)) != 0
}

// ColorPicker3 calls ColorPicker3(label, col, 0)
func ColorPicker3(label string, col *[3]float32, flags int) bool {
	return ColorPicker3V(label, col, 0)
}

// ColorPicker3V will show directly a color picker control for editing a color in 3D vector (rgb format).
func ColorPicker3V(label string, col *[3]float32, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	ccol := (*C.float)(&col[0])
	return C.iggColorPicker3(labelArg, ccol, C.int(flags)) != 0
}

// ColorPicker4 calls ColorPicker4(label, col, 0)
func ColorPicker4(label string, col *[4]float32) bool {
	return ColorPicker4V(label, col, 0)
}

// ColorPicker4V will show directly a color picker control for editing a color in 4D vector (rgba format).
func ColorPicker4V(label string, col *[4]float32, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	ccol := (*C.float)(&col[0])
	return C.iggColorPicker4(labelArg, ccol, C.int(flags)) != 0
}

// Separator is generally horizontal. Inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
func Separator() {
	C.iggSeparator()
}

// SameLineV is between widgets or groups to layout them horizontally.
func SameLineV(posX float32, spacingW float32) {
	C.iggSameLine(C.float(posX), C.float(spacingW))
}

// SameLine calls SameLineV(0, -1).
func SameLine() {
	SameLineV(0, -1)
}

// Spacing adds vertical spacing.
func Spacing() {
	C.iggSpacing()
}

// Dummy adds a dummy item of given size.
func Dummy(size Vec2) {
	sizeArg, _ := size.wrapped()
	C.iggDummy(sizeArg)
}

// BeginGroup locks horizontal starting position + capture group bounding box into one "item"
// (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
func BeginGroup() {
	C.iggBeginGroup()
}

// EndGroup must be called for each call to BeginGroup().
func EndGroup() {
	C.iggEndGroup()
}

// CursorPos returns the cursor position in window coordinates (relative to window position).
func CursorPos() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggCursorPos(valueArg)
	valueFin()
	return value
}

// CursorPosX returns the x-coordinate of the cursor position in window coordinates.
func CursorPosX() float32 {
	return float32(C.iggCursorPosX())
}

// CursorPosY returns the y-coordinate of the cursor position in window coordinates.
func CursorPosY() float32 {
	return float32(C.iggCursorPosY())
}

// CursorStartPos returns the initial cursor position in window coordinates.
func CursorStartPos() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggCursorStartPos(valueArg)
	valueFin()
	return value
}

// CursorScreenPos returns the cursor position in absolute screen coordinates.
func CursorScreenPos() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggCursorScreenPos(valueArg)
	valueFin()
	return value
}

// SetCursorPos sets the cursor relative to the current window.
func SetCursorPos(localPos Vec2) {
	localPosArg, _ := localPos.wrapped()
	C.iggSetCursorPos(localPosArg)
}

// SetCursorScreenPos sets the cursor position in absolute screen coordinates.
func SetCursorScreenPos(absPos Vec2) {
	absPosArg, _ := absPos.wrapped()
	C.iggSetCursorScreenPos(absPosArg)
}

// MousePos returns the mouse position in absolute screen coordinates.
func MousePos() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggMousePos(valueArg)
	valueFin()
	return value
}

// AlignTextToFramePadding vertically aligns upcoming text baseline to
// FramePadding.y so that it will align properly to regularly framed
// items. Call if you have text on a line before a framed item.
func AlignTextToFramePadding() {
	C.iggAlignTextToFramePadding()
}

// TextLineHeight returns ~ FontSize.
func TextLineHeight() float32 {
	return float32(C.iggGetTextLineHeight())
}

// TextLineHeightWithSpacing returns ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text).
func TextLineHeightWithSpacing() float32 {
	return float32(C.iggGetTextLineHeightWithSpacing())
}

// FrameHeightWithSpacing return ~ FontSize + style.FramePadding.y * 2.0f + style.ItemSpacing.y;
func FrameHeightWithSpacing() float32 {
	return float32(C.iggFrameHeightWithSpacing())
}

// TreeNodeV returns true if the tree branch is to be rendered. Call TreePop() in this case.
func TreeNodeV(label string, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	return C.iggTreeNode(labelArg, C.int(flags)) != 0
}

// TreeNode calls TreeNodeV(label, 0).
func TreeNode(label string) bool {
	return TreeNodeV(label, 0)
}

// TreePop finishes a tree branch. This has to be called for a matching TreeNodeV call returning true.
func TreePop() {
	C.iggTreePop()
}

// SetNextItemOpen sets the open/collapsed state of the following tree node.
func SetNextItemOpen(open bool, cond Condition) {
	C.iggSetNextItemOpen(castBool(open), C.int(cond))
}

// TreeNodeToLabelSpacing returns the horizontal distance preceding label for a regular unframed TreeNode.
func TreeNodeToLabelSpacing() float32 {
	return float32(C.iggGetTreeNodeToLabelSpacing())
}

// SelectableV returns true if the user clicked it, so you can modify your selection state.
// flags are the SelectableFlags to apply.
// size.x==0.0: use remaining width, size.x>0.0: specify width.
// size.y==0.0: use label height, size.y>0.0: specify height
func SelectableV(label string, selected bool, flags int, size Vec2) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	sizeArg, _ := size.wrapped()
	return C.iggSelectable(labelArg, castBool(selected), C.int(flags), sizeArg) != 0
}

// Selectable calls SelectableV(label, false, 0, Vec2{0, 0})
func Selectable(label string) bool {
	return SelectableV(label, false, 0, Vec2{})
}

// ListBoxV creates a list of selectables of given items with equal height, enclosed with header and footer.
// This version accepts a custom item height.
// The function returns true if the selection was changed. The value of currentItem will indicate the new selected item.
func ListBoxV(label string, currentItem *int32, items []string, heightItems int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()

	valueArg, valueFin := wrapInt32(currentItem)
	defer valueFin()

	itemsCount := len(items)

	argv := make([]*C.char, itemsCount)
	for i, item := range items {
		itemArg, itemDeleter := wrapString(item)
		defer itemDeleter()
		argv[i] = itemArg
	}

	return C.iggListBoxV(labelArg, valueArg, &argv[0], C.int(itemsCount), C.int(heightItems)) != 0
}

// ListBox calls ListBoxV(label, currentItem, items, -1)
// The function returns true if the selection was changed. The value of currentItem will indicate the new selected item.
func ListBox(label string, currentItem *int32, items []string) bool {
	return ListBoxV(label, currentItem, items, -1)
}

// PlotLines draws an array of floats as a line graph.
// It calls PlotLinesV using no overlay text and automatically calculated scale and graph size.
func PlotLines(label string, values []float32) {
	PlotLinesV(label, values, 0, "", math.MaxFloat32, math.MaxFloat32, Vec2{})
}

// PlotLinesV draws an array of floats as a line graph with additional options.
// valuesOffset specifies an offset into the values array at which to start drawing, wrapping around when the end of the values array is reached.
// overlayText specifies a string to print on top of the graph.
// scaleMin and scaleMax define the scale of the y axis, if either is math.MaxFloat32 that value is calculated from the input data.
// graphSize defines the size of the graph, if either coordinate is zero the default size for that direction is used.
func PlotLinesV(label string, values []float32, valuesOffset int, overlayText string, scaleMin float32, scaleMax float32, graphSize Vec2) {
	labelArg, labelFin := wrapString(label)
	defer labelFin()

	valuesCount := len(values)
	valuesArray := make([]C.float, valuesCount)
	for i, value := range values {
		valuesArray[i] = C.float(value)
	}

	var overlayTextArg *C.char
	if overlayText != "" {
		var overlayTextFinisher func()
		overlayTextArg, overlayTextFinisher = wrapString(overlayText)
		defer overlayTextFinisher()
	}

	graphSizeArg, _ := graphSize.wrapped()

	C.iggPlotLines(labelArg, &valuesArray[0], C.int(valuesCount), C.int(valuesOffset), overlayTextArg, C.float(scaleMin), C.float(scaleMax), graphSizeArg)
}

// PlotHistogram draws an array of floats as a bar graph.
// It calls PlotHistogramV using no overlay text and automatically calculated scale and graph size.
func PlotHistogram(label string, values []float32) {
	PlotHistogramV(label, values, 0, "", math.MaxFloat32, math.MaxFloat32, Vec2{})
}

// PlotHistogramV draws an array of floats as a bar graph with additional options.
// valuesOffset specifies an offset into the values array at which to start drawing, wrapping around when the end of the values array is reached.
// overlayText specifies a string to print on top of the graph.
// scaleMin and scaleMax define the scale of the y axis, if either is math.MaxFloat32 that value is calculated from the input data.
// graphSize defines the size of the graph, if either coordinate is zero the default size for that direction is used.
func PlotHistogramV(label string, values []float32, valuesOffset int, overlayText string, scaleMin float32, scaleMax float32, graphSize Vec2) {
	labelArg, labelFin := wrapString(label)
	defer labelFin()

	valuesCount := len(values)
	valuesArray := make([]C.float, valuesCount)
	for i, value := range values {
		valuesArray[i] = C.float(value)
	}

	var overlayTextArg *C.char
	if overlayText != "" {
		var overlayTextFinisher func()
		overlayTextArg, overlayTextFinisher = wrapString(overlayText)
		defer overlayTextFinisher()
	}

	graphSizeArg, _ := graphSize.wrapped()

	C.iggPlotHistogram(labelArg, &valuesArray[0], C.int(valuesCount), C.int(valuesOffset), overlayTextArg, C.float(scaleMin), C.float(scaleMax), graphSizeArg)
}

// SetTooltip sets a text tooltip under the mouse-cursor, typically use with IsItemHovered().
// Overrides any previous call to SetTooltip().
func SetTooltip(text string) {
	textArg, textFin := wrapString(text)
	defer textFin()
	C.iggSetTooltip(textArg)
}

// BeginTooltip begins/appends to a tooltip window. Used to create full-featured tooltip (with any kind of contents).
// Requires a call to EndTooltip().
func BeginTooltip() {
	C.iggBeginTooltip()
}

// EndTooltip closes the previously started tooltip window.
func EndTooltip() {
	C.iggEndTooltip()
}

// BeginMainMenuBar creates and appends to a full screen menu-bar.
// If the return value is true, then EndMainMenuBar() must be called!
func BeginMainMenuBar() bool {
	return C.iggBeginMainMenuBar() != 0
}

// EndMainMenuBar finishes a main menu bar.
// Only call EndMainMenuBar() if BeginMainMenuBar() returns true!
func EndMainMenuBar() {
	C.iggEndMainMenuBar()
}

// BeginMenuBar appends to menu-bar of current window.
// This requires WindowFlagsMenuBar flag set on parent window.
// If the return value is true, then EndMenuBar() must be called!
func BeginMenuBar() bool {
	return C.iggBeginMenuBar() != 0
}

// EndMenuBar finishes a menu bar.
// Only call EndMenuBar() if BeginMenuBar() returns true!
func EndMenuBar() {
	C.iggEndMenuBar()
}

// BeginMenuV creates a sub-menu entry.
// If the return value is true, then EndMenu() must be called!
func BeginMenuV(label string, enabled bool) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	return C.iggBeginMenu(labelArg, castBool(enabled)) != 0
}

// BeginMenu calls BeginMenuV(label, true).
func BeginMenu(label string) bool {
	return BeginMenuV(label, true)
}

// EndMenu finishes a sub-menu entry.
// Only call EndMenu() if BeginMenu() returns true!
func EndMenu() {
	C.iggEndMenu()
}

// MenuItemV adds a menu item with given label.
// Returns true if the item is selected.
// If selected is not nil, it will be toggled when true is returned.
// Shortcuts are displayed for convenience but not processed by ImGui at the moment.
func MenuItemV(label string, shortcut string, selected bool, enabled bool) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	shortcutArg, shortcutFin := wrapString(shortcut)
	defer shortcutFin()
	return C.iggMenuItem(labelArg, shortcutArg, castBool(selected), castBool(enabled)) != 0
}

// MenuItem calls MenuItemV(label, "", false, true).
func MenuItem(label string) bool {
	return MenuItemV(label, "", false, true)
}

// OpenPopup marks popup as open (don't call every frame!).
// Popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
// By default, Selectable()/MenuItem() are calling CloseCurrentPopup().
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
func OpenPopup(id string) {
	idArg, idFin := wrapString(id)
	defer idFin()
	C.iggOpenPopup(idArg)
}

// Popups, Modals
//  - They block normal mouse hovering detection (and therefore most mouse
//  interactions) behind them.
//  - If not modal: they can be closed by clicking anywhere outside them, or by
//  pressing ESCAPE.
//  - Their visibility state (~bool) is held internally instead of being held by
//  the programmer as we are used to with regular Begin*() calls.
//  - The 3 properties above are related: we need to retain popup visibility
//  state in the library because popups may be closed as any time.
//  - You can bypass the hovering restriction by using
//  ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or
//  IsWindowHovered().
//  - IMPORTANT: Popup identifiers are relative to the current ID stack, so
//  OpenPopup and BeginPopup generally needs to be at the same level of the
//  stack.
//    This is sometimes leading to confusing mistakes. May rework this in the
//    future.
// Popups: begin/end functions
//  - BeginPopup(): query popup state, if open start appending into the window.
//  Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window.
//  - BeginPopupModal(): block every interactions behind the window, cannot be
//  closed by user, add a dimming background, has a title bar.
func BeginPopup(name string, flags int) bool {
	nameArg, nameFin := wrapString(name)
	defer nameFin()
	return C.iggBeginPopup(nameArg, C.int(flags)) != 0
}

// BeginPopupModalV creates modal dialog (regular window with title bar, block interactions behind the modal window,
// can't close the modal window by clicking outside).
func BeginPopupModalV(name string, open *bool, flags int) bool {
	nameArg, nameFin := wrapString(name)
	defer nameFin()
	openArg, openFin := wrapBool(open)
	defer openFin()
	return C.iggBeginPopupModal(nameArg, openArg, C.int(flags)) != 0
}

// BeginPopupModal calls BeginPopupModalV(name, nil, 0)
func BeginPopupModal(name string) bool {
	return BeginPopupModalV(name, nil, 0)
}

// BeginPopupContextItemV returns true if the identified mouse button was pressed
// while hovering over the last item.
func BeginPopupContextItemV(label string, mouseButton int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	return C.iggBeginPopupContextItem(labelArg, C.int(mouseButton)) != 0
}

// BeginPopupContextItem calls BeginPopupContextItemV("", 1)
func BeginPopupContextItem() bool {
	return BeginPopupContextItemV("", 1)
}

// EndPopup finshes a popup. Only call EndPopup() if BeginPopupXXX() returns true!
func EndPopup() {
	C.iggEndPopup()
}

// CloseCurrentPopup closes the popup we have begin-ed into.
// Clicking on a MenuItem or Selectable automatically close the current popup.
func CloseCurrentPopup() {
	C.iggCloseCurrentPopup()
}

// IsItemHoveredV returns true if the last item is hovered.
// (and usable, aka not blocked by a popup, etc.). See HoveredFlags for more options.
func IsItemHoveredV(flags int) bool {
	return C.iggIsItemHovered(C.int(flags)) != 0
}

// IsItemHovered calls IsItemHoveredV(HoveredFlagsNone)
func IsItemHovered() bool {
	return IsItemHoveredV(HoveredFlagsNone)
}

// Is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered()
func IsItemClicked(mouseButton int) bool {
	return C.iggIsItemClicked(C.int(mouseButton)) != 0
}

func IsItemActive() bool {
	return C.iggIsItemActive() != 0
}

// IsAnyItemActive returns true if the any item is active.
func IsAnyItemActive() bool {
	return C.iggIsAnyItemActive() != 0
}

// IsKeyDown returns true if the corresponding key is currently being held down.
func IsKeyDown(key int) bool {
	return C.iggIsKeyDown(C.int(key)) != 0
}

// IsKeyPressedV returns true if the corresponding key was pressed (went from !Down to Down).
// If repeat=true and the key is being held down then the press is repeated using io.KeyRepeatDelay and KeyRepeatRate
func IsKeyPressedV(key int, repeat bool) bool {
	return C.iggIsKeyPressed(C.int(key), castBool(repeat)) != 0
}

// IsKeyPressed calls IsKeyPressedV(key, true).
func IsKeyPressed(key int) bool {
	return IsKeyPressedV(key, true)
}

// IsKeyReleased returns true if the corresponding key was released (went from Down to !Down).
func IsKeyReleased(key int) bool {
	return C.iggIsKeyReleased(C.int(key)) != 0
}

// IsMouseDown returns true if the corresponding mouse button is currently being held down.
func IsMouseDown(button int) bool {
	return C.iggIsMouseDown(C.int(button)) != 0
}

// IsAnyMouseDown returns true if any mouse button is currently being held down.
func IsAnyMouseDown() bool {
	return C.iggIsAnyMouseDown() != 0
}

// IsMouseClickedV returns true if the mouse button was clicked (0=left, 1=right, 2=middle)
// If repeat=true and the mouse button is being held down then the click is repeated using io.KeyRepeatDelay and KeyRepeatRate
func IsMouseClickedV(button int, repeat bool) bool {
	return C.iggIsMouseClicked(C.int(button), castBool(repeat)) != 0
}

// IsMouseClicked calls IsMouseClickedV(key, false).
func IsMouseClicked(button int) bool {
	return IsMouseClickedV(button, false)
}

// IsMouseReleased returns true if the mouse button was released (went from Down to !Down).
func IsMouseReleased(button int) bool {
	return C.iggIsMouseReleased(C.int(button)) != 0
}

// IsMouseDoubleClicked returns true if the mouse button was double-clicked (0=left, 1=right, 2=middle).
func IsMouseDoubleClicked(button int) bool {
	return C.iggIsMouseDoubleClicked(C.int(button)) != 0
}

// Columns calls ColumnsV(1, "", false).
func Columns() {
	ColumnsV(1, "", false)
}

// ColumnsV creates a column layout of the specified number of columns.
// The brittle columns API will be superseded by an upcoming 'table' API.
func ColumnsV(count int, label string, border bool) {
	labelArg, labelFin := wrapString(label)
	defer labelFin()
	C.iggColumns(C.int(count), labelArg, castBool(border))
}

// NextColumn next column, defaults to current row or next row if the current row is finished.
func NextColumn() {
	C.iggNextColumn()
}

// ColumnIndex get current column index.
func ColumnIndex() int {
	return int(C.iggGetColumnIndex())
}

// ColumnWidth calls ColumnWidthV(-1).
func ColumnWidth() int {
	return ColumnWidthV(-1)
}

// ColumnWidthV get column width (in pixels). pass -1 to use current column.
func ColumnWidthV(index int) int {
	return int(C.iggGetColumnWidth(C.int(index)))
}

// SetColumnWidth sets column width (in pixels). pass -1 to use current column.
func SetColumnWidth(index int, width float32) {
	C.iggSetColumnWidth(C.int(index), C.float(width))
}

// ColumnOffset calls ColumnOffsetV(-1)
func ColumnOffset() float32 {
	return ColumnOffsetV(-1)
}

// ColumnOffsetV get position of column line (in pixels, from the left side of the contents region). pass -1 to use
// current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0.
func ColumnOffsetV(index int) float32 {
	return float32(C.iggGetColumnOffset(C.int(index)))
}

// SetColumnOffset set position of column line (in pixels, from the left side of the contents region). pass -1 to use
// current column.
func SetColumnOffset(index int, offsetX float32) {
	C.iggSetColumnOffset(C.int(index), C.float(offsetX))
}

// ColumnsCount returns number of current columns.
func ColumnsCount() int {
	return int(C.iggGetColumnsCount())
}

// BeginTabBarV create and append into a TabBar
func BeginTabBarV(strID string, flags int) bool {
	idArg, idFin := wrapString(strID)
	defer idFin()

	return C.iggBeginTabBar(idArg, C.int(flags)) != 0
}

// BeginTabBar calls BeginTabBarV(strId, 0)
func BeginTabBar(strID string) bool {
	return BeginTabBarV(strID, 0)
}

// EndTabBar only call EndTabBar() if BeginTabBar() returns true!
func EndTabBar() {
	C.iggEndTabBar()
}

// BeginTabItemV create a Tab. Returns true if the Tab is selected.
func BeginTabItemV(label string, open *bool, flags int) bool {
	labelArg, labelFin := wrapString(label)
	defer labelFin()

	openArg, openFin := wrapBool(open)
	defer openFin()

	return C.iggBeginTabItem(labelArg, openArg, C.int(flags)) != 0
}

// BeginTabItem calls BeginTabItemV(label, nil, 0)
func BeginTabItem(label string) bool {
	return BeginTabItemV(label, nil, 0)
}

// EndTabItem Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
func EndTabItem() {
	C.iggEndTabItem()
}

// SetTabItemClosed notify TabBar or Docking system of a closed tab/window ahead
// (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call
// after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
func SetTabItemClosed(tabOrDockedWindowLabel string) {
	labelArg, labelFin := wrapString(tabOrDockedWindowLabel)
	defer labelFin()
	C.iggSetTabItemClosed(labelArg)
}

// ScrollX returns the horizontal scrolling amount [0..GetScrollMaxX()].
func ScrollX() float32 {
	return float32(C.iggGetScrollX())
}

// ScrollY returns the vertical scrolling amount [0..GetScrollMaxY()].
func ScrollY() float32 {
	return float32(C.iggGetScrollY())
}

// ScrollMaxX returns the maximum horizontal scrolling amount: ContentSize.X - WindowSize.X .
func ScrollMaxX() float32 {
	return float32(C.iggGetScrollMaxX())
}

// ScrollMaxY returns the maximum vertical scrolling amount: ContentSize.Y - WindowSize.Y .
func ScrollMaxY() float32 {
	return float32(C.iggGetScrollMaxY())
}

// SetScrollHereX adjusts horizontal scrolling amount to make current cursor
// position visible.  ratio=0.0: left, 0.5: center, 1.0: right.  When using to
// make a "default/current item" visible, consider using SetItemDefaultFocus()
// instead.
func SetScrollHereX(ratio float32) {
	C.iggSetScrollHereX(C.float(ratio))
}

// SetScrollHereY adjusts scrolling amount to make current cursor position visible.
// ratio=0.0: top, 0.5: center, 1.0: bottom.
// When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
func SetScrollHereY(ratio float32) {
	C.iggSetScrollHereY(C.float(ratio))
}

// SetScrollX sets horizontal scrolling amount [0..GetScrollMaxX()].
func SetScrollX(scrollX float32) {
	C.iggSetScrollX(C.float(scrollX))
}

// SetScrollY sets vertical scrolling amount [0..GetScrollMaxY()].
func SetScrollY(scrollY float32) {
	C.iggSetScrollY(C.float(scrollY))
}

// SetItemDefaultFocus makes the last item the default focused item of a window.
func SetItemDefaultFocus() {
	C.iggSetItemDefaultFocus()
}

// IsItemFocused returns true if the last item is focused.
func IsItemFocused() bool {
	return C.iggIsItemFocused() != 0
}

// IsAnyItemFocused returns true if any item is focused.
func IsAnyItemFocused() bool {
	return C.iggIsAnyItemFocused() != 0
}

// MouseCursor returns desired cursor type, reset in imgui.NewFrame(), this is updated during the frame.
// Valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you.
func MouseCursor() int {
	return int(C.iggGetMouseCursor())
}

// SetMouseCursor sets desired cursor type.
func SetMouseCursor(cursor int) {
	C.iggSetMouseCursor(C.int(cursor))
}

// SetKeyboardFocusHere calls SetKeyboardFocusHereV(0)
func SetKeyboardFocusHere() {
	C.iggSetKeyboardFocusHere(0)
}

// SetKeyboardFocusHereV gives keyboard focus to next item
func SetKeyboardFocusHereV(offset int) {
	C.iggSetKeyboardFocusHere(C.int(offset))
}

func GetWindowDrawList() DrawList {
	return DrawList(C.iggGetWindowDrawList())
}

func GetItemRectMin() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggGetItemRectMin(valueArg)
	valueFin()
	return value
}

func GetItemRectMax() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggGetItemRectMax(valueArg)
	valueFin()
	return value
}

func GetItemRectSize() Vec2 {
	var value Vec2
	valueArg, valueFin := value.wrapped()
	C.iggGetItemRectSize(valueArg)
	valueFin()
	return value
}

func PushClipRect(clipRectMin, clipRectMax Vec2, intersectWithClipRect bool) {
	clipMin, _ := clipRectMin.wrapped()
	clipMax, _ := clipRectMax.wrapped()
	C.iggPushClipRect(clipMin, clipMax, castBool(intersectWithClipRect))
}

func PopClipRect() {
	C.iggPopClipRect()
}

func PushAllowKeyboardFocus(allowKeyboardFocus bool) {
	C.iggPushAllowKeyboardFocus(castBool(allowKeyboardFocus))
}

func PopAllowKeyboardFocus() {
	C.iggPopAllowKeyboardFocus()
}
