sss.c (10108B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <mouse.h> 6 #include <cursor.h> 7 #include <keyboard.h> 8 9 #include "stack.h" 10 #include "cells.h" 11 12 /* cell drawing flags */ 13 enum { 14 CENTER = 1, 15 HIGHLIGHT = 2, 16 SELECTED = 4, 17 CURSOR = 8, 18 }; 19 20 Stack *hp, *hr; 21 Stack *T; 22 23 struct Selection { 24 Stack rows; 25 Stack cols; 26 Stack cells; 27 Point cursor; 28 } selection; 29 30 int defcwidth, defcheight; 31 int mstate; 32 33 enum { BG, HG, FG, BR }; 34 Image *Inorm[4], *Isel[4]; 35 36 Point view; 37 38 Rectangle rcells, rrows, rcols, rlbar, rbbar, rtext, rnope; 39 40 void (*mousefunc)(Mouse); 41 42 Mousectl *mc; 43 Keyboardctl *kc; 44 45 void usage(void); 46 void calc_rects(void); 47 void cell_primitive(Image *dst, Rectangle r, char *s, int flag); 48 void clear(void); 49 void draw_columns(void); 50 void draw_cells(void); 51 void draw_cell(Point); 52 void draw_rows(void); 53 void colors(void); 54 void mousecells(Mouse); 55 void mousecols(Mouse); 56 void mouserows(Mouse); 57 void run_cmd(Mousectl *mc, Keyboardctl *kc); 58 void edit_cell(Point addr); 59 Value* hist_get_value(Stack*, Point); 60 Point mouse2addr(Point); 61 int is_selected(Point); 62 void unselect(void); 63 64 void 65 threadmain(int argc, char **argv) 66 { 67 Mouse mv; 68 Rune kv; 69 int rv[2]; 70 Mouse mv_old; 71 ARGBEGIN{ 72 default: 73 usage(); 74 break; 75 } 76 ARGEND; 77 78 if(initdraw(0, 0, "Super Spreadsheet 64!") < 0) 79 sysfatal("inidraw failed: %r"); 80 if((mc = initmouse(0, screen)) == nil) 81 sysfatal("initmouse failed: %r"); 82 if((kc = initkeyboard(0)) == nil) 83 sysfatal("initkeyboard failed: %r"); 84 85 colors(); 86 mousefunc = nil; 87 mstate = 0; 88 view = ZP; 89 90 defcheight = font->height + 4; 91 defcwidth = stringwidth(font, "0") * 8 + 4; 92 if (argc == 1) T = table_read(argv[0]); 93 else T = newstack(); 94 hp = newstack(); 95 selection.cursor = Pt(0, 0); 96 push(hp, T); 97 98 calc_rects(); 99 clear(); 100 draw_cells(); 101 draw_columns(); 102 draw_rows(); 103 cell_primitive(screen, rnope, "", 0); 104 flushimage(display, 1); 105 106 enum { KBD, MOUSE, RESIZE, CHEND }; 107 Alt alts[4] = { 108 [KBD] {kc->c, &kv, CHANRCV}, 109 [MOUSE] {mc->c, &mv, CHANRCV}, 110 [RESIZE] {mc->resizec, rv, CHANRCV}, 111 [CHEND] {0, 0, CHANEND}, 112 }; 113 114 for (;;) { 115 switch (alt(alts)) { 116 case KBD: 117 if (kv == 0x7f) threadexitsall(nil); 118 run_cmd(mc, kc); 119 break; 120 case MOUSE: 121 if (mv.buttons == 0){ 122 mstate = 0; 123 mousefunc = nil; 124 if (ptinrect(mv.xy, rrows)) mousefunc = mouserows; 125 if (ptinrect(mv.xy, rcols)) mousefunc = mousecols; 126 if (ptinrect(mv.xy, rcells)) mousefunc = mousecells; 127 } 128 else { 129 if (mousefunc != nil) mousefunc(mv); 130 } 131 if (mv.buttons == 2) mstate = 1; 132 if (mstate == 1) { 133 view = addpt(view, subpt(mv.xy, mv_old.xy)); 134 if (view.x > 0) view.x = 0; 135 if (view.y > 0) view.y = 0; 136 draw_cells(); 137 draw_columns(); 138 draw_rows(); 139 cell_primitive(screen, rnope, "", 0); 140 flushimage(display, 1); 141 } 142 mv_old = mv; 143 break; 144 case RESIZE: 145 if(getwindow(display, Refnone) < 0) 146 sysfatal("resize failed: %r"); 147 calc_rects(); 148 clear(); 149 draw_cells(); 150 draw_columns(); 151 draw_rows(); 152 cell_primitive(screen, rnope, "", 0); 153 flushimage(display, 1); 154 break; 155 } 156 } 157 } 158 159 void 160 cell_primitive(Image *dst, Rectangle r, char *s, int flag) 161 { 162 Rectangle rr; 163 Image **Ipal, *Ibg, *Ibr; 164 int selected, center, cursor, high; 165 int dx; 166 selected = flag & SELECTED; 167 center = flag & CENTER; 168 high = flag & HIGHLIGHT; 169 cursor = flag & CURSOR; 170 Ipal = selected ? Isel : Inorm; 171 Ibg = high ? Ipal[HG] : Ipal[BG]; 172 Ibr = Ipal[BR]; 173 rr = insetrect(r, 1); 174 if (cursor != 0) { 175 Ibr = Ipal[FG]; 176 rr = insetrect(r, 2); 177 } 178 dx = 0; 179 if (center != 0) dx = (rr.max.x - rr.min.x - stringwidth(font, s)) / 2; 180 draw(dst, r, Ibr, 0, ZP); 181 draw(dst, rr, Ibg, 0, ZP); 182 string(dst, addpt(Pt(2 + dx, 2), r.min), Ipal[FG], ZP, font, s); 183 } 184 185 void 186 colors(void) 187 { 188 Inorm[BG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0xFFFFFFFF); 189 Inorm[HG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0xBBBBBBFF); 190 Inorm[FG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x000000FF); 191 Inorm[BR] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x000000FF); 192 Isel[BG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x000000FF); 193 Isel[HG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x444444FF); 194 Isel[FG] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0xFFFFFFFF); 195 Isel[BR] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x888888FF); 196 } 197 198 void 199 usage(void) 200 { 201 fprint(2, "usage: %s", argv0); 202 threadexitsall("usage"); 203 } 204 205 void 206 calc_rects(void) 207 { 208 Rectangle r; 209 r = screen->r; 210 rtext = Rect( 211 r.min.x, r.min.y, 212 r.max.x, r.min.y + font->height + 4); 213 214 rnope = Rect( 215 r.min.x, rtext.max.y, 216 r.min.x + defcwidth, rtext.max.y + defcheight); 217 218 rrows = Rect( 219 r.min.x, rtext.max.y + defcheight, 220 r.min.x + defcwidth, r.max.y); 221 222 rcols = Rect( 223 r.min.x + defcwidth, rtext.max.y, 224 r.max.x, rtext.max.y + defcheight); 225 226 rcells = Rect( 227 rrows.max.x, rcols.max.y, 228 r.max.x, r.max.y); 229 } 230 231 void 232 clear(void) 233 { 234 draw(screen, screen->r, display->white, 0, ZP); 235 } 236 237 void 238 draw_columns(void) 239 { 240 Point pt; 241 Rectangle r; 242 long col, *scol, i; 243 int flag; 244 char *colnum; 245 col = 0; 246 pt = addpt(Pt(view.x, 0), rcols.min); 247 while (pt.x < rcols.max.x) { 248 if (pt.x + defcwidth >= rcols.min.x) { 249 flag = CENTER|HIGHLIGHT; 250 for (i = 0; i < selection.cols.size; i++) { 251 scol = selection.cols.data[i]; 252 if (col == *scol) { 253 flag |= SELECTED; 254 break; 255 } 256 } 257 r = rectaddpt(Rect(0, 0, defcwidth, defcheight), pt); 258 colnum = smprint("%ld", col); 259 cell_primitive(screen, r, colnum, flag); 260 free(colnum); 261 } 262 pt.x += defcwidth; 263 col++; 264 } 265 } 266 267 void 268 draw_rows(void) 269 { 270 Point pt; 271 Rectangle r; 272 long row, *srow, i; 273 int flag; 274 char *rownum; 275 row = 0; 276 pt = addpt(Pt(0, view.y), rrows.min); 277 while (pt.y < rrows.max.y) { 278 if (pt.y + defcheight >= rrows.min.y) { 279 flag = CENTER|HIGHLIGHT; 280 for (i = 0; i < selection.rows.size; i++) { 281 srow = selection.rows.data[i]; 282 if (row == *srow) { 283 flag |= SELECTED; 284 break; 285 } 286 } 287 r = rectaddpt(Rect(0, 0, defcwidth, defcheight), pt); 288 rownum = smprint("%ld", row); 289 cell_primitive(screen, r, rownum, flag); 290 free(rownum); 291 } 292 pt.y += defcheight; 293 row++; 294 } 295 } 296 297 void 298 draw_cell(Point addr) 299 { 300 Rectangle r; 301 Point p; 302 Value *v; 303 char *text; 304 int flag; 305 p = addpt(Pt(addr.x * defcwidth, addr.y * defcheight), view); 306 r.min = addpt(rcells.min, p); 307 r.max = addpt(r.min, Pt(defcwidth, defcheight)); 308 v = hist_get_value(hp, addr); 309 text = (v == nil) ? "" : v->data; 310 flag = is_selected(addr); 311 if (eqpt(addr, selection.cursor) != 0) flag |= CURSOR; 312 cell_primitive(screen, r, text, flag); 313 } 314 315 316 void 317 draw_cells(void) 318 { 319 Rectangle r; 320 long x, y; 321 r = rectsubpt(rcells, addpt(view, rcells.min)); 322 r.min.x = r.min.x / defcwidth; 323 r.max.x = r.max.x / defcwidth; 324 r.min.y = r.min.y / defcheight; 325 r.max.y = r.max.y / defcheight; 326 for (x = r.min.x; x <= r.max.x; x++) 327 for (y = r.min.y; y <= r.max.y; y++) 328 draw_cell(Pt(x, y)); 329 } 330 331 332 void 333 run_cmd(Mousectl *mc, Keyboardctl *kc) 334 { 335 char buf[1024]; 336 *buf = 0; 337 enter("cmd:", buf, 1024, mc, kc, 0); 338 339 } 340 341 void 342 edit_cell(Point addr) 343 { 344 Value *v; 345 Stack *N; 346 N = newstack(); 347 char prompt[256], buf[1024]; 348 snprint(prompt, 256, "%d,%d:", addr.x, addr.y); 349 v = hist_get_value(hp, addr); 350 *buf = 0; 351 if ((v != nil)&&(v->data != nil)) strncat(buf, v->data, 1024); 352 if (enter(prompt, buf, 1024, mc, kc, 0) < 0) return; 353 v = malloc(sizeof(Value)); 354 v->addr = addr; 355 v->data = strdup(buf); 356 push(N, v); 357 push(hp, N); 358 T = N; 359 } 360 361 Value* 362 hist_get_value(Stack *H, Point addr) 363 { 364 Stack *T; 365 Value *v; 366 long x, y; 367 for (x = H->size - 1; x >= 0; x--) { 368 T = H->data[x]; 369 for (y = 0; y < T->size; y++) { 370 v = T->data[y]; 371 if (eqpt(addr, v->addr) != 0) return v; 372 } 373 } 374 return nil; 375 } 376 377 Point 378 mouse2addr(Point xy) 379 { 380 Point addr; 381 addr.x = (xy.x - view.x - rcells.min.x)/defcwidth; 382 addr.y = (xy.y - view.y - rcells.min.y)/defcheight; 383 return addr; 384 } 385 386 387 int 388 is_selected(Point addr) 389 { 390 long i; 391 Point *a; 392 long *n; 393 for (i = 0; i < selection.cells.size; i++) { 394 a = selection.cells.data[i]; 395 if (eqpt(addr, *a) != 0) return SELECTED; 396 } 397 for (i = 0; i < selection.cols.size; i++) { 398 n = selection.cols.data[i]; 399 if (*n == addr.x) return SELECTED; 400 } 401 for (i = 0; i < selection.rows.size; i++) { 402 n = selection.rows.data[i]; 403 if (*n == addr.y) return SELECTED; 404 } 405 return 0; 406 } 407 408 409 void 410 mousecells(Mouse mv) 411 { 412 Point m, n; 413 static Rectangle s; 414 Rectangle r; 415 m = mouse2addr(mv.xy); 416 if (mv.buttons == 1) { 417 unselect(); 418 if (mstate == 0) { 419 draw_columns(); 420 draw_rows(); 421 s.min = m; 422 mstate = 2; 423 } 424 s.max = m; 425 r = canonrect(s); 426 for (n = r.min;; n.x++) { 427 if (n.x > r.max.x) { 428 n.x = r.min.x; 429 n.y++; 430 } 431 if (n.y > r.max.y) break; 432 Point *a; 433 a = malloc(sizeof(Point)); 434 *a = n; 435 push(&selection.cells, a); 436 } 437 selection.cursor = m; 438 draw_cells(); 439 cell_primitive(screen, rnope, "", 0); 440 flushimage(display, 1); 441 } 442 if (mv.buttons == 4) { 443 edit_cell(m); 444 draw_cell(m); 445 draw_columns(); 446 draw_rows(); 447 cell_primitive(screen, rnope, "", 0); 448 flushimage(display, 1); 449 flushimage(display, 1); 450 } 451 } 452 453 void 454 mousecols(Mouse mv) 455 { 456 Point m; 457 static Rectangle s; 458 Rectangle r; 459 int i; 460 m = mouse2addr(mv.xy); 461 if (mv.buttons == 1) { 462 unselect(); 463 if (mstate == 0) { 464 draw_rows(); 465 s.min = m; 466 mstate = 2; 467 } 468 s.max = m; 469 r = canonrect(s); 470 for (i = r.min.x; i <= r.max.x; i++) { 471 long *col; 472 col = malloc(sizeof(long)); 473 *col = i; 474 push(&selection.cols, col); 475 } 476 draw_columns(); 477 draw_cells(); 478 flushimage(display, 1); 479 } 480 } 481 482 void 483 mouserows(Mouse mv) 484 { 485 Point m; 486 static Rectangle s; 487 Rectangle r; 488 int i; 489 m = mouse2addr(mv.xy); 490 if (mv.buttons == 1) { 491 unselect(); 492 if (mstate == 0) { 493 draw_columns(); 494 s.min = m; 495 mstate = 2; 496 } 497 s.max = m; 498 r = canonrect(s); 499 for (i = r.min.y; i <= r.max.y; i++) { 500 long *row; 501 row = malloc(sizeof(long)); 502 *row = i; 503 push(&selection.rows, row); 504 } 505 draw_rows(); 506 draw_cells(); 507 flushimage(display, 1); 508 } 509 } 510 511 void 512 unselect(void) 513 { 514 while (selection.cells.size > 0) free(pop(&selection.cells)); 515 while (selection.rows.size > 0) free(pop(&selection.rows)); 516 while (selection.cols.size > 0) free(pop(&selection.cols)); 517 }