|
202 | 202 | (file/quick-open! {"Defaults" (table ["" 2018 2017] table-data)})))
|
203 | 203 |
|
204 | 204 |
|
| 205 | +;;; Helpers to manipulate [[cell]] data structures |
| 206 | + |
| 207 | + |
205 | 208 | (defn with-title
|
206 |
| - [title [row & _ :as rows]] |
| 209 | + "Prepend a centered `title` row to the `grid` with the same width as the |
| 210 | + first row of the grid." |
| 211 | + [title [row & _ :as grid]] |
207 | 212 | (let [width (count row)]
|
208 | 213 | (cons
|
209 |
| - [(dims title {:width width})] |
210 |
| - rows))) |
| 214 | + [(-> title (dims {:width width}) (style {:alignment :center}))] |
| 215 | + grid))) |
| 216 | + |
| 217 | + |
| 218 | +(defn transpose |
| 219 | + "Transpose a grid." |
| 220 | + [grid] |
| 221 | + (apply mapv vector grid)) |
| 222 | + |
| 223 | + |
| 224 | +(defn juxtapose |
| 225 | + "Put grids side by side (whereas `concat` works vertically, this works |
| 226 | + horizontally). |
| 227 | +
|
| 228 | + Optionally, supply some number of blank `padding` columns between the two |
| 229 | + grids. |
| 230 | +
|
| 231 | + Finds the maximum row width in the left-most grid and pads all of its rows |
| 232 | + to that length before sticking them together." |
| 233 | + ([left-grid right-grid] |
| 234 | + (juxtapose left-grid right-grid 0)) |
| 235 | + ([left-grid right-grid padding] |
| 236 | + (let [;; First pad the height of both grids |
| 237 | + height (max (count left-grid) (count right-grid)) |
| 238 | + empty-row [] |
| 239 | + pad-height (fn [xs] |
| 240 | + (concat xs (repeat (- height (count xs)) empty-row))) |
| 241 | + |
| 242 | + ;; Then pad the width of the left grid so that it's uniform |
| 243 | + row-width (fn [row] (apply + (map (comp :width dims) row))) |
| 244 | + max-row-width (apply max (map row-width left-grid)) |
| 245 | + pad-to (fn [width row] |
| 246 | + (let [cells-needed (- width (row-width row))] |
| 247 | + (into row (repeat cells-needed "")))) |
| 248 | + padded-left-grid (map |
| 249 | + (partial pad-to (+ max-row-width padding)) |
| 250 | + (pad-height left-grid))] |
| 251 | + (map into padded-left-grid (pad-height right-grid))))) |
| 252 | + |
| 253 | + |
| 254 | +(comment |
| 255 | + "Example: juxtaposing two grids with different widths and heights" |
| 256 | + (let [squares (-> (table (for [i (range 10)] {"X" i "X^2" (* i i)})) |
| 257 | + (vec) |
| 258 | + (update 5 into [(dims "<- This one is 4^2" {:width 2})]) |
| 259 | + (update 6 into ["^ Juxt should make room for that cell"])) |
| 260 | + cubes (table (for [i (range 20)] {"X" i "X^3" (* i i i)}))] |
| 261 | + (file/quick-open! |
| 262 | + {"Juxtapose" (juxtapose squares cubes)})) |
| 263 | + |
| 264 | + "Example: A multiplication table" |
| 265 | + (let [highlight {:fill-pattern :solid-foreground |
| 266 | + :fill-foreground-color :yellow} |
| 267 | + |
| 268 | + grid (for [x (range 1 11)] |
| 269 | + (for [y (range 1 11)] |
| 270 | + (cond-> (* x y) (= x y) (style highlight)))) |
| 271 | + |
| 272 | + cols (map #(style % {:font {:bold true}}) (range 1 11)) |
| 273 | + |
| 274 | + grid (concat [cols] grid) |
| 275 | + grid (juxtapose (transpose [(cons nil cols)]) grid)] |
| 276 | + (file/quick-open! |
| 277 | + {"Transpose & Juxtapose" |
| 278 | + (with-title "Multiplication Table" grid)}))) |
| 279 | + |
211 | 280 |
|
212 | 281 | ;;; File interaction
|
213 | 282 |
|
|
0 commit comments