| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 | 
							- package door
 
- import (
 
- 	"log"
 
- 	"strings"
 
- 	"unicode"
 
- )
 
- /*
 
- type MenuOption struct {
 
- 	Ch   rune
 
- 	Text string
 
- }
 
- */
 
- type Menu struct {
 
- 	Chosen      int
 
- 	SelectedR   ColorRender
 
- 	UnselectedR ColorRender
 
- 	Options     []rune
 
- 	Activated   func(int, *Door) // Which option is active
 
- 	// MenuOptions []MenuOption
 
- 	Panel
 
- }
 
- func MakeMenuRender(bracketColor, optionColor, upperColor, lowerColor string) ColorRender {
 
- 	f := func(text string) string {
 
- 		var output string
 
- 		var lastColor string
 
- 		option := true
 
- 		for _, c := range text {
 
- 			if option {
 
- 				if c == '[' || c == ']' {
 
- 					if lastColor != bracketColor {
 
- 						output += bracketColor
 
- 						lastColor = bracketColor
 
- 					}
 
- 					output += string(c)
 
- 					option = (c == '[')
 
- 				} else {
 
- 					if lastColor != optionColor {
 
- 						output += optionColor
 
- 						lastColor = optionColor
 
- 					}
 
- 					output += string(c)
 
- 				}
 
- 			} else {
 
- 				if unicode.IsUpper(c) {
 
- 					if lastColor != upperColor {
 
- 						output += upperColor
 
- 						lastColor = upperColor
 
- 					}
 
- 					output += string(c)
 
- 				} else {
 
- 					if lastColor != lowerColor {
 
- 						output += lowerColor
 
- 						lastColor = lowerColor
 
- 					}
 
- 					output += string(c)
 
- 				}
 
- 			}
 
- 		}
 
- 		return output
 
- 	}
 
- 	return f
 
- }
 
- func (m *Menu) AddSelection(key string, text string) {
 
- 	key = key[:1] // Make sure it is just 1 character
 
- 	m.Options = append(m.Options, rune(key[0]))
 
- 	// 4 = [ key ] + " "
 
- 	if len(text)+4 > m.Width {
 
- 		log.Panicf("Menu (not wide enough) Width %d : text size %d + 4 = %d\n", m.Width, len(text), len(text)+4)
 
- 	}
 
- 	linetext := "[" + key + "] " + text + strings.Repeat(" ", m.Width-(4+len(text)))
 
- 	m.Lines = append(m.Lines, Line{Text: linetext, RenderF: m.UnselectedR})
 
- }
 
- // Should I be using this, or write a function like the original --
 
- // m.AddSelection("K", "Text") to build?  (And throw away the
 
- // redundant) MenuOptions/MenuOption parts?  They do let me create
 
- // the menu in larger chunks -- but it is redundant.
 
- // Once the menu is built, I really could delete the MenuOptions.
 
- /*
 
- func (m *Menu) Build() {
 
- 	// Take MenuOptions and build the Menu
 
- 	// Reset
 
- 	m.Lines = make([]Line, 0)
 
- 	m.Options = make([]rune, 0)
 
- 	m.Chosen = 0
 
- 	for _, option := range m.MenuOptions {
 
- 		m.Options = append(m.Options, option.Ch)
 
- 		text := "[" + string(option.Ch) + "] " + option.Text + strings.Repeat(" ", m.Width-(4+len(option.Text)))
 
- 		m.Lines = append(m.Lines, Line{Text: text, RenderF: m.UnselectedR})
 
- 	}
 
- }
 
- */
 
- // Get the character that was pressed from the choice
 
- func (m *Menu) GetOption(choice int) rune {
 
- 	return m.Options[choice-1]
 
- }
 
