testdoor.go 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "red-green/door"
  6. "runtime/debug"
  7. "strconv"
  8. "strings"
  9. "time"
  10. // "net/http"
  11. // _ "net/http/pprof"
  12. "github.com/mitchellh/go-wordwrap"
  13. )
  14. //go:generate sh -c "font-util extract -f 'Amazon Cyan,Serpent,Unchained,Asylum,ArmageonRed,BrainDmgBlu,Boner,Descent,Remorse,Dungeon' ../TDFONTS.TDF ../TDFONTS2.TDF ../TDFONTS9.TDF > fonts.go"
  15. //go:generate sh -c "font-util extract -f Armageddon -c 7,1 -c 4,2 ../TDFONTS2.TDF > rgfont.go; sed -i 's/Armageddon/RedGreen/g' rgfont.go"
  16. func pctUpdate(pct *int64) func() int64 {
  17. return func() int64 {
  18. return *pct
  19. }
  20. }
  21. func press_keys(d *door.Door) {
  22. d.Write(door.Reset + door.CRNL + "Press some keys... <ENTER> to exit.")
  23. var r rune
  24. var ex door.Extended
  25. var err error
  26. for (r != 0x0d) && (err == nil) {
  27. r, ex, err = d.WaitKey(door.Inactivity)
  28. if ex == door.MOUSE {
  29. m, ok := d.GetMouse()
  30. if ok {
  31. // var m door.MouseInfo = door.Mouse
  32. d.Write(fmt.Sprintf("M %d (%d,%d) ", m.Button, m.X, m.Y))
  33. }
  34. } else {
  35. if ex == door.NOP {
  36. d.Write(fmt.Sprintf("%d (%x) ", r, r))
  37. } else {
  38. d.Write(fmt.Sprintf("<%s> ", ex.String()))
  39. }
  40. }
  41. }
  42. d.Write(door.Reset + door.CRNL)
  43. }
  44. func press_a_key(d *door.Door) error {
  45. var err error
  46. var ex door.Extended
  47. d.Write(door.Reset + door.CRNL + "Press a key, or LEFT mouse click to continue...")
  48. for {
  49. _, ex, err = d.WaitKey(door.Inactivity)
  50. if ex == door.MOUSE {
  51. m, ok := d.GetMouse()
  52. if ok {
  53. if m.Button == 1 {
  54. break
  55. }
  56. }
  57. } else {
  58. break
  59. }
  60. }
  61. d.Write(door.CRNL)
  62. return err
  63. }
  64. func about_test_door(d *door.Door) {
  65. var W int = 60
  66. var center_x int = (door.Width - W) / 2
  67. var center_y int = (door.Height - 16) / 2
  68. var about door.Panel = door.Panel{X: center_x,
  69. Y: center_y,
  70. Width: W,
  71. Style: door.SINGLE_DOUBLE,
  72. BorderColor: door.ColorText("BOLD YELLOW ON BLUE"),
  73. }
  74. about.Lines = append(about.Lines, door.Line{Text: fmt.Sprintf("%*s", -W, "About This Door"),
  75. DefaultColor: door.ColorText("BOLD CYAN ON BLUE")})
  76. about.Lines = append(about.Lines, about.Spacer())
  77. about.Lines = append(about.Lines, door.Line{Text: fmt.Sprintf("%*s", -W, "Test Door written in go, using go door.")})
  78. var copyright string = "(C) 2022 Bugz, Red Green Software"
  79. if door.Unicode {
  80. copyright = strings.Replace(copyright, "(C)", "\u00a9", -1)
  81. }
  82. about.Lines = append(about.Lines,
  83. door.Line{Text: copyright, Width: W,
  84. DefaultColor: door.ColorText("BOLD WHITE ON BLUE")})
  85. for _, text := range []string{"",
  86. "This door was written by Bugz.",
  87. "",
  88. "It is written in Go, detects CP437/unicode, detects screen",
  89. "size, supports door.sys & door32.sys, supports TheDraw Fonts",
  90. "(the fonts are compiled into the door), has NoMoreSecrets",
  91. "and SpinRite effects, and runs on Linux",
  92. "and sometimes even Windows..."} {
  93. about.Lines = append(about.Lines, door.Line{Text: text, Width: W})
  94. }
  95. var better door.NoMoreSecretsConfig = door.NoMoreSecretsDefault
  96. better.Jumble_Loop_Speed = 75 // 35
  97. better.Reveal_Loop_Speed = 100 // 50
  98. better.Color = door.ColorText("BRI CYAN ON BLUE")
  99. door.NoMoreSecrets(about.Output(), d, &better)
  100. }
  101. // Build door.Menu (Main menu)
  102. func MainMenu() door.Menu {
  103. // Make the main menu
  104. // Width was 45
  105. var menu door.Menu = door.Menu{Panel: door.Panel{Width: 35,
  106. X: 2,
  107. Y: 5,
  108. Style: door.DOUBLE,
  109. Title: "[ Main Menu: ]",
  110. TitleOffset: 3,
  111. BorderColor: door.ColorText("BRI CYAN ON BLA")}}
  112. menu.SelectedR = door.MakeMenuRender(door.ColorText("BOLD CYAN"),
  113. door.ColorText("BOLD BLUE"),
  114. door.ColorText("BOLD WHITE"),
  115. door.ColorText("BOLD CYAN"))
  116. menu.UnselectedR = door.MakeMenuRender(door.ColorText("BOLD YEL ON BLUE"),
  117. door.ColorText("BOLD WHI ON BLUE"),
  118. door.ColorText("BOLD YEL ON BLUE"),
  119. door.ColorText("BOLD CYAN ON BLUE"))
  120. menu.AddSelection("A", "ANSI Display")
  121. // m.AddSelection("C", "Crash")
  122. menu.AddSelection("D", "Display Information")
  123. menu.AddSelection("F", "Font Demo")
  124. menu.AddSelection("I", "Input Demo")
  125. menu.AddSelection("M", "Menu Demo")
  126. menu.AddSelection("P", "Progress Bars Demo")
  127. menu.AddSelection("S", "Show Panel")
  128. menu.AddSelection("T", "Test Door About")
  129. menu.AddSelection("W", "Screen Width")
  130. menu.AddSelection("Q", "Quit")
  131. var descriptions []string = []string{
  132. // 12345678901234567890123456789012345678901234567890
  133. "Display an ANSI file. It is compiled into the door itself.",
  134. // "Crash go, see a handled error.", // The error shows up in the logs.
  135. "Display dropfile information.",
  136. "Display TheDraw Fonts. Font information is compiled into the door.",
  137. "Input some values, while updating the time.",
  138. "Isn't this is a menu?",
  139. "Display progress bar styles: half step, display percentage, and gradient.",
  140. "Show multiple panels. Panels can be mouse drag/drop around.",
  141. "Show about the door, using NoMoreSecrets effect.",
  142. "Examples using the full width of the screen.",
  143. "Exit this door.",
  144. }
  145. var widthLeft int = door.Width - (menu.Width + menu.X + 2)
  146. var panelWidth int = widthLeft - (2 + 2)
  147. var maxLines int = 1
  148. var maxLineLength int
  149. // Calculate the max lines needed for each line.
  150. for _, line := range descriptions {
  151. var wrapped string = wordwrap.WrapString(line, uint(panelWidth))
  152. var lines int = len(strings.Split(wrapped, "\n"))
  153. if lines > maxLines {
  154. maxLines = lines
  155. }
  156. if len(line) > maxLineLength {
  157. maxLineLength = len(line)
  158. }
  159. }
  160. if maxLines == 1 {
  161. // Ok! Everything fits into one line, SO use max line length as width of panel.
  162. panelWidth = maxLineLength
  163. }
  164. // Position the description panel beside the menu. m.Width + m.X + 2 (1 one to give it a space)
  165. var descPanel door.Panel = door.Panel{X: menu.Width + menu.X + 2 + 1, Y: menu.Y, Width: panelWidth, Style: door.SINGLE, BorderColor: door.ColorText("WHI ON BLU")}
  166. for x := 0; x < maxLines; x++ {
  167. descPanel.Lines = append(descPanel.Lines, door.Line{Text: "", Width: panelWidth})
  168. }
  169. menu.Activated = func(item int, d *door.Door) {
  170. var line string = descriptions[item]
  171. var lines []string = strings.Split(wordwrap.WrapString(line, uint(panelWidth)), "\n")
  172. for idx := range descPanel.Lines {
  173. if idx >= len(lines) {
  174. descPanel.Lines[idx].Text = ""
  175. } else {
  176. descPanel.Lines[idx].Text = lines[idx]
  177. }
  178. }
  179. d.Write(door.SavePos + descPanel.Output() + door.RestorePos)
  180. }
  181. return menu
  182. }
  183. func display_information(d *door.Door) {
  184. d.Write(door.Clrscr)
  185. var headerColor string = door.ColorText("BRI CYAN")
  186. var keyColor string = door.ColorText("BRI GREEN")
  187. var sepColor string = door.ColorText("BRI YEL")
  188. var valColor string = door.ColorText("CYAN")
  189. var nice_format func(string, string) string = func(key string, value string) string {
  190. return fmt.Sprintf("%s%-20s %s: %s%s", keyColor, key, sepColor, valColor, value) + door.CRNL
  191. }
  192. var offset string
  193. var header string = "DropFile: "
  194. offset = strings.Repeat(" ", len(header))
  195. d.Write(headerColor + header)
  196. d.Write(nice_format("Comm Type", strconv.Itoa(d.Config.Comm_type)))
  197. if d.Config.BBSID != "" {
  198. d.Write(offset + nice_format("BBS Software", d.Config.BBSID))
  199. }
  200. d.Write(offset + nice_format("Time Left", strconv.Itoa(d.Config.Time_left)))
  201. d.Write(offset + nice_format("Real Name", d.Config.Real_name))
  202. // d.Write(nice_format("Comm Handle", strconv.Itoa(d.Config.Comm_handle)))
  203. d.Write(offset + nice_format("Handle", d.Config.Handle))
  204. d.Write(offset + nice_format("User #", strconv.Itoa(d.Config.User_number)))
  205. d.Write(offset + nice_format("Security Level", strconv.Itoa(d.Config.Security_level)))
  206. d.Write(offset + nice_format("Node #", strconv.Itoa(d.Config.Node)))
  207. header = "Detected: "
  208. offset = strings.Repeat(" ", len(header))
  209. d.Write(door.CRNL + headerColor + header)
  210. d.Write(nice_format("Unicode", strconv.FormatBool(door.Unicode)))
  211. d.Write(offset + nice_format("CP437", strconv.FormatBool(door.CP437)))
  212. d.Write(offset + nice_format("Full CP437", strconv.FormatBool(door.Full_CP437)))
  213. d.Write(offset + nice_format("Screen Size", fmt.Sprintf("%d X %d", door.Width, door.Height)))
  214. var time time.Duration = d.TimeLeft()
  215. d.Write(offset + nice_format("Door Time Left", fmt.Sprintf("%d Hours, %d Minutes, %d Seconds", int(time.Hours()), int(time.Minutes())%60, int(time.Seconds())%60)))
  216. time = d.TimeUsed()
  217. d.Write(offset + nice_format("Door Time Used", fmt.Sprintf("%d Minutes, %d Seconds", int(time.Minutes()), int(time.Seconds())%60)))
  218. press_a_key(d)
  219. d.Write(door.Clrscr + door.CRNL + door.CRNL + door.CRNL)
  220. modules := GetModules()
  221. header = "Build: "
  222. offset = strings.Repeat(" ", len(header))
  223. d.Write(headerColor + header)
  224. gover, gitver, goarch, goos := GetVersion()
  225. d.Write(nice_format("go version", gover))
  226. d.Write(offset + nice_format("git commit", gitver))
  227. d.Write(offset + nice_format("Arch", goarch))
  228. d.Write(offset + nice_format("OS", goos))
  229. for mod, version := range modules {
  230. d.Write(offset + nice_format(mod, version))
  231. }
  232. }
  233. func display_ansi(d *door.Door) {
  234. var art []string = ANSIGrowl()
  235. d.Write(door.Clrscr)
  236. for _, line := range art {
  237. d.Write(line + door.CRNL)
  238. }
  239. }
  240. func font_demo(d *door.Door) {
  241. var output []string
  242. var l int
  243. var centering string
  244. var now time.Time = time.Now()
  245. // I have checks here (but not all are complete), that verify the font
  246. // output doesn't exceed the size of the screen.
  247. d.Write(door.Clrscr + door.CRNL) // + door.CRNL + door.CRNL)
  248. var fac door.ColorFont = FontAmazonCyan()
  249. output, l = fac.Output(now.Format("Jan Mon"))
  250. // Size check: Is this too big for the screen?
  251. /*
  252. if l > door.Width {
  253. output, l = fac.Output("Jan")
  254. }
  255. */
  256. if l < door.Width {
  257. centering = ""
  258. // centering = strings.Repeat(" ", (door.Width-l)/2)
  259. for _, o := range output {
  260. d.Write(fmt.Sprintf("%s%s%s", centering, o, door.Reset) + door.CRNL)
  261. }
  262. d.Write(door.CRNL)
  263. }
  264. var patch door.ColorMap = fac.Scan(6)
  265. // log.Printf("Patch: %#v\n", patch)
  266. fac.Modify(4, patch)
  267. output, l = fac.Output(now.Format("Monday"))
  268. centering = strings.Repeat(" ", (door.Width-l)/2)
  269. for _, o := range output {
  270. d.Write(fmt.Sprintf("%s%s%s", centering, o, door.Reset) + door.CRNL)
  271. }
  272. d.Write(door.CRNL)
  273. fac.Modify(1, patch)
  274. output, l = fac.Output(now.Format("January")) // 3:04:05 PM"))
  275. centering = strings.Repeat(" ", (door.Width-l)/2)
  276. for _, o := range output {
  277. d.Write(fmt.Sprintf("%s%s%s", centering, o, door.Reset) + door.CRNL)
  278. }
  279. d.Write(door.CRNL)
  280. press_a_key(d)
  281. // Anarchy Blue - no digits
  282. var fab door.ColorFont = FontSerpent()
  283. output, l = fab.Output("Date/Time:")
  284. if l < door.Width {
  285. centering = strings.Repeat(" ", (door.Width-l)/2)
  286. for _, o := range output {
  287. d.Write(centering + o + door.Reset + door.CRNL)
  288. }
  289. d.Write(door.CRNL)
  290. }
  291. var unchain door.ColorFont = FontUnchained()
  292. now = time.Now()
  293. output, l = unchain.Output(now.Format("01/02/2006"))
  294. if l < door.Width {
  295. centering = strings.Repeat(" ", (door.Width-l)/2)
  296. for _, o := range output {
  297. d.Write(centering + o + door.Reset + door.CRNL)
  298. }
  299. d.Write(door.CRNL)
  300. }
  301. output, l = unchain.Output(now.Format("3:04:05 PM"))
  302. if l > door.Width {
  303. output, l = unchain.Output("Meow")
  304. }
  305. if l < door.Width {
  306. centering = strings.Repeat(" ", (door.Width-l)/2)
  307. for _, o := range output {
  308. d.Write(centering + o + door.Reset + door.CRNL)
  309. }
  310. d.Write(door.CRNL)
  311. }
  312. press_a_key(d)
  313. var asylum door.ColorFont = FontAsylum()
  314. output, l = asylum.Output("Bugz ROCKS")
  315. if l > door.Width {
  316. output, l = asylum.Output("Aslym")
  317. }
  318. if l < door.Width {
  319. centering = strings.Repeat(" ", (door.Width-l)/2)
  320. for _, o := range output {
  321. d.Write(centering + o + door.Reset + door.CRNL)
  322. }
  323. d.Write(door.CRNL)
  324. }
  325. var brain door.ColorFont = FontBrainDmgBlu()
  326. output, l = brain.Output("I'm so BLUE")
  327. if l > door.Width {
  328. output, l = brain.Output("Blue")
  329. }
  330. if l < door.Width {
  331. centering = strings.Repeat(" ", (door.Width-l)/2)
  332. for _, o := range output {
  333. d.Write(centering + o + door.Reset + door.CRNL)
  334. }
  335. d.Write(door.CRNL)
  336. }
  337. var boner door.ColorFont = FontBoner()
  338. output, l = boner.Output("Welcome!")
  339. if l < door.Width {
  340. centering = strings.Repeat(" ", (door.Width-l)/2)
  341. for _, o := range output {
  342. d.Write(centering + o + door.Reset + door.CRNL)
  343. }
  344. d.Write(door.CRNL)
  345. }
  346. press_a_key(d)
  347. var descent door.ColorFont = FontDescent()
  348. output, l = descent.Output("Meanwhile...")
  349. if l > door.Width {
  350. output, l = descent.Output("BUGZ")
  351. }
  352. if l < door.Width {
  353. centering = strings.Repeat(" ", (door.Width-l)/2)
  354. for _, o := range output {
  355. d.Write(centering + o + door.Reset + door.CRNL)
  356. }
  357. d.Write(door.CRNL)
  358. }
  359. var remorse door.ColorFont = FontRemorse()
  360. output, l = remorse.Output("Enjoy the fonts")
  361. if l > door.Width {
  362. output, l = remorse.Output("Amazing")
  363. }
  364. if l < door.Width {
  365. centering = strings.Repeat(" ", (door.Width-l)/2)
  366. for _, o := range output {
  367. d.Write(centering + o + door.Reset + door.CRNL)
  368. }
  369. d.Write(door.CRNL)
  370. }
  371. var dungeon door.ColorFont = FontDungeon()
  372. output, l = dungeon.Output("Until NEXT time")
  373. if l > door.Width {
  374. output, l = dungeon.Output("Beware")
  375. }
  376. if l < door.Width {
  377. centering = strings.Repeat(" ", (door.Width-l)/2)
  378. for _, o := range output {
  379. d.Write(centering + o + door.Reset + door.CRNL)
  380. }
  381. d.Write(door.CRNL)
  382. }
  383. /*
  384. redgreen := FontArmageddon()
  385. white := redgreen.Scan(7)
  386. blue := redgreen.Scan(4)
  387. redgreen.Modify(1, white)
  388. redgreen.Modify(2, blue)
  389. */
  390. redgreen := FontRedGreen()
  391. output, l = redgreen.Output("Red-Green")
  392. if l < door.Width {
  393. press_a_key(d)
  394. centering = strings.Repeat(" ", (door.Width-l)/2)
  395. for _, o := range output {
  396. d.Write(centering + o + door.Reset + door.CRNL)
  397. }
  398. d.Write(door.CRNL)
  399. output, l = redgreen.Output("Software")
  400. centering = strings.Repeat(" ", (door.Width-l)/2)
  401. for _, o := range output {
  402. d.Write(centering + o + door.Reset + door.CRNL)
  403. }
  404. d.Write(door.CRNL)
  405. }
  406. }
  407. func input_demo(d *door.Door) {
  408. var ticker *time.Ticker = time.NewTicker(time.Second)
  409. var StopIt = make(chan bool)
  410. go func() {
  411. for {
  412. select {
  413. case <-StopIt:
  414. return
  415. case t := <-ticker.C:
  416. const tf = "January 2, 2006 03:04:05 PM MST"
  417. output := door.SavePos + door.Goto(5, 2) + door.ColorText("BRI WHI ON CYAN") + t.Format(tf) + door.RestorePos
  418. d.Write(output)
  419. }
  420. }
  421. }()
  422. var inputColor string = door.ColorText("BRI WHI ON BLUE")
  423. var inputColor2 string = door.ColorText("BRI WHI ON GREEN")
  424. var prompt door.Line = door.Line{Text: "What is YOUR Name: "}
  425. prompt.RenderF = door.RenderBlueYellow
  426. d.Write(prompt.Output() + inputColor)
  427. var name string = d.Input(25)
  428. d.Write(door.Reset + door.CRNL)
  429. prompt.Text = "What is Your Quest: "
  430. d.Write(prompt.Output() + inputColor2)
  431. var quest string = d.Input(35)
  432. d.Write(door.Reset + door.CRNL)
  433. prompt.Text = "What is your Favorite CoLoR: "
  434. d.Write(prompt.Output() + inputColor)
  435. var color string = d.Input(15)
  436. d.Write(door.Reset + door.CRNL)
  437. ticker.Stop()
  438. StopIt <- true
  439. d.Write(fmt.Sprintf("You're %s on the %s quest, and fond of %s."+door.CRNL, name, quest, color))
  440. }
  441. func progress_bars(d *door.Door) {
  442. d.Write(door.Clrscr)
  443. var bar door.BarLine = door.BarLine{Line: door.Line{DefaultColor: door.ColorText("BOLD YELLOW")}, Width: 20, Style: door.HALF_STEP}
  444. var bar2 door.BarLine = door.BarLine{Width: 30, Style: door.SOLID, PercentStyle: door.PERCENT_SPACE}
  445. bar2.ColorRange = []door.BarRange{
  446. {Percent: 2500, Color: door.ColorText("RED")},
  447. {Percent: 5000, Color: door.ColorText("BROWN")},
  448. {Percent: 7500, Color: door.ColorText("BOLD YEL")},
  449. {Percent: 9500, Color: door.ColorText("GREEN")},
  450. {Percent: 10100, Color: door.ColorText("BRI GRE")}}
  451. var bar3 door.BarLine = door.BarLine{Width: 15, Style: door.GRADIENT, Line: door.Line{DefaultColor: door.ColorText("CYAN")}}
  452. var percentage int64
  453. bar.UpdateP = pctUpdate(&percentage)
  454. bar2.UpdateP = pctUpdate(&percentage)
  455. bar3.UpdateP = pctUpdate(&percentage)
  456. update_bars := func() {
  457. bar.Update()
  458. bar2.Update()
  459. bar3.Update()
  460. }
  461. d.Write(door.Goto(3, 12) + "Half-Step")
  462. d.Write(door.Goto(25, 12) + "% with space and Color Range")
  463. d.Write(door.Goto(57, 12) + "Gradient")
  464. d.Write(door.HideCursor)
  465. bar_start := door.Goto(3, 15)
  466. for f := 0; f <= 100; f++ {
  467. d.Write(door.Goto(3, 10) + door.Reset + fmt.Sprintf("Value: %d", f))
  468. percentage = int64(f * 100)
  469. update_bars()
  470. d.Write(bar_start + bar.Output() + " " + door.Reset + bar2.Output() + door.Reset + " " + bar3.Output())
  471. if d.Disconnect() {
  472. // don't continue to sleep if we're disconnected
  473. break
  474. }
  475. time.Sleep(time.Millisecond * 100)
  476. }
  477. d.Write(door.ShowCursor)
  478. }
  479. func width_demo(d *door.Door) {
  480. var w int = door.Width
  481. var panel door.Panel = door.Panel{X: 1, Y: 1, Width: w}
  482. var lineColor string = door.ColorText("WHI")
  483. var line string
  484. for y := 1; y <= door.Height; y++ {
  485. if y%10 == 0 {
  486. line = strings.Repeat("1234567890", w/10)
  487. for x := len(line); x < w; x++ {
  488. line += strconv.Itoa((x + 1) % 10)
  489. }
  490. } else {
  491. line = ""
  492. for x := 1; x < w; x++ {
  493. if x%10 == 0 {
  494. line += strconv.Itoa(y % 10)
  495. } else {
  496. line += " "
  497. }
  498. }
  499. }
  500. var l door.Line = door.Line{Text: line, DefaultColor: lineColor}
  501. panel.Lines = append(panel.Lines, l)
  502. }
  503. var message string = fmt.Sprintf("Screen Size: %d X %d", door.Width, door.Height)
  504. d.Write(panel.Output())
  505. // Output alert on top of panel
  506. var cx, cy int
  507. cx = (door.Width - len(message) + 2) / 2
  508. cy = (door.Height - 3) / 2
  509. var alert []string = door.AlertBox(message, 1)
  510. d.Write(door.ColorText("BRI YEL ON BLUE"))
  511. for idx, ab := range alert {
  512. d.Write(door.Goto(cx, cy+idx) + ab)
  513. }
  514. d.Write(door.Reset + panel.GotoEnd())
  515. // Pause for key
  516. d.WaitKey(door.Inactivity)
  517. panel.Lines = make([]door.Line, 0)
  518. var background string = "BUGZ Test Door in GO "
  519. var bl int = len(background)
  520. for y := 1; y <= door.Height; y++ {
  521. offset := (y - 1) % bl
  522. line = background[offset:]
  523. for len(line) < w {
  524. if len(line)+bl <= w {
  525. line += background
  526. } else {
  527. line += background[0 : w-len(line)]
  528. }
  529. }
  530. var l door.Line = door.Line{Text: line, RenderF: door.RenderBlueYellow}
  531. panel.Lines = append(panel.Lines, l)
  532. }
  533. d.Write(panel.Output())
  534. d.WaitKey(door.Inactivity)
  535. }
  536. type TrackPanels struct {
  537. Panel *door.Panel
  538. XPos int
  539. YPos int
  540. BColor string
  541. }
  542. // Find the Panel that was mouse clicked.
  543. func FindPanel(m door.Mouse, panels []TrackPanels) int {
  544. for idx, p := range panels {
  545. hit, _, _ := p.Panel.Within(int(m.X), int(m.Y))
  546. if hit {
  547. return idx
  548. }
  549. }
  550. return -1
  551. }
  552. func panel_demo(d *door.Door) {
  553. var width int = 55
  554. var panel door.Panel = door.Panel{X: 5, Y: 5, Width: width, Style: door.DOUBLE, BorderColor: door.ColorText("CYAN ON BLUE"), Title: "[ Panel Demo ]"}
  555. var moveColor string = door.ColorText("CYAN ON BLACK")
  556. var lineColor string = door.ColorText("BRIGHT WHI ON BLUE")
  557. // Add lines to the panel
  558. for _, line := range []string{"The BBS Door Panel Demo", "(C) 2021 Red Green Software, https://red-green.com"} {
  559. if door.Unicode {
  560. line = strings.Replace(line, "(C)", "\u00a9", -1)
  561. }
  562. var l door.Line = door.Line{Text: line, Width: width, DefaultColor: lineColor}
  563. panel.Lines = append(panel.Lines, l)
  564. }
  565. panel.Lines = append(panel.Lines, panel.Spacer())
  566. panel.Lines = append(panel.Lines, door.Line{Text: "Welcome to golang!", Width: width, DefaultColor: lineColor})
  567. width = 10
  568. var single door.Panel = door.Panel{X: 6, Y: 12, Width: width, Style: door.SINGLE, BorderColor: door.ColorText("WHITE ON BLUE"), Title: "< Single >"}
  569. single.Lines = append(single.Lines, door.Line{Text: "Example", Width: width, DefaultColor: door.ColorText("WHI ON BLACK")})
  570. single.Lines = append(single.Lines, single.Spacer())
  571. single.Lines = append(single.Lines, door.Line{Text: "More Text", Width: width, DefaultColor: door.ColorText("BRI GREEN ON BLACK")})
  572. width = 15
  573. var double_single door.Panel = door.Panel{X: 26, Y: 12, Width: width, Style: door.DOUBLE_SINGLE, BorderColor: door.ColorText("BRI CYAN ON GREEN"), Title: "Double", TitleOffset: 3}
  574. double_single.Lines = append(double_single.Lines, door.Line{Text: "Double / Single", Width: width, DefaultColor: door.ColorText("BRI WHI ON GREEN")})
  575. double_single.Lines = append(double_single.Lines, double_single.Spacer())
  576. double_single.Lines = append(double_single.Lines, door.Line{Text: "Some Other Text", Width: width, DefaultColor: door.ColorText("BRI CYAN ON GREEN")})
  577. var single_double door.Panel = door.Panel{X: 46, Y: 12, Width: width, Style: door.SINGLE_DOUBLE, BorderColor: door.ColorText("BRI YELL ON RED")}
  578. single_double.Lines = append(single_double.Lines, door.Line{Text: "Single / Double", Width: width, DefaultColor: door.ColorText("BRI WHI ON RED")})
  579. single_double.Lines = append(single_double.Lines, single_double.Spacer())
  580. single_double.Lines = append(single_double.Lines, door.Line{Text: "Text Goes Here ", Width: width, DefaultColor: door.ColorText("BRI GREEN ON RED")})
  581. d.Write(door.Clrscr)
  582. d.Write(panel.Output())
  583. d.Write(single.Output())
  584. d.Write(double_single.Output())
  585. d.Write(single_double.Output())
  586. d.Write(door.Goto(1, 20) + door.Reset + "Use MOUSE to click/drag panels, Right-Click Exits, R to Reset, Q to quit...")
  587. var panels []TrackPanels = []TrackPanels{
  588. {&panel, panel.X, panel.Y, panel.BorderColor},
  589. {&single, single.X, single.Y, single.BorderColor},
  590. {&double_single, double_single.X, double_single.Y, single.BorderColor},
  591. {&single_double, single_double.X, single_double.Y, single_double.BorderColor}}
  592. var movingPanel *door.Panel
  593. var moveX, moveY int
  594. var panelColor string
  595. for {
  596. key, ex, err := d.WaitKey(door.Inactivity)
  597. if err != nil {
  598. return
  599. }
  600. if ex == door.MOUSE {
  601. m, ok := d.GetMouse()
  602. if ok {
  603. // Process Mouse Event
  604. if m.Button == 3 {
  605. // Exit on right click
  606. return
  607. }
  608. if m.Button == 1 {
  609. idx := FindPanel(m, panels)
  610. if idx != -1 {
  611. movingPanel = panels[idx].Panel
  612. panelColor = movingPanel.BorderColor
  613. moveX = int(m.X)
  614. moveY = int(m.Y)
  615. } else {
  616. continue
  617. }
  618. // Should we do something to the panel? Yes!
  619. movingPanel.BorderColor = moveColor
  620. d.Update(movingPanel.Output())
  621. } else if m.Button == 4 {
  622. if movingPanel != nil {
  623. PR, PB := movingPanel.RightBottomPos()
  624. log.Printf("Panel (%d,%d) End(%d,%d) W %d, L %d\n", movingPanel.X, movingPanel.Y, PR, PB, movingPanel.Width, movingPanel.Length())
  625. // Ok, panel is move!
  626. d.Update(movingPanel.Clear())
  627. // Restore panel border
  628. movingPanel.BorderColor = panelColor
  629. // move panel
  630. movingPanel.X -= (moveX - int(m.X))
  631. movingPanel.Y -= (moveY - int(m.Y))
  632. // sanity checks
  633. if movingPanel.X < 1 {
  634. movingPanel.X = 1
  635. }
  636. // var edgeX bool
  637. if movingPanel.X+movingPanel.Width >= door.Width {
  638. movingPanel.X = door.Width - movingPanel.Width - 1
  639. // edgeX = true
  640. }
  641. if movingPanel.Y < 1 {
  642. movingPanel.Y = 1
  643. }
  644. // var edgeY bool
  645. if movingPanel.Y+movingPanel.Length() >= door.Height {
  646. movingPanel.Y = door.Height - movingPanel.Length() - 1
  647. // edgeY = true
  648. }
  649. PR, PB = movingPanel.RightBottomPos()
  650. log.Printf("Panel Now (%d,%d) End (%d,%d) %d, %d\n", movingPanel.X, movingPanel.Y, PR, PB, movingPanel.Width, movingPanel.Length()) //, edgeX, edgeY)
  651. // If panel is at the end of the screen -- it scrolls (syncterm)
  652. // This "fixes" it. (Maybe a better way would be to not use last
  653. // line on the screen?)
  654. // Or another way:
  655. if PR == door.Width && PB == door.Height {
  656. movingPanel.X--
  657. }
  658. /*
  659. if edgeX && edgeY {
  660. movingPanel.X--
  661. log.Printf("Panel adjust X\n")
  662. }
  663. */
  664. d.Update(movingPanel.Output())
  665. }
  666. movingPanel = nil
  667. }
  668. }
  669. } else {
  670. if (key == 'Q') || (key == 'q') || (key == '\x1b') {
  671. return
  672. }
  673. if (key == 'R') || (key == 'r') {
  674. for _, p := range panels {
  675. d.Update(p.Panel.Clear())
  676. }
  677. for _, p := range panels {
  678. p.Panel.X = p.XPos
  679. p.Panel.Y = p.YPos
  680. p.Panel.BorderColor = p.BColor
  681. d.Update(p.Panel.Output())
  682. }
  683. }
  684. if key == '0' {
  685. d.Write(panels[0].Panel.GotoEnd())
  686. }
  687. if key == '1' {
  688. d.Write(panels[1].Panel.GotoEnd())
  689. }
  690. }
  691. }
  692. }
  693. func main() {
  694. var message string
  695. /*
  696. go func() {
  697. http.ListenAndServe(":6060", nil)
  698. }()
  699. */
  700. var d door.Door = door.Door{}
  701. d.Init("testdoor")
  702. defer func() {
  703. if err := recover(); err != nil {
  704. // This displays stack trace stderr
  705. debug.PrintStack()
  706. fmt.Println("ERROR:", err)
  707. log.Println("FAILURE:", err)
  708. // Display error to user
  709. d.Write(fmt.Sprintf(door.Reset+door.CRNL+"Exception: %v"+door.CRNL, err))
  710. }
  711. }()
  712. defer d.Close()
  713. // Updaters work best when the screen doesn't scroll, so start
  714. // us off at the very top.
  715. d.Write(door.Clrscr)
  716. // Start spinrite effects
  717. var ticker *time.Ticker = time.NewTicker(time.Millisecond * time.Duration(100))
  718. var spin door.SpinRiteMsg = door.SpinRiteMsgInit(15, 5,
  719. door.ColorText("RED ON GREEN"),
  720. []string{"RED", "GREEN", "SOFTWARE"})
  721. /*
  722. var spin2 door.SpinRite = door.SpinRiteInit(13, 5,
  723. door.ColorText("BRI CYA ON BLUE"))
  724. */
  725. // Add in the GoRoutine Status panel
  726. var goPanel door.Panel = door.Panel{X: door.Width - 19,
  727. Y: 3,
  728. Width: 16,
  729. Style: door.DOUBLE,
  730. Title: "] GoRuntime [",
  731. BorderColor: door.ColorText("BOLD YELL"),
  732. }
  733. goLineUpdater := func() string {
  734. status := GoRoutinesStatus()
  735. // log.Println(status)
  736. return status
  737. }
  738. var goLine door.Line = door.Line{
  739. UpdateF: goLineUpdater,
  740. Width: goPanel.Width,
  741. DefaultColor: door.ColorText("CYAN"),
  742. }
  743. // goLine.Update() // Force Update
  744. goPanel.Lines = append(goPanel.Lines, goLine)
  745. // Display Legend on GoRuntime panel
  746. const DisplayGoRoutineLegend bool = false
  747. // Display Memory
  748. const DisplayMemory bool = true
  749. var MemoryStats map[string]string
  750. if DisplayGoRoutineLegend {
  751. // Line for legend.
  752. goPanel.Lines = append(goPanel.Lines, door.Line{Width: goPanel.Width})
  753. }
  754. if DisplayMemory {
  755. memoryUpdater := func() string {
  756. MemoryStats = Memory()
  757. return fmt.Sprintf("%-8s%8s", "Sys", MemoryStats["Sys"])
  758. }
  759. goPanel.Lines = append(goPanel.Lines, door.Line{UpdateF: memoryUpdater,
  760. Width: goPanel.Width,
  761. DefaultColor: door.ColorText("BLU")})
  762. heapUpdater := func() string {
  763. return fmt.Sprintf("%-8s%8s", "HeapSys", MemoryStats["Heap"])
  764. }
  765. goPanel.Lines = append(goPanel.Lines, door.Line{UpdateF: heapUpdater,
  766. Width: goPanel.Width,
  767. DefaultColor: door.ColorText("BLU")})
  768. stackUpdater := func() string {
  769. return fmt.Sprintf("%-8s%8s", "StackSys", MemoryStats["StackSys"])
  770. }
  771. goPanel.Lines = append(goPanel.Lines, door.Line{UpdateF: stackUpdater,
  772. Width: goPanel.Width,
  773. DefaultColor: door.ColorText("BLU")})
  774. }
  775. var lIndex int = 0
  776. var legendCount int = 0
  777. const legendUpdate = 20
  778. go func() {
  779. var output string
  780. var legend []string = []string{
  781. "R=run r=Runnable",
  782. "S=Select s=Syscall",
  783. "Chan <read >write",
  784. "Z=Sleep P=Preempt",
  785. "I=Idle D=Dead",
  786. "W=Wait C=Copystk",
  787. }
  788. if DisplayGoRoutineLegend {
  789. goPanel.Lines[1].Text = legend[0]
  790. }
  791. for range ticker.C {
  792. // output = door.SavePos + door.Goto(door.Width-16, 1) + spin.Output() +
  793. // door.Goto(door.Width-15, 3) + spin2.Output() + door.RestorePos
  794. if DisplayGoRoutineLegend {
  795. legendCount++
  796. if legendCount >= legendUpdate {
  797. legendCount = 0
  798. lIndex++
  799. if lIndex == len(legend) {
  800. lIndex = 0
  801. }
  802. goPanel.Lines[1].Text = legend[lIndex]
  803. }
  804. }
  805. if goPanel.X == 0 {
  806. goPanel.X = door.Width - 40
  807. }
  808. goPanel.Update()
  809. output = door.Goto(door.Width-16, 1) + spin.Output() + goPanel.Output()
  810. /*
  811. +
  812. door.Goto(door.Width-15, 3) + spin2.Output()
  813. */
  814. if !d.Disconnect() {
  815. d.Update(output)
  816. } else {
  817. ticker.Stop()
  818. return
  819. }
  820. }
  821. }()
  822. var wopr door.WOPR
  823. wopr.Init(d.StartTime, d.TimeOut, "")
  824. wopr.ElapsedPanel.X = door.Width - 19
  825. wopr.ElapsedPanel.Y = door.Height - 15
  826. wopr.RemainingPanel.X = door.Width - 19
  827. wopr.RemainingPanel.Y = door.Height - 8
  828. wopr.Animate(&d)
  829. // bold := door.Color(1, 37, 40)
  830. var bolder string = door.ColorText("BOLD YEL ON BLUE")
  831. d.Write("Welcome to " + bolder + "go door go TestDoor." + door.Reset + door.CRNL + "..." + door.CRNL)
  832. d.EnableMouse(door.Normal)
  833. press_a_key(&d)
  834. d.Write(door.CRNL)
  835. var b []string
  836. if door.CP437 {
  837. b = door.AlertBox("Alert: go \xfb is in use!", 1)
  838. } else {
  839. b = door.AlertBox("Alert: go \u221a is in use!", 1)
  840. }
  841. warningColor := door.ColorText("BRI WHI ON GREEN")
  842. for _, line := range b {
  843. // Prevent color bleeding.
  844. d.Write(warningColor + line + door.Reset + door.CRNL)
  845. }
  846. d.Write(door.Reset + door.CRNL)
  847. var left time.Duration = d.TimeLeft()
  848. message = fmt.Sprintf("You have %0.2f minutes / %0.2f seconds remaining..."+door.CRNL, left.Minutes(), left.Seconds())
  849. d.Write(message)
  850. press_a_key(&d)
  851. var mainmenu door.Menu = MainMenu()
  852. var choice int
  853. for choice >= 0 {
  854. d.Write(door.Clrscr + door.HideCursor)
  855. choice = mainmenu.Choose(&d)
  856. d.Write(door.ShowCursor)
  857. if choice < 0 {
  858. break
  859. }
  860. option := mainmenu.GetOption(choice)
  861. wopr.Stop()
  862. // Clear WOPR panels.
  863. d.Write(door.Reset + wopr.Clear())
  864. r, b := mainmenu.Panel.RightBottomPos()
  865. d.Write(door.Goto(r, b))
  866. // fmt.Printf("Choice: %d, Option: %c\n", choice, option)
  867. switch option {
  868. case 'A':
  869. display_ansi(&d)
  870. press_a_key(&d)
  871. case 'D':
  872. display_information(&d)
  873. press_a_key(&d)
  874. case 'F':
  875. font_demo(&d)
  876. press_a_key(&d)
  877. case 'I':
  878. d.Write(door.Reset + door.CRNL + door.CRNL)
  879. input_demo(&d)
  880. press_a_key(&d)
  881. case 'M':
  882. // Why is this so far down on the screen? (Scrolls)
  883. d.Write(door.Reset + door.CRNL + "TO DO: Provide menu of options to select from..." + door.CRNL)
  884. press_a_key(&d)
  885. case 'P':
  886. progress_bars(&d)
  887. press_a_key(&d)
  888. case 'S':
  889. panel_demo(&d)
  890. press_a_key(&d)
  891. case 'T':
  892. about_test_door(&d)
  893. press_a_key(&d)
  894. case 'W':
  895. width_demo(&d)
  896. case 'Q':
  897. // This is also far down on the screen ...
  898. choice = -1
  899. case 'C': // Disabled
  900. var a, z int
  901. z = 0
  902. a = 10 / z
  903. z = a
  904. _ = a
  905. _ = z
  906. }
  907. wopr.Animate(&d)
  908. }
  909. // d.Write("\x1b[?1000l") // disable mouse
  910. // d.Write("\x1b[?1002l")
  911. d.DisableMouse()
  912. d.Write(door.Reset + door.CRNL)
  913. if d.Config.BBSID != "" {
  914. message = fmt.Sprintf("Returning to the %s BBS..."+door.CRNL, d.Config.BBSID)
  915. } else {
  916. message = "Returning to the BBS..." + door.CRNL
  917. }
  918. d.Write(message)
  919. d.WaitKey(time.Second)
  920. left = d.TimeLeft()
  921. ticker.Stop()
  922. message = fmt.Sprintf("You had %0.2f minutes remaining!"+door.CRNL, left.Minutes())
  923. d.Write(message)
  924. left = d.TimeUsed()
  925. d.Write(fmt.Sprintf("You used %0.2f seconds / %0.2f minutes."+door.CRNL, left.Seconds(), left.Minutes()))
  926. fmt.Println("Ending testdoor.go")
  927. }