aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/old/examples/term.ui/term_drawing.v
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/old/examples/term.ui/term_drawing.v')
-rw-r--r--v_windows/v/old/examples/term.ui/term_drawing.v510
1 files changed, 510 insertions, 0 deletions
diff --git a/v_windows/v/old/examples/term.ui/term_drawing.v b/v_windows/v/old/examples/term.ui/term_drawing.v
new file mode 100644
index 0000000..df08cb7
--- /dev/null
+++ b/v_windows/v/old/examples/term.ui/term_drawing.v
@@ -0,0 +1,510 @@
+// Copyright (c) 2020 Raúl Hernández. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+module main
+
+import term.ui
+
+// The color palette, taken from Google's Material design
+const (
+ colors = [
+ [
+ ui.Color{239, 154, 154},
+ ui.Color{244, 143, 177},
+ ui.Color{206, 147, 216},
+ ui.Color{179, 157, 219},
+ ui.Color{159, 168, 218},
+ ui.Color{144, 202, 249},
+ ui.Color{129, 212, 250},
+ ui.Color{128, 222, 234},
+ ui.Color{128, 203, 196},
+ ui.Color{165, 214, 167},
+ ui.Color{197, 225, 165},
+ ui.Color{230, 238, 156},
+ ui.Color{255, 245, 157},
+ ui.Color{255, 224, 130},
+ ui.Color{255, 204, 128},
+ ui.Color{255, 171, 145},
+ ui.Color{188, 170, 164},
+ ui.Color{238, 238, 238},
+ ui.Color{176, 190, 197},
+ ],
+ [
+ ui.Color{244, 67, 54},
+ ui.Color{233, 30, 99},
+ ui.Color{156, 39, 176},
+ ui.Color{103, 58, 183},
+ ui.Color{63, 81, 181},
+ ui.Color{33, 150, 243},
+ ui.Color{3, 169, 244},
+ ui.Color{0, 188, 212},
+ ui.Color{0, 150, 136},
+ ui.Color{76, 175, 80},
+ ui.Color{139, 195, 74},
+ ui.Color{205, 220, 57},
+ ui.Color{255, 235, 59},
+ ui.Color{255, 193, 7},
+ ui.Color{255, 152, 0},
+ ui.Color{255, 87, 34},
+ ui.Color{121, 85, 72},
+ ui.Color{120, 120, 120},
+ ui.Color{96, 125, 139},
+ ],
+ [
+ ui.Color{198, 40, 40},
+ ui.Color{173, 20, 87},
+ ui.Color{106, 27, 154},
+ ui.Color{69, 39, 160},
+ ui.Color{40, 53, 147},
+ ui.Color{21, 101, 192},
+ ui.Color{2, 119, 189},
+ ui.Color{0, 131, 143},
+ ui.Color{0, 105, 92},
+ ui.Color{46, 125, 50},
+ ui.Color{85, 139, 47},
+ ui.Color{158, 157, 36},
+ ui.Color{249, 168, 37},
+ ui.Color{255, 143, 0},
+ ui.Color{239, 108, 0},
+ ui.Color{216, 67, 21},
+ ui.Color{78, 52, 46},
+ ui.Color{33, 33, 33},
+ ui.Color{55, 71, 79},
+ ],
+ ]
+)
+
+const (
+ frame_rate = 30 // fps
+ msg_display_time = 5 * frame_rate
+ w = 200
+ h = 100
+ space = ' '
+ spaces = ' '
+ select_color = 'Select color: '
+ select_size = 'Size: + -'
+ help_1 = '╭────────╮'
+ help_2 = '│ HELP │'
+ help_3 = '╰────────╯'
+)
+
+struct App {
+mut:
+ ui &ui.Context = 0
+ header_text []string
+ mouse_pos Point
+ msg string
+ msg_hide_tick int
+ primary_color ui.Color = colors[1][6]
+ secondary_color ui.Color = colors[1][9]
+ primary_color_idx int = 25
+ secondary_color_idx int = 28
+ bg_color ui.Color = ui.Color{0, 0, 0}
+ drawing [][]ui.Color = [][]ui.Color{len: h, init: []ui.Color{len: w}}
+ size int = 1
+ should_redraw bool = true
+ is_dragging bool
+}
+
+struct Point {
+mut:
+ x int
+ y int
+}
+
+fn main() {
+ mut app := &App{}
+ app.ui = ui.init(
+ user_data: app
+ frame_fn: frame
+ event_fn: event
+ frame_rate: frame_rate
+ hide_cursor: true
+ window_title: 'V terminal pixelart drawing app'
+ )
+ app.mouse_pos.x = 40
+ app.mouse_pos.y = 15
+ app.ui.clear()
+ app.ui.run() ?
+}
+
+fn frame(x voidptr) {
+ mut app := &App(x)
+ mut redraw := app.should_redraw
+ if app.msg != '' && app.ui.frame_count >= app.msg_hide_tick {
+ app.msg = ''
+ redraw = true
+ }
+ if redraw {
+ app.render(false)
+ app.should_redraw = false
+ }
+}
+
+fn event(event &ui.Event, x voidptr) {
+ mut app := &App(x)
+ match event.typ {
+ .mouse_down {
+ app.is_dragging = true
+ if app.ui.window_height - event.y < 5 {
+ app.footer_click(event)
+ } else {
+ app.paint(event)
+ }
+ }
+ .mouse_up {
+ app.is_dragging = false
+ }
+ .mouse_drag {
+ app.mouse_pos = Point{
+ x: event.x
+ y: event.y
+ }
+ app.paint(event)
+ }
+ .mouse_move {
+ app.mouse_pos = Point{
+ x: event.x
+ y: event.y
+ }
+ }
+ .mouse_scroll {
+ app.mouse_pos = Point{
+ x: event.x
+ y: event.y
+ }
+ d := event.direction == .down
+ if event.modifiers.has(.ctrl) {
+ p := !event.modifiers.has(.shift)
+ c := if d {
+ if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
+ } else {
+ if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 }
+ }
+ app.select_color(p, c)
+ } else {
+ if d {
+ app.inc_size()
+ } else {
+ app.dec_size()
+ }
+ }
+ }
+ .key_down {
+ match event.code {
+ .f1, ._1 {
+ oevent := *event
+ nevent := ui.Event{
+ ...oevent
+ button: ui.MouseButton.left
+ x: app.mouse_pos.x
+ y: app.mouse_pos.y
+ }
+ app.paint(nevent)
+ }
+ .f2, ._2 {
+ oevent := *event
+ nevent := ui.Event{
+ ...oevent
+ button: ui.MouseButton.right
+ x: app.mouse_pos.x
+ y: app.mouse_pos.y
+ }
+ app.paint(nevent)
+ }
+ .space, .enter {
+ oevent := *event
+ nevent := ui.Event{
+ ...oevent
+ button: .left
+ x: app.mouse_pos.x
+ y: app.mouse_pos.y
+ }
+ app.paint(nevent)
+ }
+ .delete, .backspace {
+ oevent := *event
+ nevent := ui.Event{
+ ...oevent
+ button: .middle
+ x: app.mouse_pos.x
+ y: app.mouse_pos.y
+ }
+ app.paint(nevent)
+ }
+ .j, .down {
+ if event.modifiers.has(.shift) {
+ app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
+ }
+ app.mouse_pos.y++
+ }
+ .k, .up {
+ if event.modifiers.has(.shift) {
+ app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
+ }
+ app.mouse_pos.y--
+ }
+ .h, .left {
+ if event.modifiers.has(.shift) {
+ app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
+ }
+ app.mouse_pos.x -= 2
+ }
+ .l, .right {
+ if event.modifiers.has(.shift) {
+ app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
+ }
+ app.mouse_pos.x += 2
+ }
+ .t {
+ p := !event.modifiers.has(.alt)
+ c := if event.modifiers.has(.shift) {
+ if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 }
+ } else {
+ if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 }
+ }
+ app.select_color(p, c)
+ }
+ .r {
+ p := !event.modifiers.has(.alt)
+ c := if event.modifiers.has(.shift) {
+ if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
+ } else {
+ if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 }
+ }
+ app.select_color(p, c)
+ }
+ .plus {
+ app.inc_size()
+ }
+ .minus {
+ app.dec_size()
+ }
+ .c {
+ app.drawing = [][]ui.Color{len: h, init: []ui.Color{len: w}}
+ }
+ .q, .escape {
+ app.render(true)
+ exit(0)
+ }
+ else {}
+ }
+ }
+ else {}
+ }
+ app.should_redraw = true
+}
+
+fn (mut app App) render(paint_only bool) {
+ app.ui.clear()
+ app.draw_header()
+ app.draw_content()
+ if !paint_only {
+ app.draw_footer()
+ app.draw_cursor()
+ }
+ app.ui.flush()
+}
+
+fn (mut app App) select_color(primary bool, idx int) {
+ c := (idx + 57) % 57
+ cx := c % 19
+ cy := (c / 19) % 3
+ color := colors[cy][cx]
+ if primary {
+ app.primary_color_idx = c % (19 * 3)
+ app.primary_color = color
+ } else {
+ app.secondary_color_idx = c % (19 * 3)
+ app.secondary_color = color
+ }
+ c_str := if primary { 'primary' } else { 'secondary' }
+ app.show_msg('set $c_str color idx: $idx', 1)
+}
+
+fn (mut app App) set_pixel(x_ int, y_ int, c ui.Color) {
+ // Term coords start at 1, and adjust for the header
+ x, y := x_ - 1, y_ - 4
+ if y < 0 || app.ui.window_height - y < 3 {
+ return
+ }
+ if y >= app.drawing.len || x < 0 || x >= app.drawing[0].len {
+ return
+ }
+ app.drawing[y][x] = c
+}
+
+fn (mut app App) paint(event &ui.Event) {
+ if event.y < 4 || app.ui.window_height - event.y < 4 {
+ return
+ }
+ x_start, y_start := int(f32((event.x - 1) / 2) - app.size / 2 + 1), event.y - app.size / 2
+ color := match event.button {
+ .left { app.primary_color }
+ .right { app.secondary_color }
+ else { app.bg_color }
+ }
+ for x in x_start .. x_start + app.size {
+ for y in y_start .. y_start + app.size {
+ app.set_pixel(x, y, color)
+ }
+ }
+}
+
+fn (mut app App) draw_content() {
+ w_, mut h_ := app.ui.window_width / 2, app.ui.window_height - 8
+ if h_ > app.drawing.len {
+ h_ = app.drawing.len
+ }
+ for row_idx, row in app.drawing[..h_] {
+ app.ui.set_cursor_position(0, row_idx + 4)
+ mut last := ui.Color{0, 0, 0}
+ for cell in row[..w_] {
+ if cell.r == 0 && cell.g == 0 && cell.b == 0 {
+ if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
+ app.ui.reset()
+ }
+ } else {
+ if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
+ app.ui.set_bg_color(cell)
+ }
+ }
+ app.ui.write(spaces)
+ last = cell
+ }
+ app.ui.reset()
+ }
+}
+
+fn (mut app App) draw_cursor() {
+ if app.mouse_pos.y in [3, app.ui.window_height - 5] {
+ // inside the horizontal separators
+ return
+ }
+ cursor_color := if app.is_dragging { ui.Color{220, 220, 220} } else { ui.Color{160, 160, 160} }
+ app.ui.set_bg_color(cursor_color)
+ if app.mouse_pos.y >= 3 && app.mouse_pos.y <= app.ui.window_height - 4 {
+ // inside the main content
+ mut x_start := int(f32((app.mouse_pos.x - 1) / 2) - app.size / 2 + 1) * 2 - 1
+ mut y_start := app.mouse_pos.y - app.size / 2
+ mut x_end := x_start + app.size * 2 - 1
+ mut y_end := y_start + app.size - 1
+ if x_start < 1 {
+ x_start = 1
+ }
+ if y_start < 4 {
+ y_start = 4
+ }
+ if x_end > app.ui.window_width {
+ x_end = app.ui.window_width
+ }
+ if y_end > app.ui.window_height - 5 {
+ y_end = app.ui.window_height - 5
+ }
+ app.ui.draw_rect(x_start, y_start, x_end, y_end)
+ } else {
+ app.ui.draw_text(app.mouse_pos.x, app.mouse_pos.y, space)
+ }
+ app.ui.reset()
+}
+
+fn (mut app App) draw_header() {
+ if app.msg != '' {
+ app.ui.set_color(
+ r: 0
+ g: 0
+ b: 0
+ )
+ app.ui.set_bg_color(
+ r: 220
+ g: 220
+ b: 220
+ )
+ app.ui.draw_text(0, 0, ' $app.msg ')
+ app.ui.reset()
+ }
+ //'tick: $app.ui.frame_count | ' +
+ app.ui.draw_text(3, 2, 'terminal size: ($app.ui.window_width, $app.ui.window_height) | primary color: $app.primary_color.hex() | secondary color: $app.secondary_color.hex()')
+ app.ui.horizontal_separator(3)
+}
+
+fn (mut app App) draw_footer() {
+ _, wh := app.ui.window_width, app.ui.window_height
+ app.ui.horizontal_separator(wh - 4)
+ for i, color_row in colors {
+ for j, color in color_row {
+ x := j * 3 + 19
+ y := wh - 3 + i
+ app.ui.set_bg_color(color)
+ if app.primary_color_idx == j + (i * 19) {
+ app.ui.set_color(r: 0, g: 0, b: 0)
+ app.ui.draw_text(x, y, '><')
+ app.ui.reset_color()
+ } else if app.secondary_color_idx == j + (i * 19) {
+ app.ui.set_color(r: 255, g: 255, b: 255)
+ app.ui.draw_text(x, y, '><')
+ app.ui.reset_color()
+ } else {
+ app.ui.draw_rect(x, y, x + 1, y)
+ }
+ }
+ }
+ app.ui.reset_bg_color()
+ app.ui.draw_text(3, wh - 3, select_color)
+ app.ui.bold()
+ app.ui.draw_text(3, wh - 1, '$select_size $app.size')
+ app.ui.reset()
+
+ // TODO: help button
+ // if ww >= 90 {
+ // app.ui.draw_text(80, wh - 3, help_1)
+ // app.ui.draw_text(80, wh - 2, help_2)
+ // app.ui.draw_text(80, wh - 1, help_3)
+ // }
+}
+
+[inline]
+fn (mut app App) inc_size() {
+ if app.size < 30 {
+ app.size++
+ }
+ app.show_msg('inc. size: $app.size', 1)
+}
+
+[inline]
+fn (mut app App) dec_size() {
+ if app.size > 1 {
+ app.size--
+ }
+ app.show_msg('dec. size: $app.size', 1)
+}
+
+fn (mut app App) footer_click(event &ui.Event) {
+ footer_y := 3 - (app.ui.window_height - event.y)
+ match event.x {
+ 8...11 {
+ app.inc_size()
+ }
+ 12...15 {
+ app.dec_size()
+ }
+ 18...75 {
+ if (event.x % 3) == 0 {
+ // Inside the gap between tiles
+ return
+ }
+ idx := footer_y * 19 - 6 + event.x / 3
+ if idx < 0 || idx > 56 {
+ return
+ }
+ app.select_color(event.button == .left, idx)
+ }
+ else {}
+ }
+}
+
+fn (mut app App) show_msg(text string, time int) {
+ frames := time * frame_rate
+ app.msg_hide_tick = if time > 0 { int(app.ui.frame_count) + frames } else { -1 }
+ app.msg = text
+}