Fix dialogue linebreaks; surround text with spaces
… finally! It took so dang long to get linebreaking and positioning working in a satisfactory way, but it’s done, dammit! And no-one can break it, never again! Also, surrounding the text with spaces makes it a bit more legible. Nice touch, right? =w=
This commit is contained in:
parent
845c2540a9
commit
1d30f66df4
|
@ -220,8 +220,8 @@ Returns the state for use with STATE-LOOP, pay attention!"
|
||||||
return the parameters of a text-box that can optimally fit the given TEXT in the
|
return the parameters of a text-box that can optimally fit the given TEXT in the
|
||||||
direction specified relative to the focal point. If a legible position can’t be
|
direction specified relative to the focal point. If a legible position can’t be
|
||||||
found, just give up! Return nil.
|
found, just give up! Return nil.
|
||||||
Otherwise, return a list list with the coordinates, max column, and max row — for
|
Otherwise, return a list list with the coordinates, textbox width, and textbox
|
||||||
use with RENDER-STRING."
|
height — all parameters for use with RENDER-STRING & co."
|
||||||
(let* ((text-x-margin (if rightp
|
(let* ((text-x-margin (if rightp
|
||||||
(+ (getf coords :x) 3)
|
(+ (getf coords :x) 3)
|
||||||
0))
|
0))
|
||||||
|
@ -231,30 +231,35 @@ use with RENDER-STRING."
|
||||||
(- (getf coords :x) 3))))
|
(- (getf coords :x) 3))))
|
||||||
(lines (ignore-errors (str:lines (…:linewrap-string text text-width))))
|
(lines (ignore-errors (str:lines (…:linewrap-string text text-width))))
|
||||||
(text-height (length lines)))
|
(text-height (length lines)))
|
||||||
(format *error-output* "HEIGHT: ~A WIDTH ~A LINES: ~A~%" text-height text-width lines)
|
(format *error-output* "HORIZ COORD: ~A HEIGHT: ~A WIDTH ~A LINES:~%~S~%" coords text-height text-width lines)
|
||||||
;; When this layout is valid…
|
;; When this layout is valid…
|
||||||
(when (and lines
|
(when (and lines
|
||||||
(>= height text-height) ;; If the text’ll fit on screen
|
(>= height text-height) ;; If the text’ll fit on screen
|
||||||
(> text-width 10)) ;; If the text is wide enough to be legible
|
(> text-width 10)) ;; If the text is wide enough to be legible
|
||||||
(let ((y (…:at-least 0 (- (getf coords :y)
|
(let* ((y (…:at-least 0 (- (getf coords :y)
|
||||||
(if (eq (length lines) 1) ;; Align toward the speaker’s face
|
(if (eq text-height 1) ;; Align toward the speaker’s face
|
||||||
1 0)
|
1 0)
|
||||||
(floor (/ (length lines) 2)))))
|
(floor (/ text-height 2)))))
|
||||||
(x (if (and (not rightp)
|
(x (if (and (not rightp)
|
||||||
(eq (length lines) 1))
|
(eq (length lines) 1))
|
||||||
(- text-width (length text))
|
(- text-width (length text))
|
||||||
text-x-margin)))
|
text-x-margin))
|
||||||
(list (list :x x :y y) ;; Coords
|
(y-margin (if (> (+ y (length lines)) height) ;; How many lines are off-screen
|
||||||
text-width ;;(+ x text-width) ;; Max column
|
(- (+ y (length lines)) height)
|
||||||
height))))) ;; Max row
|
0)))
|
||||||
|
(list
|
||||||
|
;; Coords of text-box’es top-left corner
|
||||||
|
(list :x x :y (- y y-margin))
|
||||||
|
text-width ;; Width of text-box
|
||||||
|
text-height))))) ;; Height of text-box
|
||||||
|
|
||||||
|
|
||||||
(defun optimal-text-placement-vertically (text coords &key (downp nil) (width 72) (height 20))
|
(defun optimal-text-placement-vertically (text coords &key (downp nil) (width 72) (height 20))
|
||||||
"Given a vertical direction (DOWNP defined or nil) and a focal point COORDS,)
|
"Given a vertical direction (DOWNP defined or nil) and a focal point COORDS,)
|
||||||
return the parameters of a text-box that can optimally fit the given TEXT in the
|
return the parameters of a text-box that can optimally fit the given TEXT in the
|
||||||
direction specified relative to the focal point. Return nil if no such placement
|
direction specified relative to the focal point. Return nil if no such placement
|
||||||
is found, otherwise return a list of the coordinates, max-column, and max-row
|
is found, otherwise return a list of the coordinates, textbox width, and textbox
|
||||||
(for use with RENDER-STRING)."
|
height (for use as parameters with RENDER-STRING et al.)."
|
||||||
(let* ((text-y-margin (if downp
|
(let* ((text-y-margin (if downp
|
||||||
(+ (getf coords :y) 2)
|
(+ (getf coords :y) 2)
|
||||||
(- (getf coords :y) 2)))
|
(- (getf coords :y) 2)))
|
||||||
|
@ -263,10 +268,10 @@ is found, otherwise return a list of the coordinates, max-column, and max-row
|
||||||
(- text-y-margin 1)))
|
(- text-y-margin 1)))
|
||||||
(text-width (floor (* width 3/5))) ;; Too wide’s illegible! So ⅗-screen.
|
(text-width (floor (* width 3/5))) ;; Too wide’s illegible! So ⅗-screen.
|
||||||
(lines (ignore-errors (str:lines (…:linewrap-string text text-width)))))
|
(lines (ignore-errors (str:lines (…:linewrap-string text text-width)))))
|
||||||
(format *error-output* "HEIGHT: ~A WIDTH ~A LINES: ~A~%" text-height text-width lines)
|
(format *error-output* "VERT HEIGHT: ~A WIDTH ~A LINES: ~A~%" text-height text-width lines)
|
||||||
;; When the text can be printed with this layout…
|
;; When the text can be printed with this layout…
|
||||||
(when (and lines (>= text-height (length lines)))
|
(when (and lines (>= text-height (length lines)))
|
||||||
(let ((y (…:at-least
|
(let* ((y (…:at-least
|
||||||
0
|
0
|
||||||
(if downp
|
(if downp
|
||||||
text-y-margin
|
text-y-margin
|
||||||
|
@ -276,10 +281,15 @@ is found, otherwise return a list of the coordinates, max-column, and max-row
|
||||||
(- (getf coords :x)
|
(- (getf coords :x)
|
||||||
(if (eq (length lines) 1)
|
(if (eq (length lines) 1)
|
||||||
(floor (/ (length (car lines)) 2))
|
(floor (/ (length (car lines)) 2))
|
||||||
(floor (/ text-width 2)))))))
|
(floor (/ text-width 2))))))
|
||||||
(list (list :x x :y y) ;; Coords
|
(x-margin (if (> (+ x text-width) width)
|
||||||
text-width ;;(+ x text-width) ;; Max column
|
(- (+ x text-width) width)
|
||||||
(+ y text-height)))))) ;; Max row
|
0)))
|
||||||
|
(list
|
||||||
|
;; Coords of text-box’es top-left corner
|
||||||
|
(list :x (- x x-margin) :y y)
|
||||||
|
text-width ;; Width of the text-box
|
||||||
|
(length lines)))))) ;; Height of text-box
|
||||||
|
|
||||||
|
|
||||||
(defun optimal-speech-layout (map dialogue &key (width 72) (height 20))
|
(defun optimal-speech-layout (map dialogue &key (width 72) (height 20))
|
||||||
|
@ -305,22 +315,30 @@ and max-row; for use with RENDER-STRING. Like so:
|
||||||
(optimal-text-placement-vertically text coords :width width :height height
|
(optimal-text-placement-vertically text coords :width width :height height
|
||||||
:downp (not playerp)))))
|
:downp (not playerp)))))
|
||||||
|
|
||||||
|
(defun ensure-dialogue-layout (map dialogue-list)
|
||||||
|
"Given a DIALOGUE-LIST, ensure that the FIRST line of dialogue has a :layout
|
||||||
|
property — that is, a property detailing the optimal width and coordinates for
|
||||||
|
its display."
|
||||||
|
(when (and (getf (car dialogue-list) :text)
|
||||||
|
(not (getf (car dialogue-list) :layout)))
|
||||||
|
(setf (getf (car dialogue-list) :layout)
|
||||||
|
(optimal-speech-layout map (car dialogue-list)))))
|
||||||
|
|
||||||
(defun render-dialogue-block (matrix map dialogue)
|
|
||||||
|
(defun render-dialogue-block (matrix dialogue)
|
||||||
"Render a bit of DIALOGUE to the MATRIX, in an intelligent fashion; that is,
|
"Render a bit of DIALOGUE to the MATRIX, in an intelligent fashion; that is,
|
||||||
make it pretty, dang it! >O<
|
make it pretty, dang it! >O<
|
||||||
☆:.。.o(≧▽≦)o.。.:☆"
|
☆:.。.o(≧▽≦)o.。.:☆"
|
||||||
(let* ((progress (getf dialogue :progress))
|
(let* ((progress (getf dialogue :progress))
|
||||||
(text (getf dialogue :text))
|
(text (getf dialogue :text))
|
||||||
(optimal-layout (when text (optimal-speech-layout map dialogue)))
|
(optimal-layout (getf dialogue :layout))
|
||||||
(coords (car optimal-layout)))
|
(coords (car optimal-layout)))
|
||||||
(when (and text optimal-layout)
|
(when (and text optimal-layout)
|
||||||
(format *error-output* "~A~%" optimal-layout)
|
(✎:render-fill-rectangle matrix #\space
|
||||||
;; (✎:render-fill-rectangle matrix #\space
|
(list :x (- (getf coords :x) 1)
|
||||||
;; (list :x (- (getf coords :x) 1)
|
:y (- (getf coords :y) 1))
|
||||||
;; :y (- (getf coords :y) 1)
|
(+ (second optimal-layout) 2) ;; Width
|
||||||
;; (- (second optimal-layout) (getf coords :x) -2)
|
(+ (third optimal-layout) 1)) ;; Height
|
||||||
;; (- (third optimal-layout) (getf coords :y) -2))
|
|
||||||
(✎:render-string
|
(✎:render-string
|
||||||
matrix text (first optimal-layout)
|
matrix text (first optimal-layout)
|
||||||
:width (second optimal-layout)
|
:width (second optimal-layout)
|
||||||
|
@ -332,7 +350,8 @@ make it pretty, dang it! >O<
|
||||||
Helper function for DIALOGUE-STATE."
|
Helper function for DIALOGUE-STATE."
|
||||||
(when (getf (car dialogue-list) :text)
|
(when (getf (car dialogue-list) :text)
|
||||||
(✎:show-cursor)
|
(✎:show-cursor)
|
||||||
(render-dialogue-block matrix map (car dialogue-list))))
|
(ensure-dialogue-layout map dialogue-list)
|
||||||
|
(render-dialogue-block matrix (car dialogue-list))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ No word-wrapping is done, even if the line exceeds the MATRIX’es size!"
|
||||||
(y (getf coords :y)))
|
(y (getf coords :y)))
|
||||||
(render-string-verbatim
|
(render-string-verbatim
|
||||||
matrix
|
matrix
|
||||||
(…:linewrap-string (subseq text 0 char-count) width)
|
(subseq (…:linewrap-string text width) 0 char-count)
|
||||||
coords)))
|
coords)))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,8 @@ side (either :CENTER, :LEFT, or :RIGHT)."
|
||||||
(defun linewrap-string (string width)
|
(defun linewrap-string (string width)
|
||||||
"Break a STRING into several lines, each one no larger than WIDTH. Uses
|
"Break a STRING into several lines, each one no larger than WIDTH. Uses
|
||||||
newlines and hypens (to break long words) as necessary."
|
newlines and hypens (to break long words) as necessary."
|
||||||
(let ((spaces (append '(0) (search-all " " string)))
|
(let* ((string (str:replace-all (string #\newline) " " string))
|
||||||
|
(spaces (append '(0) (search-all " " string)))
|
||||||
(index width))
|
(index width))
|
||||||
(loop while (< index (length string))
|
(loop while (< index (length string))
|
||||||
do (let ((closest-space (car (closest-below index spaces)))
|
do (let ((closest-space (car (closest-below index spaces)))
|
||||||
|
@ -71,8 +72,7 @@ newlines and hypens (to break long words) as necessary."
|
||||||
;; Break up long words with a hyphen
|
;; Break up long words with a hyphen
|
||||||
(return
|
(return
|
||||||
(linewrap-string
|
(linewrap-string
|
||||||
(str:insert "- " (- index 1)
|
(str:insert "- " (- index 1) string)
|
||||||
(str:replace-all (string #\newline) " " string))
|
|
||||||
width))
|
width))
|
||||||
;; Replace eligible spaces with newlines uwu
|
;; Replace eligible spaces with newlines uwu
|
||||||
(progn
|
(progn
|
||||||
|
|
Ŝarĝante…
Reference in New Issue