shithub: irc.myr

ref: 8d6c1b01c6e17894cb1054d954d18272e71e5aae
dir: /draw.myr/

View raw version
use std
use date
use iter
use termdraw

use "types"
use "irc"

pkg =
	const redraw	: (irc : irc# -> void)
;;

const redraw = {irc
	var c, x, y, w, h, lh

	if irc.term.width < 10 || irc.term.height < 5
		-> void
	;;

	x = 0
	y = 0
	w = irc.term.width
	h = irc.term.height
	c = curchan(irc)
	if irc.chandirty
		lh = listheight(irc, 0, 1, w, h - 1)
		drawbanner(irc, 0, 0, w, 1, c)
		drawtext(irc, 0, 1, w, h - lh - 1, c)
		drawlist(irc, 0, h - lh - 1, w, h - 1, c)
		irc.chandirty = false
	;;
	if irc.cmddirty
		drawinput(irc, 0, h - 1, w, h, c)
		irc.cmddirty = false
	;;
	termdraw.flush(irc.term)
}

const drawbanner = {irc, x0, y0, x1, y1, c
	var t

	t = irc.term
	termdraw.setbg(t, termdraw.Blue)
	termdraw.clear(t, x0, y0, x1, y1)
	termdraw.move(t, x0, y0)
	termdraw.put(t, "{}", c.topic)
}

const drawtext = {irc, x0, y0, x1, y1, c
	var height, margin, width, off
	var t, dx, dy
	var count
	var x, y

	t = irc.term
	termdraw.setbg(t, termdraw.Default)
	termdraw.clear(t, x0, y0, x1, y1)
	termdraw.move(t, x0, y0)

	dx = x1 - x0
	dy = y1 - y0
	count = 0
	height = 0
	width = dx
	off = 0
	/* nothing worth drawing... */
	if dx <= c.gutter
		-> void
	;;
	for (tm, ent) : iter.byreverse(c.hist[:c.hist.len - c.scroll])
		margin = 0
		match ent
		| `Msg (m, ln):
			margin = strwidth(x0, c.gutter, " | ") + c.gutter
			width = strwidth(x0, margin, ln)
		| `Act (m, ln):
			margin = strwidth(x0, 0, "  *")
			width = strwidth(x0, margin, m)
			width += strwidth(x0, margin, " ")
			width += strwidth(x0, margin, ln)
		| `Join user:
			margin = strwidth(x0, 0, "#joined: ")
			width = strwidth(x0, margin, user)
		| `Part user:
			margin = strwidth(x0, 0, "#parted: ")
			width = strwidth(x0, margin, user)
		| `Status msg:
			margin = strwidth(x0, 0, "! ")
			width = strwidth(x0, margin, msg)
		;;
		/* no point in drawing if all we draw is gutter */
		if dx - margin <=  0
			-> void
		;;
		height++
		if width > 0
			height += width / (dx - margin)
		;;
		count++
		if height == dy
			break
		elif height > dy
			off = (dx - margin)*(height - dy)
			off = std.clamp(off, 0, width)
			break
		;;
	;;

	x = x0
	y = y0
	off = std.clamp(off, 0, width)
	for (tm, h) : c.hist[c.hist.len - c.scroll - count:]
		match h
		| `Msg (m, ln):
			termdraw.setattr(t, termdraw.Bold)
			x = std.clamp(x0 + c.gutter - strwidth(x0, 0, m), 0, dx)
			termdraw.move(t, x0 + c.gutter, y)
			(x, y) = draw(t, m, x, y, x1, y1)
			(x, y) = draw(t, " | ", x, y, x1, y1)
			termdraw.setattr(t, lineattr(irc, ln[off:]))
			(x, y) = draw(t, ln[off:], x, y, x1, y1)
			termdraw.setattr(t, termdraw.Normal)
		| `Act (m, ln):
			termdraw.setattr(t, termdraw.Bold)
			(x, y) = draw(t, "  *", x0, y, x1, y1)
			(x, y) = draw(t, m, x, y, x1, y1)
			termdraw.setattr(t, lineattr(irc, ln[off:]))
			(x, y) = draw(t, " ", x, y, x1, y1)
			(x, y) = draw(t, ln[off:], x, y, x1, y1)
			termdraw.setattr(t, termdraw.Normal)
		| `Join user:
			(x, y) = draw(t, "#joined ", x0, y, x1, y1)
			(x, y) = draw(t, user[off:], x, y, x1, y1)
		| `Part user:
			(x, y) = draw(t, "#parted ", x0, y, x1, y1)
			(x, y) = draw(t, user[off:], x, y, x1, y1)
		| `Status msg:
			(x, y) = draw(t, "! ", x0, y, x1, y1)
			(x, y) = draw(t, msg[off:], x, y, x1, y1)
		;;
		y++
		off = 0
		if y >= y1
			break
		;;
	;;
}

const strwidth = {x0, margin, str
	var x

	x = x0 + margin
	for c : std.bychar(str)
		match c
		| '\t':	x = (x / 8 + 1) * 8
		| _:	x += (std.cellwidth(c) : int)
		;;
	;;
	-> x - (x0 + margin)
}

const draw = {t, msg, x0, y0, x1, y1
	var x, y

	x = x0
	y = y0
	for l : std.bychar(msg)
		match l
		| '\t':	
			x = (x / 8 + 1)*8
		| '\n':	
			termdraw.put(t, "\\n")
			x += 2
		| chr:
			if x < x1
				termdraw.move(t, x, y)
				termdraw.putc(t, chr)
				x++
			;;
		;;
		if x >= x1
			x = x0
			y++
		;;
	;;
	-> (x, y)
}

const drawlist = {irc, x0, y0, x1, y1, c
	var t, h


	h = 1
	t = irc.term
	termdraw.setbg(t, termdraw.Blue)
	termdraw.clear(t, x0, y0, x1, y1)
	termdraw.move(t, x0, y0)
	termdraw.putc(t, '|')
	termdraw.put(t, "[{}]", irc.self.name)
	for s : irc.srv
		for ch : s.chan
			if t.x + strwidth(t.x, 0, ch.name) + 4 >= x1
				h++
				termdraw.move(t, x0, y0 + h - 1)
			;;
			if ch.flagged
				termdraw.setattr(t, termdraw.Bold)
				termdraw.put(t, "[@{}]", ch.name)
				termdraw.setattr(t, termdraw.Normal)
			elif ch.stale
				termdraw.put(t, "[*{}]", ch.name)
			else
				termdraw.put(t, "[ {}]", ch.name)
			;;
		;;
		termdraw.setattr(t, termdraw.Normal)
		termdraw.putc(t, '|')
	;;
	-> h
}

const drawinput = {irc, x0, y0, x1, y1, c
	var t, chan, ln, cx, dx

	dx = x1 - x0
	t = irc.term
	chan = std.fmt("[{}] ", c.name)
	ln = inputstr(irc, chan, dx)
	cx = x0 + (std.strcellwidth(chan) + irc.off : int)
	if cx > dx
		cx = dx
	;;
	termdraw.setbg(t, termdraw.Default)
	termdraw.move(t, x0, y0)
	termdraw.clear(t, x0, y0, x1, y1)
	termdraw.put(t, "{}{}", chan, ln)
	termdraw.cursorpos(t, cx, y0)
	std.slfree(chan)
	std.slfree(ln)
}

const listheight = {irc, x0, y0, x1, y1
	var w, h
	w = 0

	h = 1
	w += strwidth(x0, 0, "|")
	w += strwidth(x0 + w, 0, "[ ]")
	w += strwidth(x0 + w, 0, irc.self.name)
	for s : irc.srv
		for ch : s.chan
			if x0 + w + strwidth(w, 0, ch.name) + 4 >= x1
				h++
				w = 0
			;;
			w += strwidth(x0 + w, 0, "[ ]")
			w += strwidth(x0 + w, 0, ch.name)
		;;
		w += strwidth(x0 + w, 0, "|")
	;;
	-> h
}

const lineattr = {irc, ln
	match cursrv(irc)
	| `std.None:	-> termdraw.Normal
	| `std.Some srv:
		match std.strfind(ln, srv.nick)
		| `std.Some _:	-> termdraw.Italic
		| `std.None:	-> termdraw.Normal
		;;
	;;
}

const inputstr = {irc, chan, dx
	var w, s, o
	var start, end

	s = irc.cmd
	o = (irc.off : int)
	dx -= strwidth(0, 0, chan)
	w = 0
	start = 0
	end = 0
	for var i = 0; i < s.len; i++
		w += std.cellwidth(s[i])
		if w >= dx
			break
		;;
		end++
	;;
	while end < s.len && irc.off >= (w : std.size)
		start++
		while std.cellwidth(s[end]) == 0
			start++
		;;
		w += std.cellwidth(s[end])
		end++
		while end < s.len && std.cellwidth(s[end]) == 0
			end++
		;;
	;;
	-> getstr(s[start:end])
}