| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- package imgui
- // #include "InputTextCallbackDataWrapper.h"
- import "C"
- import (
- "sync"
- "unsafe"
- )
- const (
- // InputTextFlagsNone sets everything default.
- InputTextFlagsNone = 0
- // InputTextFlagsCharsDecimal allows 0123456789.+-
- InputTextFlagsCharsDecimal = 1 << 0
- // InputTextFlagsCharsHexadecimal allow 0123456789ABCDEFabcdef
- InputTextFlagsCharsHexadecimal = 1 << 1
- // InputTextFlagsCharsUppercase turns a..z into A..Z.
- InputTextFlagsCharsUppercase = 1 << 2
- // InputTextFlagsCharsNoBlank filters out spaces, tabs.
- InputTextFlagsCharsNoBlank = 1 << 3
- // InputTextFlagsAutoSelectAll selects entire text when first taking mouse focus.
- InputTextFlagsAutoSelectAll = 1 << 4
- // InputTextFlagsEnterReturnsTrue returns 'true' when Enter is pressed (as opposed to when the value was modified).
- InputTextFlagsEnterReturnsTrue = 1 << 5
- // InputTextFlagsCallbackCompletion for callback on pressing TAB (for completion handling).
- InputTextFlagsCallbackCompletion = 1 << 6
- // InputTextFlagsCallbackHistory for callback on pressing Up/Down arrows (for history handling).
- InputTextFlagsCallbackHistory = 1 << 7
- // InputTextFlagsCallbackAlways for callback on each iteration. User code may query cursor position, modify text buffer.
- InputTextFlagsCallbackAlways = 1 << 8
- // InputTextFlagsCallbackCharFilter for callback on character inputs to replace or discard them.
- // Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
- InputTextFlagsCallbackCharFilter = 1 << 9
- // InputTextFlagsAllowTabInput when pressing TAB to input a '\t' character into the text field.
- InputTextFlagsAllowTabInput = 1 << 10
- // InputTextFlagsCtrlEnterForNewLine in multi-line mode, unfocus with Enter, add new line with Ctrl+Enter
- // (default is opposite: unfocus with Ctrl+Enter, add line with Enter).
- InputTextFlagsCtrlEnterForNewLine = 1 << 11
- // InputTextFlagsNoHorizontalScroll disables following the cursor horizontally.
- InputTextFlagsNoHorizontalScroll = 1 << 12
- // InputTextFlagsAlwaysInsertMode sets insert mode.
- InputTextFlagsAlwaysInsertMode = 1 << 13
- // InputTextFlagsReadOnly sets read-only mode.
- InputTextFlagsReadOnly = 1 << 14
- // InputTextFlagsPassword sets password mode, display all characters as '*'.
- InputTextFlagsPassword = 1 << 15
- // InputTextFlagsNoUndoRedo disables undo/redo. Note that input text owns the text data while active,
- // if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
- InputTextFlagsNoUndoRedo = 1 << 16
- // InputTextFlagsCharsScientific allows 0123456789.+-*/eE (Scientific notation input).
- InputTextFlagsCharsScientific = 1 << 17
- // inputTextFlagsCallbackResize for callback on buffer capacity change requests.
- inputTextFlagsCallbackResize = 1 << 18
- )
- // InputTextCallback is called for sharing state of an input field.
- // By default, the callback should return 0.
- type InputTextCallback func(InputTextCallbackData) int32
- type inputTextState struct {
- buf *stringBuffer
- key C.int
- callback InputTextCallback
- }
- var inputTextStates = make(map[C.int]*inputTextState)
- var inputTextStatesMutex sync.Mutex
- func newInputTextState(text string, cb InputTextCallback) *inputTextState {
- state := &inputTextState{}
- state.buf = newStringBuffer(text)
- state.callback = cb
- state.register()
- return state
- }
- func (state *inputTextState) register() {
- inputTextStatesMutex.Lock()
- defer inputTextStatesMutex.Unlock()
- key := C.int(len(inputTextStates) + 1)
- for _, existing := inputTextStates[key]; existing; _, existing = inputTextStates[key] {
- key++
- }
- state.key = key
- inputTextStates[key] = state
- }
- func (state *inputTextState) release() {
- state.buf.free()
- if state.key != 0 {
- inputTextStatesMutex.Lock()
- defer inputTextStatesMutex.Unlock()
- delete(inputTextStates, state.key)
- }
- }
- func (state *inputTextState) onCallback(handle C.IggInputTextCallbackData) C.int {
- data := InputTextCallbackData{state: state, handle: handle}
- if data.EventFlag() == inputTextFlagsCallbackResize {
- state.buf.resizeTo(data.bufSize())
- data.setBuf(state.buf.ptr, state.buf.size, data.bufTextLen())
- return 0
- }
- if state.callback == nil {
- return 0
- }
- return C.int(state.callback(data))
- }
- //export iggInputTextCallback
- func iggInputTextCallback(handle C.IggInputTextCallbackData, key C.int) C.int {
- state := iggInputTextStateFor(key)
- return state.onCallback(handle)
- }
- func iggInputTextStateFor(key C.int) *inputTextState {
- inputTextStatesMutex.Lock()
- defer inputTextStatesMutex.Unlock()
- return inputTextStates[key]
- }
- // InputTextCallbackData represents the shared state of InputText(), passed as an argument to your callback.
- type InputTextCallbackData struct {
- state *inputTextState
- handle C.IggInputTextCallbackData
- }
- // EventFlag returns one of the InputTextFlagsCallback* constants to indicate the nature of the callback.
- func (data InputTextCallbackData) EventFlag() int {
- return int(C.iggInputTextCallbackDataGetEventFlag(data.handle))
- }
- // Flags returns the set of flags that the user originally passed to InputText.
- func (data InputTextCallbackData) Flags() int {
- return int(C.iggInputTextCallbackDataGetFlags(data.handle)) & ^inputTextFlagsCallbackResize
- }
- // EventChar returns the current character input. Only valid during CharFilter callback.
- func (data InputTextCallbackData) EventChar() rune {
- return rune(C.iggInputTextCallbackDataGetEventChar(data.handle))
- }
- // SetEventChar overrides what the user entered. Set to zero do drop the current input.
- // Returning 1 from the callback also drops the current input.
- // Only valid during CharFilter callback.
- //
- // Note: The internal representation of characters is based on uint16, so less than rune would provide.
- func (data InputTextCallbackData) SetEventChar(value rune) {
- C.iggInputTextCallbackDataSetEventChar(data.handle, C.ushort(value))
- }
- // EventKey returns the currently pressed key. Valid for completion and history callbacks.
- func (data InputTextCallbackData) EventKey() int {
- return int(C.iggInputTextCallbackDataGetEventKey(data.handle))
- }
- // Buffer returns a view into the current UTF-8 buffer.
- // Only during the callbacks of [Completion,History,Always] the current buffer is returned.
- // The returned slice is a temporary view into the underlying raw buffer. Do not keep it!
- // The underlying memory allocation may even change through a call to InsertBytes().
- //
- // You may change the buffer through the following ways:
- // If the new text has a different (encoded) length, use the functions InsertBytes() and/or DeleteBytes().
- // Otherwise you may keep the buffer as is and modify the bytes. If you change the buffer this way directly, mark the buffer
- // as modified with MarkBufferModified().
- func (data InputTextCallbackData) Buffer() []byte {
- ptr := C.iggInputTextCallbackDataGetBuf(data.handle)
- if ptr == nil {
- return nil
- }
- textLen := data.bufTextLen()
- return ((*[1 << 30]byte)(unsafe.Pointer(ptr)))[:textLen]
- }
- // MarkBufferModified indicates that the content of the buffer was modified during a callback.
- // Only considered during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) MarkBufferModified() {
- C.iggInputTextCallbackDataMarkBufferModified(data.handle)
- }
- func (data InputTextCallbackData) setBuf(buf unsafe.Pointer, size, textLen int) {
- C.iggInputTextCallbackDataSetBuf(data.handle, (*C.char)(buf), C.int(size), C.int(textLen))
- }
- func (data InputTextCallbackData) bufSize() int {
- return int(C.iggInputTextCallbackDataGetBufSize(data.handle))
- }
- func (data InputTextCallbackData) bufTextLen() int {
- return int(C.iggInputTextCallbackDataGetBufTextLen(data.handle))
- }
- // DeleteBytes removes the given count of bytes starting at the specified byte offset within the buffer.
- // This function can be called during the [Completion,History,Always] callbacks.
- // Clears the current selection.
- //
- // This function ignores the deletion beyond the current buffer length.
- // Calling with negative offset or count arguments will panic.
- func (data InputTextCallbackData) DeleteBytes(offset, count int) {
- if offset < 0 {
- panic("invalid offset")
- }
- if count < 0 {
- panic("invalid count")
- }
- textLen := data.bufTextLen()
- if offset >= textLen {
- return
- }
- toRemove := count
- available := textLen - offset
- if toRemove > available {
- toRemove = available
- }
- C.iggInputTextCallbackDataDeleteBytes(data.handle, C.int(offset), C.int(toRemove))
- }
- // InsertBytes inserts the given bytes at given byte offset into the buffer.
- // Calling this function may change the underlying buffer allocation.
- //
- // This function can be called during the [Completion,History,Always] callbacks.
- // Clears the current selection.
- //
- // Calling with an offset outside of the range of the buffer will panic.
- func (data InputTextCallbackData) InsertBytes(offset int, bytes []byte) {
- if (offset < 0) || (offset > data.bufTextLen()) {
- panic("invalid offset")
- }
- var bytesPtr *C.char
- byteCount := len(bytes)
- if byteCount > 0 {
- bytesPtr = (*C.char)(unsafe.Pointer(&bytes[0]))
- C.iggInputTextCallbackDataInsertBytes(data.handle, C.int(offset), bytesPtr, C.int(byteCount))
- }
- }
- // CursorPos returns the byte-offset of the cursor within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) CursorPos() int {
- return int(C.iggInputTextCallbackDataGetCursorPos(data.handle))
- }
- // SetCursorPos changes the current byte-offset of the cursor within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) SetCursorPos(value int) {
- C.iggInputTextCallbackDataSetCursorPos(data.handle, C.int(value))
- }
- // SelectionStart returns the byte-offset of the selection start within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) SelectionStart() int {
- return int(C.iggInputTextCallbackDataGetSelectionStart(data.handle))
- }
- // SetSelectionStart changes the current byte-offset of the selection start within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) SetSelectionStart(value int) {
- C.iggInputTextCallbackDataSetSelectionStart(data.handle, C.int(value))
- }
- // SelectionEnd returns the byte-offset of the selection end within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) SelectionEnd() int {
- return int(C.iggInputTextCallbackDataGetSelectionEnd(data.handle))
- }
- // SetSelectionEnd changes the current byte-offset of the selection end within the buffer.
- // Only valid during [Completion,History,Always] callbacks.
- func (data InputTextCallbackData) SetSelectionEnd(value int) {
- C.iggInputTextCallbackDataSetSelectionEnd(data.handle, C.int(value))
- }
|