naledi / client / crt-ext.lisp
;;;; Naledi ya Africa ("Star of Africa") is an ncurses-based survival game
;;;; set in Africa.
;;;; This file holds extension functions for croatoan.
;;;; (c) 2018 Daniel Vedder, MIT license

(in-package :naledi-ya-africa)

(defun query-user (scr msg &key (cls NIL) (val-width 30) (default ""))
	"Display a popup asking the user to enter a value, then return that value"
	;; I found croatoan's field/form to complicated to use (:form-default-keymap
	;; doesn't seem to work), so I hacked up my own alternative
	;; TODO display additional lines of text
	(when cls (croatoan:clear scr))
	(croatoan:refresh scr)
	(let* ((x0 (- (halve (croatoan:.width scr)) (+ 5 (halve val-width))))
			  (y0 (- (halve (croatoan:.height scr)) 3))
			  (inputwin (make-instance 'croatoan:window :position (list y0 x0)
							:width (+ 10 val-width) :height 6)))
		(setf (croatoan:.visible inputwin) t)
		(croatoan:box inputwin)
		(croatoan:add-string inputwin msg :y 2 :x 4)
		(croatoan:add-string inputwin ">>> " :y 3 :x 4)
		(croatoan:add-string inputwin (to-string default) :y 3 :x 8
			:color-pair '(:blue :black))
		(croatoan:move inputwin 3 (+ 8 (length (to-string default))))
		(croatoan:refresh inputwin)
		(croatoan:event-case (scr event)
			((nil) nil)
				(when (< 8 (croatoan:.cursor-position-x inputwin))
					(croatoan:move inputwin 0 -1 :relative t)
					(croatoan:add-char inputwin #\space)
					(croatoan:move inputwin 0 -1 :relative t)
					(croatoan:refresh inputwin)))
				(return-from croatoan:event-case
						(croatoan:extract-string inputwin
							:y 3 :x 8 :n val-width))))
				(when (and (characterp event)
						  (> (+ 8 val-width)
							  (croatoan:.cursor-position-x inputwin)))
					(croatoan:add-char inputwin event
						:color-pair '(:blue :black))
					(croatoan:refresh inputwin))))))

(defun user-confirm-p (scr msg &optional (cls NIL))
	"Ask the user to confirm (Yes/No) a message."
	(when cls (croatoan:clear scr))
	(croatoan:refresh scr)
	(let ((dw (make-instance 'croatoan:dialog-window
				  :center t :border t :width (max 20 (+ 4 (length msg)))
				  :max-item-length (max 4 (halve (length msg)))
				  :input-blocking t :layout '(1 2)
				  :message-height 1 :message-text msg
				  :items '(" Yes" " No"))))
		(croatoan:draw-menu dw)
		(croatoan:event-case (scr event)
			((nil) nil)
			((:left :right)
				(croatoan:update-menu dw event)
				(croatoan:draw-menu dw))
				(return-from croatoan:event-case
					(zerop (croatoan:.current-item-number dw)))))))

(defun inform-user (scr msg)
	"Display an informational message to the user"