fileselectdlg.go
func CreateFileSelectDialog(title, fileMasks, initPath string, selectDir, mustExist bool) *FileSelectDialog {
	dlg := new(FileSelectDialog)
	cw, ch := term.Size()
	dlg.selectDir = selectDir
	dlg.mustExist = mustExist

	if fileMasks != "" {
		maskList := strings.FieldsFunc(fileMasks,
			func(c rune) bool { return c == ',' || c == ':' })
		dlg.fileMasks = make([]string, 0, len(maskList))
		for _, m := range maskList {
			if m != "" {
				dlg.fileMasks = append(dlg.fileMasks, m)
			}
		}
	}

	dlg.View = AddWindow(10, 4, 20, 16, fmt.Sprintf("%s (%s)", title, fileMasks))
	WindowManager().BeginUpdate()
	defer WindowManager().EndUpdate()

	dlg.View.SetModal(true)
	dlg.View.SetPack(Vertical)

	dlg.currPath = initPath
	dlg.detectPath()
	dlg.curDir = CreateLabel(dlg.View, AutoSize, AutoSize, "", Fixed)
	dlg.curDir.SetTextDisplay(AlignRight)

	flist := CreateFrame(dlg.View, 1, 1, BorderNone, 1)
	flist.SetPaddings(1, 1)
	flist.SetPack(Horizontal)
	dlg.listBox = CreateListBox(flist, 16, ch-20, 1)

	fselected := CreateFrame(dlg.View, 1, 1, BorderNone, Fixed)
	// text + edit field to enter name manually
	fselected.SetPack(Vertical)
	fselected.SetPaddings(1, 0)
	CreateLabel(fselected, AutoSize, AutoSize, "Selected object:", 1)
	dlg.edFile = CreateEditField(fselected, cw-22, "", 1)

	// buttons at the right
	blist := CreateFrame(flist, 1, 1, BorderNone, Fixed)
	blist.SetPack(Vertical)
	blist.SetPaddings(1, 1)
	btnOpen := CreateButton(blist, AutoSize, AutoSize, "Open", Fixed)
	btnSelect := CreateButton(blist, AutoSize, AutoSize, "Select", Fixed)
	btnCancel := CreateButton(blist, AutoSize, AutoSize, "Cancel", Fixed)

	btnCancel.OnClick(func(ev Event) {
		WindowManager().DestroyWindow(dlg.View)
		WindowManager().BeginUpdate()
		dlg.Selected = false
		closeFunc := dlg.onClose
		WindowManager().EndUpdate()
		if closeFunc != nil {
			closeFunc()
		}
	})

	btnSelect.OnClick(func(ev Event) {
		WindowManager().DestroyWindow(dlg.View)
		WindowManager().BeginUpdate()
		dlg.Selected = true

		dlg.FilePath = filepath.Join(dlg.currPath, dlg.listBox.SelectedItemText())
		if dlg.edFile.Title() != "" {
			dlg.FilePath = filepath.Join(dlg.currPath, dlg.edFile.Title())
		}
		_, err := os.Stat(dlg.FilePath)
		dlg.Exists = !os.IsNotExist(err)

		closeFunc := dlg.onClose
		WindowManager().EndUpdate()
		if closeFunc != nil {
			closeFunc()
		}
	})

	dlg.View.OnClose(func(ev Event) bool {
		if dlg.result == DialogAlive {
			dlg.result = DialogClosed
			if ev.X != 1 {
				WindowManager().DestroyWindow(dlg.View)
			}
			if dlg.onClose != nil {
				dlg.onClose()
			}
		}
		return true
	})

	dlg.listBox.OnSelectItem(func(ev Event) {
		item := ev.Msg
		if item == ".." {
			btnSelect.SetEnabled(false)
			btnOpen.SetEnabled(true)
			return
		}
		isDir := strings.HasSuffix(item, string(os.PathSeparator))
		if isDir {
			btnOpen.SetEnabled(true)
			if !dlg.selectDir {
				btnSelect.SetEnabled(false)
				return
			}
		}
		if !isDir {
			btnOpen.SetEnabled(false)
		}

		btnSelect.SetEnabled(true)
		if (isDir && dlg.selectDir) || !isDir {
			dlg.edFile.SetTitle(item)
		} else {
			dlg.edFile.Clear()
		}
	})

	btnOpen.OnClick(func(ev Event) {
		s := dlg.listBox.SelectedItemText()
		if s != ".." && (s == "" || !strings.HasSuffix(s, string(os.PathSeparator))) {
			return
		}

		if s == ".." {
			dlg.pathUp()
		} else {
			dlg.pathDown(s)
		}
	})

	dlg.edFile.OnChange(func(ev Event) {
		s := ""
		lowCurrText := strings.ToLower(dlg.listBox.SelectedItemText())
		lowEditText := strings.ToLower(dlg.edFile.Title())
		if !strings.HasPrefix(lowCurrText, lowEditText) {
			itemIdx := dlg.listBox.PartialFindItem(dlg.edFile.Title(), false)
			if itemIdx == -1 {
				if dlg.mustExist {
					btnSelect.SetEnabled(false)
				}
				return
			}

			s, _ = dlg.listBox.Item(itemIdx)
			dlg.listBox.SelectItem(itemIdx)
		} else {
			s = dlg.listBox.SelectedItemText()
		}

		isDir := strings.HasSuffix(s, string(os.PathSeparator))
		equal := strings.EqualFold(s, dlg.edFile.Title()) ||
			strings.EqualFold(s, dlg.edFile.Title()+string(os.PathSeparator))

		btnOpen.SetEnabled(isDir || s == "..")
		if isDir {
			btnSelect.SetEnabled(dlg.selectDir && (equal || !dlg.mustExist))
			return
		}

		btnSelect.SetEnabled(equal || !dlg.mustExist)
	})

	dlg.edFile.OnKeyPress(func(key term.Key, c rune) bool {
		if key == term.KeyArrowUp {
			idx := dlg.listBox.SelectedItem()
			if idx > 0 {
				dlg.listBox.SelectItem(idx - 1)
				dlg.updateEditBox()
			}
			return true
		}
		if key == term.KeyArrowDown {
			idx := dlg.listBox.SelectedItem()
			if idx < dlg.listBox.ItemCount()-1 {
				dlg.listBox.SelectItem(idx + 1)
				dlg.updateEditBox()
			}
			return true
		}

		return false
	})

	dlg.listBox.OnKeyPress(func(key term.Key) bool {
		if key == term.KeyBackspace || key == term.KeyBackspace2 {
			dlg.pathUp()
			return true
		}

		if key == term.KeyCtrlM {
			s := dlg.listBox.SelectedItemText()
			if s == ".." {
				dlg.pathUp()
				return true
			}

			if strings.HasSuffix(s, string(os.PathSeparator)) {
				dlg.pathDown(s)
				return true
			}

			return false
		}

		return false
	})

	dlg.curDir.SetTitle(dlg.currPath)
	dlg.populateFiles()
	dlg.selectFirst()

	ActivateControl(dlg.View, dlg.listBox)
	return dlg
}
func CreateFileSelectDialog(title, fileMasks, initPath string, selectDir, mustExist bool) *FileSelectDialog {
	dlg := new(FileSelectDialog)
	cw, ch := term.Size()
	dlg.selectDir = selectDir
	dlg.mustExist = mustExist

	if fileMasks != "" {
		maskList := strings.FieldsFunc(fileMasks,
			func(c rune) bool { return c == ',' || c == ':' })
		dlg.fileMasks = make([]string, 0, len(maskList))
		for _, m := range maskList {
			if m != "" {
				dlg.fileMasks = append(dlg.fileMasks, m)
			}
		}
	}

	dlg.View = AddWindow(10, 4, 20, 16, fmt.Sprintf("%s (%s)", title, fileMasks))
	WindowManager().BeginUpdate()
	defer WindowManager().EndUpdate()

	dlg.View.SetModal(true)
	dlg.View.SetPack(Vertical)

	dlg.currPath = initPath
	dlg.detectPath()
	dlg.curDir = CreateLabel(dlg.View, AutoSize, AutoSize, "", Fixed)
	dlg.curDir.SetTextDisplay(AlignRight)

	flist := CreateFrame(dlg.View, 1, 1, BorderNone, 1)
	flist.SetPaddings(1, 1)
	flist.SetPack(Horizontal)
	dlg.listBox = CreateListBox(flist, 16, ch-20, 1)

	fselected := CreateFrame(dlg.View, 1, 1, BorderNone, Fixed)
	// text + edit field to enter name manually
	fselected.SetPack(Vertical)
	fselected.SetPaddings(1, 0)
	CreateLabel(fselected, AutoSize, AutoSize, "Selected object:", 1)
	dlg.edFile = CreateEditField(fselected, cw-22, "", 1)

	// buttons at the right
	blist := CreateFrame(flist, 1, 1, BorderNone, Fixed)
	blist.SetPack(Vertical)
	blist.SetPaddings(1, 1)
	btnOpen := CreateButton(blist, AutoSize, AutoSize, "Open", Fixed)
	btnSelect := CreateButton(blist, AutoSize, AutoSize, "Select", Fixed)
	btnCancel := CreateButton(blist, AutoSize, AutoSize, "Cancel", Fixed)

	btnCancel.OnClick(func(ev Event) {
		WindowManager().DestroyWindow(dlg.View)
		WindowManager().BeginUpdate()
		dlg.Selected = false
		closeFunc := dlg.onClose
		WindowManager().EndUpdate()
		if closeFunc != nil {
			closeFunc()
		}
	})

	btnSelect.OnClick(func(ev Event) {
		WindowManager().DestroyWindow(dlg.View)
		WindowManager().BeginUpdate()
		dlg.Selected = true

		dlg.FilePath = filepath.Join(dlg.currPath, dlg.listBox.SelectedItemText())
		if dlg.edFile.Title() != "" {
			dlg.FilePath = filepath.Join(dlg.currPath, dlg.edFile.Title())
		}
		_, err := os.Stat(dlg.FilePath)
		dlg.Exists = !os.IsNotExist(err)

		closeFunc := dlg.onClose
		WindowManager().EndUpdate()
		if closeFunc != nil {
			closeFunc()
		}
	})

	dlg.View.OnClose(func(ev Event) bool {
		if dlg.result == DialogAlive {
			dlg.result = DialogClosed
			if ev.X != 1 {
				WindowManager().DestroyWindow(dlg.View)
			}
			if dlg.onClose != nil {
				dlg.onClose()
			}
		}
		return true
	})

	dlg.listBox.OnSelectItem(func(ev Event) {
		item := ev.Msg
		if item == ".." {
			btnSelect.SetEnabled(false)
			btnOpen.SetEnabled(true)
			return
		}
		isDir := strings.HasSuffix(item, string(os.PathSeparator))
		if isDir {
			btnOpen.SetEnabled(true)
			if !dlg.selectDir {
				btnSelect.SetEnabled(false)
				return
			}
		}
		if !isDir {
			btnOpen.SetEnabled(false)
		}

		btnSelect.SetEnabled(true)
		if (isDir && dlg.selectDir) || !isDir {
			dlg.edFile.SetTitle(item)
		} else {
			dlg.edFile.Clear()
		}
	})

	btnOpen.OnClick(func(ev Event) {
		s := dlg.listBox.SelectedItemText()
		if s != ".." && (s == "" || !strings.HasSuffix(s, string(os.PathSeparator))) {
			return
		}

		if s == ".." {
			dlg.pathUp()
		} else {
			dlg.pathDown(s)
		}
	})

	dlg.edFile.OnChange(func(ev Event) {
		s := ""
		lowCurrText := strings.ToLower(dlg.listBox.SelectedItemText())
		lowEditText := strings.ToLower(dlg.edFile.Title())
		if !strings.HasPrefix(lowCurrText, lowEditText) {
			itemIdx := dlg.listBox.PartialFindItem(dlg.edFile.Title(), false)
			if itemIdx == -1 {
				if dlg.mustExist {
					btnSelect.SetEnabled(false)
				}
				return
			}

			s, _ = dlg.listBox.Item(itemIdx)
			dlg.listBox.SelectItem(itemIdx)
		} else {
			s = dlg.listBox.SelectedItemText()
		}

		isDir := strings.HasSuffix(s, string(os.PathSeparator))
		equal := strings.EqualFold(s, dlg.edFile.Title()) ||
			strings.EqualFold(s, dlg.edFile.Title()+string(os.PathSeparator))

		btnOpen.SetEnabled(isDir || s == "..")
		if isDir {
			btnSelect.SetEnabled(dlg.selectDir && (equal || !dlg.mustExist))
			return
		}

		btnSelect.SetEnabled(equal || !dlg.mustExist)
	})

	dlg.edFile.OnKeyPress(func(key term.Key, c rune) bool {
		if key == term.KeyArrowUp {
			idx := dlg.listBox.SelectedItem()
			if idx > 0 {
				dlg.listBox.SelectItem(idx - 1)
				dlg.updateEditBox()
			}
			return true
		}
		if key == term.KeyArrowDown {
			idx := dlg.listBox.SelectedItem()
			if idx < dlg.listBox.ItemCount()-1 {
				dlg.listBox.SelectItem(idx + 1)
				dlg.updateEditBox()
			}
			return true
		}

		return false
	})

	dlg.listBox.OnKeyPress(func(key term.Key) bool {
		if key == term.KeyBackspace || key == term.KeyBackspace2 {
			dlg.pathUp()
			return true
		}

		if key == term.KeyCtrlM {
			s := dlg.listBox.SelectedItemText()
			if s == ".." {
				dlg.pathUp()
				return true
			}

			if strings.HasSuffix(s, string(os.PathSeparator)) {
				dlg.pathDown(s)
				return true
			}

			return false
		}

		return false
	})

	dlg.curDir.SetTitle(dlg.currPath)
	dlg.populateFiles()
	dlg.selectFirst()

	ActivateControl(dlg.View, dlg.listBox)
	return dlg
}
// CreateFileSelectDialog creates a new file select dialog. It is useful if
// the application needs a way to select a file or directory for reading and
// writing data.
//  * title - custom dialog title (the final dialog title includes this one
//      and the file mask
//  * fileMasks - a list of file masks separated with comma or path separator.
//      If selectDir is true this option is not used. Setting fileMasks to
//      '*', '*.*', or empty string means all files
//  * selectDir - what kind of object to select: file (false) or directory
//      (true). If selectDir is true then the dialog does not show files
//  * mustExists - if it is true then the dialog allows a user to select
//       only existing object ('open file' case). If it is false then the dialog
//       makes possible to enter a name manually and click 'Select' (useful
//       for file 'file save' case)