Give the terminal a compose bar the size of the draft, and a strip that scrolls
Three rows were kept for the compose field whatever was in it: one you typed in and two ruled empty boxes under it, under a placeholder advertising a paragraph nobody writes in an IRC client. The field is the size of the draft now — a line until there is a second line, growing to five and no further — counted here rather than reported, since nothing in the terminal fires `:on-rows`. Send and the picture beside it centre on the box instead of sitting on its first row, and a row of air goes above the bar: a spacer, not a `:margin-top`, which a terminal does not read. And the overview strip is a `:scroll` rather than the first eight lines with the rest simply gone. Two things stood in the way of that. Its height was counted at twenty points a line, which is a little over half a row here, so eight lines asked for five rows and got five. And a `:scroll` with no ceiling is as tall as its content: it took the rows the conversation was reading in and drew every line rather than scrolling any. Both are one number now, and `overview-list-height` is what the pane is given and what the backlog is laid out against. The ceiling needs `:max-height` honoured for a box in jolt-tui, which it now is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5b10207 parent: d8fadee modified
common/frq/screens/chat.cljc +122 -39 | @@ -40,6 +40,35 @@ | ||
| 40 | 40 | |
| 41 | 41 | (defonce ^:private draft-rows (atom 1)) |
| 42 | 42 | |
| 43 | +;; How tall the compose field is allowed to grow. The same ceiling in both | |
| 44 | +;; backends, for different reasons: a window past it scrolls with the caret in | |
| 45 | +;; view, and a terminal past it would be spending a quarter of the screen on | |
| 46 | +;; a message that has not been sent yet. | |
| 47 | +(def ^:private draft-max-rows 5) | |
| 48 | + | |
| 49 | +(defn- terminal-draft-rows | |
| 50 | + "How many rows the terminal's compose field wants for what is in it. | |
| 51 | + | |
| 52 | + The library sizes an entry by the `:rows` it was given and reports nothing | |
| 53 | + back — there is no `:on-rows` to grow on, the way a window grows — so the | |
| 54 | + wrapping is counted here instead, and the answer is both what the field is | |
| 55 | + given and what `below-messages` keeps for it. | |
| 56 | + | |
| 57 | + An empty field is one row, so the bar starts as a line rather than as a | |
| 58 | + block of ruled nothing, and the text begins at the top of the rect and grows | |
| 59 | + downwards from there. | |
| 60 | + | |
| 61 | + The width is the row less what is beside the field — the picture button, the | |
| 62 | + Send button, and the gaps around them, about twenty-two cells of eight points | |
| 63 | + each. An estimate, and the cheap way to be wrong: a row over-counted is a row | |
| 64 | + of conversation, where a row under-counted is a line of the draft with | |
| 65 | + nowhere to go." | |
| 66 | + [] | |
| 67 | + (let [cols (max 20 (quot (- @cells/window-width (* 22 8)) 8)) | |
| 68 | + wrapped (fn [line] (max 1 (long (Math/ceil (/ (count line) (double cols))))))] | |
| 69 | + (min draft-max-rows | |
| 70 | + (max 1 (reduce + (map wrapped (str/split-lines (or @cells/draft "")))))))) | |
| 71 | + | |
| 43 | 72 | ;; What the rows under the conversation need left to them: the jump button's |
| 44 | 73 | ;; row, the separator, the compose bar and the air around it. The columns of |
| 45 | 74 | ;; the row reserve it, and so nothing inside them has to — a `:scroll` that |
| @@ -75,9 +104,29 @@ | ||
| 75 | 104 | 108) |
| 76 | 105 | (def overview-lines 8) |
| 77 | 106 | |
| 107 | +(defn- overview-list-height | |
| 108 | + "How tall the strip's list of lines is, in points. | |
| 109 | + | |
| 110 | + The number is both the reserve the backlog is laid out against and the | |
| 111 | + height the terminal's scroll is given, and it has to be one number: a pane | |
| 112 | + an inch taller than what was kept for it is a compose bar an inch off the | |
| 113 | + bottom of the screen. | |
| 114 | + | |
| 115 | + Counted from the lines there are, up to the ceiling — a room with two lines | |
| 116 | + in it should not have a screenful reserved against it — and from the ceiling | |
| 117 | + once there are more, which is the point at which the pane starts scrolling | |
| 118 | + instead of growing. | |
| 119 | + | |
| 120 | + A row of chrome a line, not the twenty points a window's line box is: a line | |
| 121 | + here is one row of the terminal, and twenty points of a window's scale comes | |
| 122 | + out as a little over half of one. Eight lines then asked for five rows, got | |
| 123 | + five, and cut three lines off a strip that had just been given a scroll to | |
| 124 | + show them in." | |
| 125 | + [] | |
| 126 | + (* @chrome-row (min overview-lines (count (actions/recent-everywhere))))) | |
| 127 | + | |
| 78 | 128 | (defn- overview-height [] |
| 79 | - (* (chrome-scale) | |
| 80 | - (+ 24 (* 20 (min overview-lines (count (actions/recent-everywhere)))) 16))) | |
| 129 | + (+ (overview-list-height) (* (chrome-scale) (+ 24 16)))) | |
| 81 | 130 | |
| 82 | 131 | (defn- below-messages [] |
| 83 | 132 | ;; 115 is that, counted: the gap under the row of columns, the jump button's |
| @@ -94,18 +143,20 @@ | ||
| 94 | 143 | (+ 115 |
| 95 | 144 | (if @cells/replying-to 34 0) |
| 96 | 145 | (if @cells/attachment 76 0))) |
| 97 | - ;; The two extra rows the terminal's compose field wraps into, in points: | |
| 98 | - ;; a row down the page is two cells' worth of the scale. | |
| 99 | - (if @terminal? (* 4 (chrome-scale)) 0) | |
| 100 | - ;; And the lines a window's compose field has GROWN by. Unscaled and | |
| 101 | - ;; outside the terminal's arm on purpose: the field only reports its | |
| 102 | - ;; height where it can change — the terminal's is the fixed block of | |
| 103 | - ;; three rows reserved just above — so `draft-rows` is one there and | |
| 104 | - ;; this term is zero. Twenty points a line is a 16-point face's line | |
| 105 | - ;; box rounded up: the reserve has to be at least what the field took, | |
| 106 | - ;; because a point too few does not crop the list, it slides the | |
| 107 | - ;; compose bar off the bottom of the window. | |
| 108 | - (* 20 (dec @draft-rows)) | |
| 146 | + ;; The rows the compose field has GROWN by, and the row of air above it. | |
| 147 | + ;; | |
| 148 | + ;; Twenty points a line in a window: a 16-point face's line box rounded | |
| 149 | + ;; up, and the reserve has to be at least what the field took, because a | |
| 150 | + ;; point too few does not crop the list — it slides the compose bar off | |
| 151 | + ;; the bottom of the window. `draft-rows` is what the field reported. | |
| 152 | + ;; | |
| 153 | + ;; A row of chrome a line in a terminal, counted here rather than | |
| 154 | + ;; reported: nothing there fires `:on-rows`, so `terminal-draft-rows` is | |
| 155 | + ;; asked the same question the field was given its height by. It used to | |
| 156 | + ;; be a fixed three rows whatever was in it, two of them blank. | |
| 157 | + (if @terminal? | |
| 158 | + (* @chrome-row (terminal-draft-rows)) | |
| 159 | + (* 20 (dec @draft-rows))) | |
| 109 | 160 | ;; And the overview strip, when it is up. Reserved here rather than |
| 110 | 161 | ;; anywhere else because this is the number the backlog is laid out |
| 111 | 162 | ;; against: without it the strip is drawn past the bottom of the window |
| @@ -948,11 +999,12 @@ | ||
| 948 | 999 | horizontal split this is. The backlog above keeps its own scroll and its own |
| 949 | 1000 | place in it, so reading down here does not move the conversation. |
| 950 | 1001 | |
| 951 | - A terminal gets a handful of lines and no scroll. Its rows are cells rather | |
| 952 | - than points, and a second scrolling pane in a screen that is already a | |
| 953 | - conversation, a compose bar and a tab bar leaves neither half enough rows to | |
| 954 | - be worth reading — so there it stays the strip it was, and `below-messages` | |
| 955 | - reserves it by the row." | |
| 1002 | + A terminal scrolls it too, but inside a fixed block of rows rather than a | |
| 1003 | + half of the column: the screen is already a conversation, a compose bar and | |
| 1004 | + a tab bar, and a second half-height pane would leave neither half enough | |
| 1005 | + rows to read. So the strip is as tall as `overview-lines`, `below-messages` | |
| 1006 | + reserves exactly that, and the lines past the eighth are a wheel or a page | |
| 1007 | + away instead of being cut off with nothing to say they were there." | |
| 956 | 1008 | [] |
| 957 | 1009 | (let [lines (actions/recent-everywhere) |
| 958 | 1010 | ;; The way back, and only while there is somewhere to go: the strip |
| @@ -998,10 +1050,23 @@ | ||
| 998 | 1050 | ms) |
| 999 | 1051 | [[:dim-label {:label "Nothing has been said in any other room yet."}]]))] |
| 1000 | 1052 | (if @terminal? |
| 1001 | - (into [:vbox {:key :overview :spacing 4 :margin-top 4} | |
| 1002 | - [:separator {}] | |
| 1003 | - [heading]] | |
| 1004 | - (rows (take overview-lines lines))) | |
| 1053 | + [:vbox {:key :overview :spacing 4 :margin-top 4} | |
| 1054 | + [:separator {}] | |
| 1055 | + [heading] | |
| 1056 | + ;; The same name as the window's, and for the same reason: the strip | |
| 1057 | + ;; comes and goes with a keypress, and a reader who had paged down it | |
| 1058 | + ;; should not be put back at the top for having looked away. | |
| 1059 | + (into [:scroll {:scroll-key "overview-list" :orientation :vertical | |
| 1060 | + :spacing 4 | |
| 1061 | + ;; The reserve, exactly, and as a ceiling as well as a | |
| 1062 | + ;; floor — see `overview-list-height`. A height-request | |
| 1063 | + ;; on its own is a minimum: the pane took the height of | |
| 1064 | + ;; everything in it, drew every line, and paid for the | |
| 1065 | + ;; surplus out of the conversation above rather than | |
| 1066 | + ;; scrolling. | |
| 1067 | + :height-request (overview-list-height) | |
| 1068 | + :max-height (overview-list-height)}] | |
| 1069 | + (rows lines))] | |
| 1005 | 1070 | [:vbox {:key :overview :spacing 4 :margin-top 4 :fill-height true} |
| 1006 | 1071 | [:separator {}] |
| 1007 | 1072 | [heading] |
| @@ -1243,6 +1308,12 @@ | ||
| 1243 | 1308 | ;; reply banner, the edit banner and the attachment share a wrapper now |
| 1244 | 1309 | ;; and cost one between them whether or not they have anything in them. |
| 1245 | 1310 | ;; This margin plus the window's own is what answers it underneath. |
| 1311 | + ;; Air above the bar as well as under it. A row rather than a margin | |
| 1312 | + ;; because a terminal reads `:margin` and not `:margin-top`, and this is | |
| 1313 | + ;; the backend that needs it: the banners above are usually empty and the | |
| 1314 | + ;; strip or the last line of the conversation sat directly on the field, | |
| 1315 | + ;; so a message being typed read as one more message in the room. | |
| 1316 | + (when @terminal? [:spacer {:key :compose-gap :size @chrome-row}]) | |
| 1246 | 1317 | [:hbox {:spacing 8 :align :center :margin-bottom 12} |
| 1247 | 1318 | ;; narrow enough that Send keeps its place on a phone-width row |
| 1248 | 1319 | ;; A picture is pasted where everything else is typed: Ctrl+V. The field |
| @@ -1262,14 +1333,24 @@ | ||
| 1262 | 1333 | (if (and (actions/desktop?) (not @terminal?)) |
| 1263 | 1334 | [:image {:src "src/frq/icons/insert-image.png" |
| 1264 | 1335 | :size [36 36] |
| 1336 | + ;; On the middle of the field rather than the top of it: the | |
| 1337 | + ;; box grows downwards as a message is typed, and a button | |
| 1338 | + ;; pinned to its first row drifts away from the thing it acts | |
| 1339 | + ;; on. Read by the terminal, where the row can be several | |
| 1340 | + ;; cells tall; a window's backends ignore it. | |
| 1341 | + :valign :center | |
| 1265 | 1342 | ;; for a backend that sizes a picture by its bounds instead |
| 1266 | 1343 | :max-width 36 |
| 1267 | 1344 | :max-height 36 |
| 1268 | 1345 | :on-click actions/open-image-picker!}] |
| 1269 | - [:button {:label "🖼" :on-click actions/open-image-picker!}]) | |
| 1270 | - ;; In a terminal the row is the width of the screen and a message is | |
| 1271 | - ;; longer than 260 points of it: the field takes the surplus and wraps | |
| 1272 | - ;; into three rows rather than scrolling one line sideways. | |
| 1346 | + [:button {:label "🖼" :valign :center :on-click actions/open-image-picker!}]) | |
| 1347 | + ;; In a terminal the row is the width of the screen, so the field takes | |
| 1348 | + ;; the surplus rather than scrolling one line sideways — and it is as | |
| 1349 | + ;; tall as what has been typed into it. Three rows were kept for it | |
| 1350 | + ;; always, empty almost always, drawn as two ruled boxes under the one | |
| 1351 | + ;; being typed in: rows spent on a paragraph nobody had written, taken | |
| 1352 | + ;; off the conversation above. Now the box is a line until there is a | |
| 1353 | + ;; second line to put in it. | |
| 1273 | 1354 | [:entry {:text @cells/draft |
| 1274 | 1355 | :width-request 260 |
| 1275 | 1356 | ;; Always, not only in a terminal. A window is the case that |
| @@ -1278,19 +1359,21 @@ | ||
| 1278 | 1359 | ;; of the bar with the rest of it empty. The number stays as |
| 1279 | 1360 | ;; the minimum it always was. |
| 1280 | 1361 | :hexpand true |
| 1281 | - :rows (if @terminal? 3 1) | |
| 1282 | - ;; In a window the field starts as one line and takes another | |
| 1283 | - ;; every time the message stops fitting, up to five — past | |
| 1284 | - ;; which it scrolls, keeping the caret in view. A paragraph | |
| 1285 | - ;; typed into a one-line box was readable a dozen characters | |
| 1286 | - ;; at a time, which is not how anybody writes one. | |
| 1287 | - :max-rows 5 | |
| 1362 | + :rows (if @terminal? (terminal-draft-rows) 1) | |
| 1363 | + ;; The field starts as one line and takes another every time | |
| 1364 | + ;; the message stops fitting, up to five — past which it | |
| 1365 | + ;; scrolls, keeping the caret in view. A paragraph typed into a | |
| 1366 | + ;; one-line box was readable a dozen characters at a time, | |
| 1367 | + ;; which is not how anybody writes one. | |
| 1368 | + ;; | |
| 1369 | + ;; A window grows itself and says so through `:on-rows`; a | |
| 1370 | + ;; terminal is given the height `terminal-draft-rows` counted, | |
| 1371 | + ;; which is the same ceiling reached the other way round. | |
| 1372 | + :max-rows draft-max-rows | |
| 1288 | 1373 | :on-rows #(reset! draft-rows %) |
| 1289 | - ;; The break is worth saying out loud where it is new: Enter | |
| 1290 | - ;; sends, as it always has, and the box under it takes a | |
| 1291 | - ;; paragraph now — which nobody would think to try unasked. | |
| 1292 | - :placeholder (if @terminal? "Message — Shift+Enter for a new line" "Message") | |
| 1374 | + :placeholder "Message" | |
| 1293 | 1375 | :on-change #(reset! cells/draft %) |
| 1294 | 1376 | :on-paste-empty actions/paste-image! |
| 1295 | 1377 | :on-activate actions/send-draft!}] |
| 1296 | - [:button {:label "Send" :kind :primary :on-click actions/send-draft!}]]])) | |
| 1378 | + [:button {:label "Send" :kind :primary :valign :center | |
| 1379 | + :on-click actions/send-draft!}]]])) | |
| @@ -40,6 +40,35 @@ | |||
| 40 | 40 | ||
| 41 | (defonce ^:private draft-rows (atom 1)) | 41 | (defonce ^:private draft-rows (atom 1)) |
| 42 | 42 | ||
| 43 | +;; How tall the compose field is allowed to grow. The same ceiling in both | ||
| 44 | +;; backends, for different reasons: a window past it scrolls with the caret in | ||
| 45 | +;; view, and a terminal past it would be spending a quarter of the screen on | ||
| 46 | +;; a message that has not been sent yet. | ||
| 47 | +(def ^:private draft-max-rows 5) | ||
| 48 | + | ||
| 49 | +(defn- terminal-draft-rows | ||
| 50 | + "How many rows the terminal's compose field wants for what is in it. | ||
| 51 | + | ||
| 52 | + The library sizes an entry by the `:rows` it was given and reports nothing | ||
| 53 | + back — there is no `:on-rows` to grow on, the way a window grows — so the | ||
| 54 | + wrapping is counted here instead, and the answer is both what the field is | ||
| 55 | + given and what `below-messages` keeps for it. | ||
| 56 | + | ||
| 57 | + An empty field is one row, so the bar starts as a line rather than as a | ||
| 58 | + block of ruled nothing, and the text begins at the top of the rect and grows | ||
| 59 | + downwards from there. | ||
| 60 | + | ||
| 61 | + The width is the row less what is beside the field — the picture button, the | ||
| 62 | + Send button, and the gaps around them, about twenty-two cells of eight points | ||
| 63 | + each. An estimate, and the cheap way to be wrong: a row over-counted is a row | ||
| 64 | + of conversation, where a row under-counted is a line of the draft with | ||
| 65 | + nowhere to go." | ||
| 66 | + [] | ||
| 67 | + (let [cols (max 20 (quot (- @cells/window-width (* 22 8)) 8)) | ||
| 68 | + wrapped (fn [line] (max 1 (long (Math/ceil (/ (count line) (double cols))))))] | ||
| 69 | + (min draft-max-rows | ||
| 70 | + (max 1 (reduce + (map wrapped (str/split-lines (or @cells/draft "")))))))) | ||
| 71 | + | ||
| 43 | ;; What the rows under the conversation need left to them: the jump button's | 72 | ;; What the rows under the conversation need left to them: the jump button's |
| 44 | ;; row, the separator, the compose bar and the air around it. The columns of | 73 | ;; row, the separator, the compose bar and the air around it. The columns of |
| 45 | ;; the row reserve it, and so nothing inside them has to — a `:scroll` that | 74 | ;; the row reserve it, and so nothing inside them has to — a `:scroll` that |
| @@ -75,9 +104,29 @@ | |||
| 75 | 108) | 104 | 108) |
| 76 | (def overview-lines 8) | 105 | (def overview-lines 8) |
| 77 | 106 | ||
| 107 | +(defn- overview-list-height | ||
| 108 | + "How tall the strip's list of lines is, in points. | ||
| 109 | + | ||
| 110 | + The number is both the reserve the backlog is laid out against and the | ||
| 111 | + height the terminal's scroll is given, and it has to be one number: a pane | ||
| 112 | + an inch taller than what was kept for it is a compose bar an inch off the | ||
| 113 | + bottom of the screen. | ||
| 114 | + | ||
| 115 | + Counted from the lines there are, up to the ceiling — a room with two lines | ||
| 116 | + in it should not have a screenful reserved against it — and from the ceiling | ||
| 117 | + once there are more, which is the point at which the pane starts scrolling | ||
| 118 | + instead of growing. | ||
| 119 | + | ||
| 120 | + A row of chrome a line, not the twenty points a window's line box is: a line | ||
| 121 | + here is one row of the terminal, and twenty points of a window's scale comes | ||
| 122 | + out as a little over half of one. Eight lines then asked for five rows, got | ||
| 123 | + five, and cut three lines off a strip that had just been given a scroll to | ||
| 124 | + show them in." | ||
| 125 | + [] | ||
| 126 | + (* @chrome-row (min overview-lines (count (actions/recent-everywhere))))) | ||
| 127 | + | ||
| 78 | (defn- overview-height [] | 128 | (defn- overview-height [] |
| 79 | - (* (chrome-scale) | 129 | + (+ (overview-list-height) (* (chrome-scale) (+ 24 16)))) |
| 80 | - (+ 24 (* 20 (min overview-lines (count (actions/recent-everywhere)))) 16))) | ||
| 81 | 130 | ||
| 82 | (defn- below-messages [] | 131 | (defn- below-messages [] |
| 83 | ;; 115 is that, counted: the gap under the row of columns, the jump button's | 132 | ;; 115 is that, counted: the gap under the row of columns, the jump button's |
| @@ -94,18 +143,20 @@ | |||
| 94 | (+ 115 | 143 | (+ 115 |
| 95 | (if @cells/replying-to 34 0) | 144 | (if @cells/replying-to 34 0) |
| 96 | (if @cells/attachment 76 0))) | 145 | (if @cells/attachment 76 0))) |
| 97 | - ;; The two extra rows the terminal's compose field wraps into, in points: | 146 | + ;; The rows the compose field has GROWN by, and the row of air above it. |
| 98 | - ;; a row down the page is two cells' worth of the scale. | 147 | + ;; |
| 99 | - (if @terminal? (* 4 (chrome-scale)) 0) | 148 | + ;; Twenty points a line in a window: a 16-point face's line box rounded |
| 100 | - ;; And the lines a window's compose field has GROWN by. Unscaled and | 149 | + ;; up, and the reserve has to be at least what the field took, because a |
| 101 | - ;; outside the terminal's arm on purpose: the field only reports its | 150 | + ;; point too few does not crop the list — it slides the compose bar off |
| 102 | - ;; height where it can change — the terminal's is the fixed block of | 151 | + ;; the bottom of the window. `draft-rows` is what the field reported. |
| 103 | - ;; three rows reserved just above — so `draft-rows` is one there and | 152 | + ;; |
| 104 | - ;; this term is zero. Twenty points a line is a 16-point face's line | 153 | + ;; A row of chrome a line in a terminal, counted here rather than |
| 105 | - ;; box rounded up: the reserve has to be at least what the field took, | 154 | + ;; reported: nothing there fires `:on-rows`, so `terminal-draft-rows` is |
| 106 | - ;; because a point too few does not crop the list, it slides the | 155 | + ;; asked the same question the field was given its height by. It used to |
| 107 | - ;; compose bar off the bottom of the window. | 156 | + ;; be a fixed three rows whatever was in it, two of them blank. |
| 108 | - (* 20 (dec @draft-rows)) | 157 | + (if @terminal? |
| 158 | + (* @chrome-row (terminal-draft-rows)) | ||
| 159 | + (* 20 (dec @draft-rows))) | ||
| 109 | ;; And the overview strip, when it is up. Reserved here rather than | 160 | ;; And the overview strip, when it is up. Reserved here rather than |
| 110 | ;; anywhere else because this is the number the backlog is laid out | 161 | ;; anywhere else because this is the number the backlog is laid out |
| 111 | ;; against: without it the strip is drawn past the bottom of the window | 162 | ;; against: without it the strip is drawn past the bottom of the window |
| @@ -948,11 +999,12 @@ | |||
| 948 | horizontal split this is. The backlog above keeps its own scroll and its own | 999 | horizontal split this is. The backlog above keeps its own scroll and its own |
| 949 | place in it, so reading down here does not move the conversation. | 1000 | place in it, so reading down here does not move the conversation. |
| 950 | 1001 | ||
| 951 | - A terminal gets a handful of lines and no scroll. Its rows are cells rather | 1002 | + A terminal scrolls it too, but inside a fixed block of rows rather than a |
| 952 | - than points, and a second scrolling pane in a screen that is already a | 1003 | + half of the column: the screen is already a conversation, a compose bar and |
| 953 | - conversation, a compose bar and a tab bar leaves neither half enough rows to | 1004 | + a tab bar, and a second half-height pane would leave neither half enough |
| 954 | - be worth reading — so there it stays the strip it was, and `below-messages` | 1005 | + rows to read. So the strip is as tall as `overview-lines`, `below-messages` |
| 955 | - reserves it by the row." | 1006 | + reserves exactly that, and the lines past the eighth are a wheel or a page |
| 1007 | + away instead of being cut off with nothing to say they were there." | ||
| 956 | [] | 1008 | [] |
| 957 | (let [lines (actions/recent-everywhere) | 1009 | (let [lines (actions/recent-everywhere) |
| 958 | ;; The way back, and only while there is somewhere to go: the strip | 1010 | ;; The way back, and only while there is somewhere to go: the strip |
| @@ -998,10 +1050,23 @@ | |||
| 998 | ms) | 1050 | ms) |
| 999 | [[:dim-label {:label "Nothing has been said in any other room yet."}]]))] | 1051 | [[:dim-label {:label "Nothing has been said in any other room yet."}]]))] |
| 1000 | (if @terminal? | 1052 | (if @terminal? |
| 1001 | - (into [:vbox {:key :overview :spacing 4 :margin-top 4} | 1053 | + [:vbox {:key :overview :spacing 4 :margin-top 4} |
| 1002 | - [:separator {}] | 1054 | + [:separator {}] |
| 1003 | - [heading]] | 1055 | + [heading] |
| 1004 | - (rows (take overview-lines lines))) | 1056 | + ;; The same name as the window's, and for the same reason: the strip |
| 1057 | + ;; comes and goes with a keypress, and a reader who had paged down it | ||
| 1058 | + ;; should not be put back at the top for having looked away. | ||
| 1059 | + (into [:scroll {:scroll-key "overview-list" :orientation :vertical | ||
| 1060 | + :spacing 4 | ||
| 1061 | + ;; The reserve, exactly, and as a ceiling as well as a | ||
| 1062 | + ;; floor — see `overview-list-height`. A height-request | ||
| 1063 | + ;; on its own is a minimum: the pane took the height of | ||
| 1064 | + ;; everything in it, drew every line, and paid for the | ||
| 1065 | + ;; surplus out of the conversation above rather than | ||
| 1066 | + ;; scrolling. | ||
| 1067 | + :height-request (overview-list-height) | ||
| 1068 | + :max-height (overview-list-height)}] | ||
| 1069 | + (rows lines))] | ||
| 1005 | [:vbox {:key :overview :spacing 4 :margin-top 4 :fill-height true} | 1070 | [:vbox {:key :overview :spacing 4 :margin-top 4 :fill-height true} |
| 1006 | [:separator {}] | 1071 | [:separator {}] |
| 1007 | [heading] | 1072 | [heading] |
| @@ -1243,6 +1308,12 @@ | |||
| 1243 | ;; reply banner, the edit banner and the attachment share a wrapper now | 1308 | ;; reply banner, the edit banner and the attachment share a wrapper now |
| 1244 | ;; and cost one between them whether or not they have anything in them. | 1309 | ;; and cost one between them whether or not they have anything in them. |
| 1245 | ;; This margin plus the window's own is what answers it underneath. | 1310 | ;; This margin plus the window's own is what answers it underneath. |
| 1311 | + ;; Air above the bar as well as under it. A row rather than a margin | ||
| 1312 | + ;; because a terminal reads `:margin` and not `:margin-top`, and this is | ||
| 1313 | + ;; the backend that needs it: the banners above are usually empty and the | ||
| 1314 | + ;; strip or the last line of the conversation sat directly on the field, | ||
| 1315 | + ;; so a message being typed read as one more message in the room. | ||
| 1316 | + (when @terminal? [:spacer {:key :compose-gap :size @chrome-row}]) | ||
| 1246 | [:hbox {:spacing 8 :align :center :margin-bottom 12} | 1317 | [:hbox {:spacing 8 :align :center :margin-bottom 12} |
| 1247 | ;; narrow enough that Send keeps its place on a phone-width row | 1318 | ;; narrow enough that Send keeps its place on a phone-width row |
| 1248 | ;; A picture is pasted where everything else is typed: Ctrl+V. The field | 1319 | ;; A picture is pasted where everything else is typed: Ctrl+V. The field |
| @@ -1262,14 +1333,24 @@ | |||
| 1262 | (if (and (actions/desktop?) (not @terminal?)) | 1333 | (if (and (actions/desktop?) (not @terminal?)) |
| 1263 | [:image {:src "src/frq/icons/insert-image.png" | 1334 | [:image {:src "src/frq/icons/insert-image.png" |
| 1264 | :size [36 36] | 1335 | :size [36 36] |
| 1336 | + ;; On the middle of the field rather than the top of it: the | ||
| 1337 | + ;; box grows downwards as a message is typed, and a button | ||
| 1338 | + ;; pinned to its first row drifts away from the thing it acts | ||
| 1339 | + ;; on. Read by the terminal, where the row can be several | ||
| 1340 | + ;; cells tall; a window's backends ignore it. | ||
| 1341 | + :valign :center | ||
| 1265 | ;; for a backend that sizes a picture by its bounds instead | 1342 | ;; for a backend that sizes a picture by its bounds instead |
| 1266 | :max-width 36 | 1343 | :max-width 36 |
| 1267 | :max-height 36 | 1344 | :max-height 36 |
| 1268 | :on-click actions/open-image-picker!}] | 1345 | :on-click actions/open-image-picker!}] |
| 1269 | - [:button {:label "🖼" :on-click actions/open-image-picker!}]) | 1346 | + [:button {:label "🖼" :valign :center :on-click actions/open-image-picker!}]) |
| 1270 | - ;; In a terminal the row is the width of the screen and a message is | 1347 | + ;; In a terminal the row is the width of the screen, so the field takes |
| 1271 | - ;; longer than 260 points of it: the field takes the surplus and wraps | 1348 | + ;; the surplus rather than scrolling one line sideways — and it is as |
| 1272 | - ;; into three rows rather than scrolling one line sideways. | 1349 | + ;; tall as what has been typed into it. Three rows were kept for it |
| 1350 | + ;; always, empty almost always, drawn as two ruled boxes under the one | ||
| 1351 | + ;; being typed in: rows spent on a paragraph nobody had written, taken | ||
| 1352 | + ;; off the conversation above. Now the box is a line until there is a | ||
| 1353 | + ;; second line to put in it. | ||
| 1273 | [:entry {:text @cells/draft | 1354 | [:entry {:text @cells/draft |
| 1274 | :width-request 260 | 1355 | :width-request 260 |
| 1275 | ;; Always, not only in a terminal. A window is the case that | 1356 | ;; Always, not only in a terminal. A window is the case that |
| @@ -1278,19 +1359,21 @@ | |||
| 1278 | ;; of the bar with the rest of it empty. The number stays as | 1359 | ;; of the bar with the rest of it empty. The number stays as |
| 1279 | ;; the minimum it always was. | 1360 | ;; the minimum it always was. |
| 1280 | :hexpand true | 1361 | :hexpand true |
| 1281 | - :rows (if @terminal? 3 1) | 1362 | + :rows (if @terminal? (terminal-draft-rows) 1) |
| 1282 | - ;; In a window the field starts as one line and takes another | 1363 | + ;; The field starts as one line and takes another every time |
| 1283 | - ;; every time the message stops fitting, up to five — past | 1364 | + ;; the message stops fitting, up to five — past which it |
| 1284 | - ;; which it scrolls, keeping the caret in view. A paragraph | 1365 | + ;; scrolls, keeping the caret in view. A paragraph typed into a |
| 1285 | - ;; typed into a one-line box was readable a dozen characters | 1366 | + ;; one-line box was readable a dozen characters at a time, |
| 1286 | - ;; at a time, which is not how anybody writes one. | 1367 | + ;; which is not how anybody writes one. |
| 1287 | - :max-rows 5 | 1368 | + ;; |
| 1369 | + ;; A window grows itself and says so through `:on-rows`; a | ||
| 1370 | + ;; terminal is given the height `terminal-draft-rows` counted, | ||
| 1371 | + ;; which is the same ceiling reached the other way round. | ||
| 1372 | + :max-rows draft-max-rows | ||
| 1288 | :on-rows #(reset! draft-rows %) | 1373 | :on-rows #(reset! draft-rows %) |
| 1289 | - ;; The break is worth saying out loud where it is new: Enter | 1374 | + :placeholder "Message" |
| 1290 | - ;; sends, as it always has, and the box under it takes a | ||
| 1291 | - ;; paragraph now — which nobody would think to try unasked. | ||
| 1292 | - :placeholder (if @terminal? "Message — Shift+Enter for a new line" "Message") | ||
| 1293 | :on-change #(reset! cells/draft %) | 1375 | :on-change #(reset! cells/draft %) |
| 1294 | :on-paste-empty actions/paste-image! | 1376 | :on-paste-empty actions/paste-image! |
| 1295 | :on-activate actions/send-draft!}] | 1377 | :on-activate actions/send-draft!}] |
| 1296 | - [:button {:label "Send" :kind :primary :on-click actions/send-draft!}]]])) | 1378 | + [:button {:label "Send" :kind :primary :valign :center |
| 1379 | + :on-click actions/send-draft!}]]])) | ||