jaar23 / tui_widget

terminal ui widget based on illwill
14 stars 1 forks source link

Feature request: Dropdown widget #7

Open sgmihai opened 2 weeks ago

sgmihai commented 2 weeks ago

If not too hard to implement. It seems to be missing from the other widget library as well. I planned on trying to make a simple TUI for qemu, something like this: https://github.com/nemuTUI/nemu And dropdown selection would be nice to have when selecting certain parameters of a predefined list. "nemu" uses left/right keys to scroll between possible elements in the textbox, but I think a dropdown would be nicer. Any suggestions are welcomed. Thanks for the contribution btw, I've been waiting for something like this for a long time.

jaar23 commented 2 weeks ago

I have tried building a dropdown widget earlier and abandoned it due to difficulties when calculating a dropdown being placed at the corner of the terminal. I changed the approach a bit by using list view as a drop down instead. You can implement action on the listview item, when enter key trigger, it would fire the event. That would have a up, down, left, right cursor movements as well.

sgmihai commented 2 weeks ago

Do you have an example of this approach somewhere, of using listview as drop down? not very clear from the description. Also, do you have any suggestion on how to implement something like a new window with labels + input fields, like https://i.imgur.com/O5AAaak.png - This is where I would have used dropdowns for selections. I was thinking to use a container for the right side of the screen, and then another container for the form entry part. But how do you delete a container and its widgets, when you are done with it ? Perhaps a new window widget would be useful here, that takes focus entirely until closed. What tui library did you use to model this ? I find it hard to conceive this from scratch.

jaar23 commented 2 weeks ago

You can refer to the test folder for example. Basically what i mean is that listview with action on listitem is similar to a dropdown too.

var list = newSeq[ListRow]()
var i = 0
const keys = {Key.A..Key.Z}

for key in keys:
  var listRow = newListRow(i, $key, $key)
  list.add(listRow)

let selectEv = proc(lv: ListView, args: varargs[string]) =
  # perform something
  # write to a file or so..

var listview = newListView(1, 38, consoleWidth(), 48, rows=list, title="list", bgColor=bgBlue, selectionStyle=HighlightArrow)

listView.onEnter = selectEv

If you check out the gif at the current readme, around list section, it give a preview for you.

The container widget could use for a new windows or prompt kind of usage too, refers to tests/container_test.nim, but i'm not sure if that fullfill what your needs.

For this question

I was thinking to use a container for the right side of the screen, and then another container for the form entry part. But how do you delete a container and its widgets, when you are done with it ? Perhaps a new window widget would be useful here, that takes focus entirely until closed.

you can set false on the widget visibility. Or more dynamic way, is to add a widget by event. One example for this will be the help window on every widget.

# create an event function
proc help(table: Table, args: varargs[string]) = 
  let wsize = ((table.width - table.posX).toFloat * 0.3).toInt()
  let hsize = ((table.height - table.posY).toFloat * 0.3).toInt()

  # init a new widget within the function
  var display = newDisplay(table.x2 - wsize, table.y2 - hsize, 
                          table.x2, table.y2, title="help",
                          bgColor=bgWhite, fgColor=fgBlack,
                          tb=table.tb, statusbar=false,
                          enableHelp=false)
  var helpText: string
  if table.helpText == "":
    helpText = " [Enter] to select\n" &
               " [/]     to search\n" &
               " [?]     for help\n" &
               " [Tab]   to go next widget\n" &
               " [Esc]   to exit this window"

  display.text = helpText

  # init the terminal buffer
  display.illwillInit = true

  # give control on this immediate widget
  display.onControl()

  # clear view on exit
  display.clear()
....
....
# register the help event with ?
table.on(Key.QuestionMark, help)

The example above is getting from table widget, it is integrate with display widget, show it when there is an event trigger.

I have considered Elm architecture when working on this tui_widget plugin, the underneath tui library is https://github.com/johnnovak/illwill

jaar23 commented 2 weeks ago

may be checkout dir example too. it may give you some basic concept how it is being layout and modify it to become what you want to achieve dir-demo

btw, the navigation method currently is by [tab] button and more towards keyboard usage.