2024-02-19 17:02:19 +01:00

316 lines
8.1 KiB
VimL

"======================================================================
"
" confirm.vim -
"
" Created by skywind on 2021/12/11
" Last Modified: 2021/12/13 22:07
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" build buttons
"----------------------------------------------------------------------
function! s:button_prepare(choices)
let choices = quickui#utils#text_list_normalize(a:choices)
let items = []
let index = 0
let max_size = 4
for choice in choices
let item = quickui#utils#item_parse(choice)
let item.index = index
let items += [item]
let width = item.text_width
let max_size = (max_size < width)? width : max_size
let index += 1
endfor
for item in items
let width = item.text_width
let pad1 = (max_size - width) / 2
let pad2 = max_size - width - pad1
" let pad1 += 1
" let pad2 += 1
let item.text = repeat(' ', pad1) . item.text . repeat(' ', pad2)
if item.key_pos >= 0
let item.key_pos += pad1
endif
let item.text_width = strwidth(item.text)
endfor
return items
endfunc
"----------------------------------------------------------------------
" synthesis button line
"----------------------------------------------------------------------
function! s:button_finalize(items, style)
let items = a:items
let final = ''
let start = 0
let index = len(a:items) - 1
for item in a:items
if 0
let text = ' ' . item.text . ' '
else
let text = '<' . item.text . '>'
endif
let item.offset = -1
let need = 0
if 0
let need = 1
let text = '[' . text . ']'
endif
if item.key_pos >= 0
let item.offset = start + 1 + item.key_pos + need
endif
let item.start = start
let item.endup = start + item.text_width + 2 + need * 2
let start += item.text_width + 2 + need * 2
let final .= text
if index > 0
let final .= ' '
let start += 2
endif
let index -= 1
endfor
return final
endfunc
"----------------------------------------------------------------------
" create highlight
"----------------------------------------------------------------------
function! s:hl_prepare(hwnd)
let hwnd = a:hwnd
let c1 = get(g:, 'quickui_button_color_on', 'QuickSel')
let c2 = get(g:, 'quickui_button_color_off', 'QuickBG')
let ck = get(g:, 'quickui_button_color_key', 'QuickKey')
let hwnd.color_on = c1
let hwnd.color_off = c2
let hwnd.color_on2 = 'QuickButtonOn2'
let hwnd.color_off2 = 'QuickButtonOff2'
call quickui#highlight#clear('QuickBUttonOn2')
call quickui#highlight#clear('QuickBUttonOff2')
if 0
call quickui#highlight#overlay('QuickButtonOn2', c1, ck)
call quickui#highlight#overlay('QuickButtonOff2', c2, ck)
else
call quickui#highlight#make_underline('QuickButtonOn2', c1)
call quickui#highlight#make_underline('QuickButtonOff2', c2)
endif
endfunc
"----------------------------------------------------------------------
" calculate requirements
"----------------------------------------------------------------------
function! s:init(text, choices, index, title)
let hwnd = {}
let hwnd.text = quickui#utils#text_list_normalize(a:text)
let hwnd.items = s:button_prepare(a:choices)
let hwnd.final = s:button_finalize(hwnd.items, 0)
let hwnd.index = a:index
let button = ''
let text_size = 40
for text in hwnd.text
let ts = strdisplaywidth(text)
let text_size = (text_size < ts)? ts : text_size
endfor
let limit = &columns * 80 / 100
let limit = get(g:, 'quickui_confirm_max_width', limit)
let text_size = (text_size < limit)? text_size : limit
let hwnd.btn_size = strdisplaywidth(hwnd.final)
let hwnd.text_size = text_size
let hwnd.w = (hwnd.btn_size > text_size)? hwnd.btn_size : text_size
let hwnd.h = len(hwnd.text) + 3
let hwnd.tw = hwnd.w + 4
let hwnd.th = hwnd.h + 4
let border = g:quickui#style#border
let opts = {}
let opts.w = hwnd.w
let opts.h = hwnd.h
let opts.border = get(g:, 'quickui_confirm_border', border)
let opts.center = 1
let opts.title = (a:title == '')? '' : (' ' . a:title . ' ')
let opts.padding = [1, 1, 1, 1]
let opts.button = 1
let opts.wrap = 1
let hwnd.opts = opts
let content = deepcopy(hwnd.text)
let content += [' ', ' ']
let hwnd.padding = hwnd.w - hwnd.btn_size
let content += [repeat(' ', hwnd.padding) . hwnd.final]
let hwnd.content = content
let hwnd.win = quickui#window#new()
let hwnd.keymap = quickui#utils#keymap()
let index = 1
for item in hwnd.items
if item.key_pos >= 0
let ch = tolower(item.key_char)
let hwnd.keymap[ch] = 'ACCEPT:' . index
endif
let index += 1
endfor
let hwnd.keymap['h'] = 'LEFT'
let hwnd.keymap['l'] = 'RIGHT'
call s:hl_prepare(hwnd)
return hwnd
endfunc
"----------------------------------------------------------------------
"
"----------------------------------------------------------------------
function! s:draw_button(hwnd, index)
let hwnd = a:hwnd
let item = hwnd.items[a:index]
let index = a:index
let win = hwnd.win
let top = hwnd.h - 1
let off = hwnd.padding
let x = item.start
let e = item.endup
if hwnd.index == index
let c1 = hwnd.color_on
let c2 = hwnd.color_on2
" let c1 = 'QuickSel'
else
let c1 = hwnd.color_off
let c2 = hwnd.color_off2
" let c1 = 'QuickBG'
" return
endif
if item.offset < 0
call win.syntax_region(c1, off + x, top, off + e, top)
else
let u = item.offset + off
call win.syntax_region(c1, off + x, top, u, top)
call win.syntax_region(c2, u, top, u + 1, top)
call win.syntax_region(c1, u + 1, top, off + e, top)
endif
endfunc
"----------------------------------------------------------------------
" render
"----------------------------------------------------------------------
function! s:render(hwnd)
let hwnd = a:hwnd
let win = hwnd.win
let off = hwnd.padding
let top = hwnd.h - 1
let index = 0
call win.syntax_begin(1)
for item in hwnd.items
call s:draw_button(hwnd, index)
let index += 1
endfor
" call win.syntax_region(ck, 12, 0, 13, 0)
call win.syntax_end()
endfunc
"----------------------------------------------------------------------
" main entry
"----------------------------------------------------------------------
function! quickui#confirm#open(text, ...)
let choices = (a:0 < 1)? " &OK " : (a:1)
let index = (a:0 < 2)? 1 : (a:2)
let title = (a:0 < 3)? 'Confirm' : (a:3)
let choices = (choices == '')? " &OK " : choices
let hwnd = s:init(a:text, choices, index - 1, title)
let win = hwnd.win
let accept = 0
let size = len(hwnd.items)
if size == 0
return 0
endif
if has('nvim')
let hwnd.opts.focusable = 1
endif
call win.open(hwnd.content, hwnd.opts)
while 1
call s:render(hwnd)
redraw
let ch = quickui#utils#getchar(1)
if ch == "\<c-c>" || ch == "\<esc>"
let accept = 0
break
elseif ch == "\<space>" || ch == "\<cr>"
let accept = hwnd.index + 1
break
elseif win.quit != 0
let accept = 0
break
elseif ch == "\<LeftMouse>"
if has('nvim') == 0
let pos = getmousepos()
let x = pos.column - 1
let y = pos.line - 1
else
let x = v:mouse_col - 1
let y = v:mouse_lnum - 1
endif
if v:mouse_winid == win.winid
if y == hwnd.h - 1 && x >= hwnd.padding
let u = x - hwnd.padding
for item in hwnd.items
if u >= item.start && u < item.endup
let accept = item.index + 1
break
endif
endfor
if accept > 0
break
endif
endif
elseif v:mouse_winid == win.info.border_winid
if y == 0 && x == win.info.tw - 1
let accept = 0
break
endif
endif
else
let key = get(hwnd.keymap, ch, ch)
if key == 'LEFT'
let hwnd.index = (hwnd.index > 0)? (hwnd.index - 1) : 0
elseif key == 'RIGHT'
if hwnd.index < size - 1
let hwnd.index += 1
endif
elseif key == 'HOME' || key == 'UP' || key == 'PAGEUP'
let hwnd.index = 0
elseif key == 'END' || key == 'DOWN' || key == 'PAGEDOWN'
let hwnd.index = size - 1
elseif key =~ '^ACCEPT:'
let key = strpart(key, 7)
let index = str2nr(key)
if index > 0 && index <= size
let accept = index
break
endif
endif
endif
endwhile
if accept > 0 && win.quit == 0
let hwnd.index = accept - 1
call s:render(hwnd)
redraw
sleep 15m
endif
call win.close()
return accept
endfunc