- func (m *Menu) Choose(d *Door) int {
 
- 	var changed []int
 
- 	updated := true
 
- 	update_and_exit := false
 
- 	blank := ColorText("BLACK")
 
- 	for {
 
- 		if updated {
 
- 			for x := range m.Lines {
 
- 				if x == m.Chosen {
 
- 					m.Lines[x].RenderF = m.SelectedR
 
- 				} else {
 
- 					m.Lines[x].RenderF = m.UnselectedR
 
- 				}
 
- 			}
 
- 			if len(changed) == 0 {
 
- 				d.Write(m.Output() + blank)
 
- 			} else {
 
- 				// Update just the lines that have changed
 
- 				for _, line := range changed {
 
- 					d.Write(m.UpdateLine(line))
 
- 				}
 
- 				d.Write(m.GotoEnd() + blank)
 
- 			}
 
- 			if m.Activated != nil {
 
- 				m.Activated(m.Chosen, d)
 
- 				// Reposition to the end of the menu
 
- 				d.Write(m.GotoEnd() + blank)
 
- 			}
 
- 		}
 
- 		if update_and_exit {
 
- 			return m.Chosen + 1
 
- 		}
 
- 		updated = false
 
- 		var r rune
 
- 		var ex Extended
 
- 		var err error
 
- 		r, ex, err = d.WaitKey(DefaultTimeout)
 
- 		if err != nil {
 
- 			return -1
 
- 		}
 
- 		previous_choice := m.Chosen
 
- 		changed = make([]int, 0)
 
- 		use_numberpad := true
 
- 		for _, option := range m.Options {
 
- 			if option == rune('8') || option == rune('2') {
 
- 				use_numberpad = false
 
- 			}
 
- 		}
 
- 		if ex == MOUSE {
 
- 			mouse, ok := d.GetMouse()
 
- 			if ok {
 
- 				if mouse.Button == 65 {
 
- 					// Translate Mouse Wheel Up
 
- 					ex = UP_ARROW
 
- 				}
 
- 				if mouse.Button == 66 {
 
- 					// Translate Mouse Wheel Down
 
- 					ex = DOWN_ARROW
 
- 				}
 
- 				// Look at Mouse X/Y to determine where they clicked
 
- 				if mouse.Button == 1 || mouse.Button == 2 {
 
- 					// TODO: log.Println("Mouse (", mouse.X, ",", mouse.Y, ")")
 
- 					clicked, cx, cy := m.Panel.Within(int(mouse.X), int(mouse.Y))
 
- 					log.Printf("%t : (%d, %d)\n", clicked, cx, cy)
 
- 					if clicked {
 
- 						if m.Panel.HasBorder() {
 
- 							// Did they click the border?
 
- 							if cy > 0 && cy <= m.Panel.Length() {
 
- 								updated = true
 
- 								m.Chosen = cy - 1
 
- 								update_and_exit = true
 
- 							}
 
- 						} else {
 
- 							// Borderless -- yes, they clicked something!
 
- 							updated = true
 
- 							m.Chosen = cy
 
- 							update_and_exit = true
 
- 						}
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 		switch ex {
 
- 		case UP_ARROW:
 
- 			if m.Chosen > 0 {
 
- 				m.Chosen--
 
- 				updated = true
 
- 			}
 
- 		case DOWN_ARROW:
 
- 			if m.Chosen < len(m.Lines)-1 {
 
- 				m.Chosen++
 
- 				updated = true
 
- 			}
 
- 		case HOME:
 
- 			if m.Chosen != 0 {
 
- 				m.Chosen = 0
 
- 				updated = true
 
- 			}
 
- 		case END:
 
- 			if m.Chosen != len(m.Lines)-1 {
 
- 				m.Chosen = len(m.Lines) - 1
 
- 				updated = true
 
- 			}
 
- 		}
 
- 		switch r {
 
- 		case '8':
 
- 			if use_numberpad {
 
- 				if m.Chosen > 0 {
 
- 					m.Chosen--
 
- 					updated = true
 
- 				}
 
- 			}
 
- 		case '2':
 
- 			if use_numberpad {
 
- 				if m.Chosen < len(m.Lines)-1 {
 
- 					m.Chosen++
 
- 					updated = true
 
- 				}
 
- 			}
 
- 		case 0x0d:
 
- 			// use current selection
 
- 			return m.Chosen + 1
 
- 		default:
 
- 			// Is the key in the list of options?
 
- 			// fmt.Printf("Event: %d\n", event)
 
- 			for x, option := range m.Options {
 
- 				// fmt.Printf("Checking %d, %d\n", x, option)
 
- 				if unicode.ToUpper(option) == unicode.ToUpper(r) {
 
- 					if m.Chosen == x {
 
- 						return x + 1
 
- 					}
 
- 					updated = true
 
- 					m.Chosen = x
 
- 					update_and_exit = true
 
- 				}
 
- 			}
 
- 		}
 
- 		if previous_choice != m.Chosen {
 
- 			changed = append(changed, previous_choice)
 
- 			changed = append(changed, m.Chosen)
 
- 			updated = true
 
- 		}
 
- 	}
 
- }
 
 
  |