1// Copyright 2019 Graham Clark. All rights reserved.  Use of this source code is governed by the MIT license
2// that can be found in the LICENSE file.
3
4// A port of urwid's palette_test.py example using gowid widgets.
5package main
6
7import (
8	"errors"
9	"regexp"
10	"strings"
11
12	"github.com/gcla/gowid"
13	"github.com/gcla/gowid/examples"
14	"github.com/gcla/gowid/widgets/button"
15	"github.com/gcla/gowid/widgets/columns"
16	"github.com/gcla/gowid/widgets/divider"
17	"github.com/gcla/gowid/widgets/holder"
18	"github.com/gcla/gowid/widgets/pile"
19	"github.com/gcla/gowid/widgets/radio"
20	"github.com/gcla/gowid/widgets/styled"
21	"github.com/gcla/gowid/widgets/text"
22	"github.com/gdamore/tcell"
23	log "github.com/sirupsen/logrus"
24)
25
26//======================================================================
27
28// t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t254 t255
29
30var chart256 = `
31brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
32yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
33
34              #00f#06f#08f#0af#0df#0ff         black_______    dark_gray___
35            #60f#00d#06d#08d#0ad#0dd#0fd         light_gray__    white_______
36          #80f#60d#00a#06a#08a#0aa#0da#0fa
37        #a0f#80d#60a#008#068#088#0a8#0d8#0f8
38      #d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6
39    #f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff
40      #f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df
41        #f0a#d08#a06#800#860#880#8a0#8d0#8f0#8f6#8f8#8fa#8fd#8ff#6df#0af
42          #f08#d06#a00#a60#a80#aa0#ad0#af0#af6#af8#afa#afd#aff#8df#6af#08f
43            #f06#d00#d60#d80#da0#dd0#df0#df6#df8#dfa#dfd#dff#adf#8af#68f#06f
44              #f00#f60#f80#fa0#fd0#ff0#ff6#ff8#ffa#ffd#fff#ddf#aaf#88f#66f#00f
45                                    #fd0#fd6#fd8#fda#fdd#fdf#daf#a8f#86f#60f
46      #66d#68d#6ad#6dd                #fa0#fa6#fa8#faa#fad#faf#d8f#a6f#80f
47    #86d#66a#68a#6aa#6da                #f80#f86#f88#f8a#f8d#f8f#d6f#a0f
48  #a6d#86a#668#688#6a8#6d8                #f60#f66#f68#f6a#f6d#f6f#d0f
49#d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd    #f00#f06#f08#f0a#f0d#f0f
50  #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
51    #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
52      #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d       g78_g82_g85_g89_g93_g100_
53                    #da6#da8#daa#dad#a8d#86d       g52_g58_g62_g66_g70_g74_
54      #88a#8aa        #d86#d88#d8a#d8d#a6d       g27_g31_g35_g38_g42_g46_g50_
55    #a8a#888#8a8#8aa    #d66#d68#d6a#d6d       g0__g3__g7__g11_g15_g19_g23_
56      #a88#aa8#aaa#88a
57            #a88#a8a
58`
59
60var chart88 = `
61brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
62yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
63
64      #00f#08f#0cf#0ff            black_______    dark_gray___
65    #80f#00c#08c#0cc#0fc            light_gray__    white_______
66  #c0f#80c#008#088#0c8#0f8
67#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff            #88c#8cc
68  #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf        #c8c#888#8c8#8cc
69    #f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f        #c88#cc8#ccc#88c
70      #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f            #c88#c8c
71                    #fc0#fc8#fcc#fcf#c8f#80f
72                      #f80#f88#f8c#f8f#c0f        g62_g74_g82_g89_g100
73                        #f00#f08#f0c#f0f        g0__g19_g35_g46_g52
74`
75
76var chart16 = `
77brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
78yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
79
80black_______    dark_gray___    light_gray__    white_______
81`
82
83var chart8 = `
84black__   red_   green_   yellow_    blue_    magenta_   cyan_   white_
85`
86
87var chartMono = `
88black__   white_
89`
90
91var attrRE = regexp.MustCompile(`(?P<whitespace>[ \n]*)(?P<entry>((#...)|([a-z_]{2,})|(g[0-9]+_+)|(t[0-9]{1,3})))`)
92
93var attrREIndices = makeRegexpNameMap(attrRE)
94
95var fgColorDefault = gowid.NewUrwidColor("light gray")
96var bgColorDefault = gowid.MakeTCellColorExt(tcell.ColorBlack)
97
98var chartHolder *holder.Widget
99
100var chart256Content *text.Widget
101var chart88Content *text.Widget
102var chart16Content *text.Widget
103var chart8Content *text.Widget
104var chartMonoContent *text.Widget
105
106var foregroundColors = true
107
108//======================================================================
109
110func makeRegexpNameMap(re *regexp.Regexp) map[string]int {
111	res := make(map[string]int)
112	for i, name := range re.SubexpNames() {
113		res[name] = i
114	}
115	return res
116}
117
118//======================================================================
119
120func updateChartHolder(mode gowid.ColorMode, app gowid.IApp) {
121	switch mode {
122	case gowid.Mode256Colors:
123		chart256Content = text.NewFromContent(parseChart(chart256))
124		chartHolder.SetSubWidget(chart256Content, app)
125	case gowid.Mode88Colors:
126		chart88Content = text.NewFromContent(parseChart(chart88))
127		chartHolder.SetSubWidget(chart88Content, app)
128	case gowid.Mode16Colors:
129		chart16Content = text.NewFromContent(parseChart(chart16))
130		chartHolder.SetSubWidget(chart16Content, app)
131	case gowid.Mode8Colors:
132		chart8Content = text.NewFromContent(parseChart(chart8))
133		chartHolder.SetSubWidget(chart8Content, app)
134	case gowid.ModeMonochrome:
135		chartMonoContent = text.NewFromContent(parseChart(chartMono))
136		chartHolder.SetSubWidget(chartMonoContent, app)
137	default:
138		panic(errors.New("Invalid mode, something went wrong!"))
139	}
140}
141
142//======================================================================
143
144func modeRb(group *[]radio.IWidget, txt string) gowid.IWidget {
145	rbt := text.New(" " + txt)
146	rb := radio.New(group)
147	widp := gowid.RenderFixed{}
148
149	rb.OnClick(gowid.WidgetCallback{"cb", func(app gowid.IApp, w gowid.IWidget) {
150		if rb.Selected {
151			switch txt {
152			case "256-Color":
153				app.SetColorMode(gowid.Mode256Colors)
154			case "88-Color":
155				app.SetColorMode(gowid.Mode88Colors)
156			case "16-Color":
157				app.SetColorMode(gowid.Mode16Colors)
158			case "8-Color":
159				app.SetColorMode(gowid.Mode8Colors)
160			case "Monochrome":
161				app.SetColorMode(gowid.ModeMonochrome)
162			case "Foreground Colors":
163				foregroundColors = true
164			case "Background Colors":
165				foregroundColors = false
166			default:
167				panic(errors.New("Invalid mode, something went wrong!"))
168			}
169			updateChartHolder(app.GetColorMode(), app) // Update the chart displayed
170		}
171	}})
172
173	c := columns.New([]gowid.IContainerWidget{
174		&gowid.ContainerWidget{rb, widp},
175		&gowid.ContainerWidget{rbt, widp},
176	})
177
178	cm := styled.NewExt(c, gowid.MakePaletteRef("panel"), gowid.MakePaletteRef("focus"))
179
180	return cm
181}
182
183//======================================================================
184
185func parseChart(chart string) *text.Content {
186	content := make([]text.ContentSegment, 0)
187	replacer := strings.NewReplacer("_", " ")
188	for _, match := range attrRE.FindAllStringSubmatch(chart, -1) {
189		ws := match[attrREIndices["whitespace"]]
190		if ws != "" {
191			content = append(content, text.StringContent(ws))
192		}
193		entry := match[attrREIndices["entry"]]
194		entry = replacer.Replace(entry)
195
196		entry2 := strings.Trim(entry, " ")
197		scol, err := gowid.MakeColorSafe(entry2)
198		if err == nil {
199			var attrPair gowid.PaletteEntry
200			if foregroundColors {
201				attrPair = gowid.MakePaletteEntry(scol, bgColorDefault)
202			} else {
203				attrPair = gowid.MakePaletteEntry(fgColorDefault, scol)
204			}
205			content = append(content, text.StyledContent(entry, attrPair))
206		} else {
207			content = append(content, text.StyledContent(entry, gowid.MakePaletteRef("redinv")))
208		}
209	}
210	return text.NewContent(content)
211}
212
213//======================================================================
214
215func main() {
216
217	f := examples.RedirectLogger("palette.log")
218	defer f.Close()
219
220	palette := gowid.Palette{
221		"header":  gowid.MakeStyledPaletteEntry(gowid.ColorBlack, gowid.ColorWhite, gowid.StyleUnderline),
222		"panel":   gowid.MakePaletteEntry(gowid.ColorWhite, gowid.ColorDarkBlue),
223		"focus":   gowid.MakePaletteEntry(gowid.ColorYellow, gowid.ColorRed),
224		"red":     gowid.MakePaletteEntry(gowid.ColorRed, gowid.ColorBlack),
225		"redinv":  gowid.MakePaletteEntry(gowid.ColorBlack, gowid.ColorRed),
226		"default": gowid.MakePaletteEntry(gowid.NewUrwidColor("light gray"), gowid.ColorBlack),
227	}
228
229	header := gowid.MakePaletteRef("header")
230
231	// make this just text
232	headerContent := []text.ContentSegment{
233		text.StyledContent("Gowid Palette Test", header),
234	}
235
236	headerText := styled.New(text.NewFromContent(text.NewContent(headerContent)), header)
237
238	rbgroup := make([]radio.IWidget, 0)
239	bggroup := make([]radio.IWidget, 0)
240
241	btn := button.New(text.New("Exit"))
242
243	btn.OnClick(gowid.WidgetCallback{"cb", func(app gowid.IApp, w gowid.IWidget) {
244		app.Quit()
245	}})
246
247	subFlow := gowid.RenderFlow{}
248
249	// Put this in the group first so it is the one selected
250	cols256 := modeRb(&rbgroup, "256-Color")
251
252	pw1 := pile.New([]gowid.IContainerWidget{
253		&gowid.ContainerWidget{modeRb(&rbgroup, "Monochrome"), subFlow},
254		&gowid.ContainerWidget{modeRb(&rbgroup, "8-Color"), subFlow},
255		&gowid.ContainerWidget{modeRb(&rbgroup, "16-Color"), subFlow},
256		&gowid.ContainerWidget{modeRb(&rbgroup, "88-Color"), subFlow},
257		&gowid.ContainerWidget{cols256, subFlow},
258	})
259
260	pw2 := pile.New([]gowid.IContainerWidget{
261		&gowid.ContainerWidget{modeRb(&bggroup, "Foreground Colors"), subFlow},
262		&gowid.ContainerWidget{modeRb(&bggroup, "Background Colors"), subFlow},
263		&gowid.ContainerWidget{divider.NewBlank(), subFlow},
264		&gowid.ContainerWidget{divider.NewBlank(), subFlow},
265		&gowid.ContainerWidget{
266			styled.NewExt(
267				btn,
268				gowid.MakePaletteRef("panel"),
269				gowid.MakePaletteRef("focus"),
270			),
271			subFlow},
272	})
273
274	cs := columns.New([]gowid.IContainerWidget{
275		&gowid.ContainerWidget{pw1, gowid.RenderWithWeight{10}},
276		&gowid.ContainerWidget{pw2, gowid.RenderWithWeight{10}},
277	})
278
279	cs2 := styled.New(cs, gowid.MakePaletteRef("panel"))
280
281	chart256Content = text.NewFromContent(parseChart(chart256))
282	chartHolder = holder.New(chart256Content)
283
284	view := pile.New([]gowid.IContainerWidget{
285		&gowid.ContainerWidget{headerText, subFlow},
286		&gowid.ContainerWidget{cs2, subFlow},
287		&gowid.ContainerWidget{chartHolder, gowid.RenderWithWeight{1}},
288	})
289
290	app, err := gowid.NewApp(gowid.AppArgs{
291		View:    view,
292		Palette: &palette,
293		Log:     log.StandardLogger(),
294	})
295	examples.ExitOnErr(err)
296	app.SetColorMode(gowid.Mode256Colors)
297
298	app.SimpleMainLoop()
299}
300
301//======================================================================
302// Local Variables:
303// mode: Go
304// fill-column: 110
305// End:
306