#include #include #include #include "../wordwrap.h" #include "slideshow.h" /* We use the font set by initdraw() for most things, but can set our own.. */ Font *titlefont, *smallfont; void content_init(void); /* Initialization, mostly for additional fonts. */ void loadfonts(void) { char *service; service = getenv("service"); if (!service || ((strcmp(service, "unix") == 0) || strcmp(service, "") == 0)) titlefont = openfont(display, "/mnt/font/Cochin/56a/font"); else titlefont = openfont(display, "/lib/font/bit/lucida/unicode.28.font"); if (!service || ((strcmp(service, "unix") == 0) || strcmp(service, "") == 0)) smallfont = openfont(display, "/mnt/font/Cochin/40a/font"); else smallfont = openfont(display, "/lib/font/bit/lucida/unicode.18.font"); if (titlefont == nil) { fprint(2, "%s: openfont failed: %r\n", argv0); exits("openfont"); } } /* Actual content below here. */ void river(void) { int n = 4; int h, w, pn, qn; Point p[4], q[4]; Point **pp; Point **qq; Image* color; w = screen->r.max.x - screen->r.min.x; h = screen->r.max.y - screen->r.min.y; p[0] = Pt(screen->r.min.x, screen->r.min.y + w*0.5); p[1] = Pt(screen->r.min.x + w*0.3, screen->r.min.y + h*0.4); p[2] = Pt(screen->r.min.x + w*0.7, screen->r.min.y + h*0.3); p[3] = Pt(screen->r.max.x, screen->r.min.y + w*0.2); q[3] = Pt(screen->r.min.x, screen->r.min.y + w*0.9); q[2] = Pt(screen->r.min.x + w*0.3, screen->r.min.y + h*0.6); q[1] = Pt(screen->r.min.x + w*0.7, screen->r.min.y + h*0.4); q[0] = Pt(screen->r.max.x, screen->r.min.y + w*0.25); /* Not sure how big to make these until after bezsplinepts. */ pp = malloc(4096); qq = malloc(4096); pn = bezsplinepts(p, n, pp); qn = bezsplinepts(q, n, qq); color = allocimagemix(display, DPalebluegreen, DBluegreen); Point *z = malloc((pn + qn) * sizeof(Point)); memcpy(z, *pp, pn * sizeof(Point)); memcpy(z+pn, *qq, qn * sizeof(Point)); poly(screen, z, pn+qn, Enddisc, Enddisc, 5, color, ZP); fillpoly(screen, z, pn+qn, ~0, allocimagemix(display, DBluegreen, DWhite), ZP); free(pp); free(qq); } void step0_main(void) { Point p; char* t0 = "Nile"; char* t1 = "A particular river."; char* name = "Anthony Sorace"; char* email = "a@9srv.net"; insert = Pt((screen->r.min.x + margin), (screen->r.min.y + margin)); insert = wrline(titlefont, t0); insert = wrline(font, t1); p = stringsize(font, name); insert = Pt(screen->r.max.x - margin*2 - p.x, screen->r.max.y - margin*0.5 - p.y*2); insert = wrline(font, name); p = stringsize(font, email); insert = Pt(screen->r.max.x - margin*2 - p.x, screen->r.max.y - margin*0.5 - p.y); insert = wordwrap(screen, insert, display->black, ZP, font, email, margin); river(); } void toc_1(void) { char* head = "Nile is a new window system for Plan 9 derived from rio."; char* body[] = { // "Window systems shoudl be transparent. -Rob Pike", // "mux, mpx, 8½, rio... all move towards greater transparency.", "Nile makes several changes, mostly aimed at making the system more transparent:", nil, }; head_body_stepwise(font, head, body); // insert = wrline(font, "Nile is a new window system for Plan 9 derived from rio."); // insert = wrline(font, "“Window systems shoudl be transparent.” — Rob Pike"); // char* b = "It makes several changes, mostly aimed at making the system more transparent:"; // insert = newline(font, insert); // insert = wrline(font, b); // insert = newline(font, insert); } void toc_ui(void) { char* head = "User interaction:"; char* body[] = { "→Simplify mouse interaction", "→Eliminate all menus (almost)", "→Import Plan 9 from User Space's scroll behavior", nil, }; head_body(font, head, body); } void toc_lf(void) { char* head = "Look and feel:"; char* body[] = { "→Transparent window creation and resizing", "→Change the colors", "→Thinner borders", nil, }; head_body(font, head, body); } void toc_other(void) { char* head = "Other things:"; char* body[] = { "→Introduce wsys/font file", "→Non–interactive mode", nil, }; head_body(font, head, body); } void eliminate_menus(void) { blankreset(); char* t = "Get rid of the menus."; insert = wrline(font, t); insert = newline(font, insert); } void why_menus(void) { char* head = "Menus are not transparent."; char* body[] = { "→ Getting a function from a menu is at least an extra click-release.", "→ The user needs to divert attention to pick the desired menu item.", "→ It's easy to pick the wrong item.", "→ Rio's windows preselect the most-recently-used item.", "→ This helps with repetative tasks, but inhibits muscle memory.", "→ Sometimes they're needed. But do we here?", nil, }; head_body_stepwise(font, head, body); } void button2_gone(void) { char* head = "Button 2: cut, paste, snarf, plumb, send, scroll"; char* body[] = { "→Cut, paste, and snarf are already provided via mouse chording.", "→Plumb and send are important and frequently used; let's make them easier.", "→Button 2 sends; button 3 plumbs.", "→We'll come back to scroll in a minute, but it's going away.", "→Nothing left on the button 2 menu; remove it.", nil, }; head_body_stepwise(font, head, body); } void button3_gone(void) { char* head = "Button 3: New, Resize, Move, Delete, Hide"; char* body[] = { "→Resize and Move are already available by grabbing a window's border.", "→Make button 3 on the background create a new window.", "→Faster window creation:", " ↳ rio: press, possibly move to select, release, press, drag, release", " ↳ nile: press, drag, release", //x "→Rio's \"adaptive\" menus don't work as well on Button 3 as on Button 2.", "→Delete and Hide get some helper programs.", nil, }; head_body_stepwise(font, head, body); } void hidden_windows(void) { char *head = "What about hidden windows?"; char* body[] = { "→In rio, they're also on button 3.", "→By default, nile moves them to button 1 on the background.", "→Option '-m' disables this, giving nile no interactive way to see them.", "→External programs like 'winwatch' can provide different views of this.", "→This should probably be the default.", nil, }; head_body_stepwise(font, head, body); } void new_ui(void) { char* head = "The new mouse interaction:"; char* body[] = { "→Same mouse chords as rio.", "→Same window border operations as rio.", "→Button 1 on the background to see hidden windows.", "→Button 2 always sends, anywhere.", "→Button 3 in a window plumbs.", "→Button 3 on the background to sweep out a new window.", nil, }; head_body(font, head, body); } void what_about_scroll(void) { char* head = "So... what about scroll mode?"; char* body[] = { "Let's talk about Larry Tesler.", "Created cut, copy, and paste as user interface elements.", "Part of a quest to 'eliminate all modes'.", "Found entering command in the wrong modes the largest source of user error.", "Found confusion about how to switch modes a common source of user frustration.", nil, }; head_body_stepwise(font, head, body); } void rio_modes_1(void) { Image *red; reset(); char* t1 = "Not all modes are"; char* t2 = " equal, though."; char* t3 = "equally bad."; insert = wordwrap(screen, insert, display->black, ZP, font, t1, margin); string(screen, insert, display->black, ZP, font, t2); flushimage(display, 1); sleep(1000); red = allocimagemix(display, DRed, DRed); Point p = stringsize(font, t2); line(screen, insert, addpt(insert, p), Endsquare, Endsquare, 2, red, ZP); line(screen, Pt(insert.x, insert.y+p.y), Pt(insert.x+p.x, insert.y), Endsquare, Endsquare, 2, red, ZP); insert.y = insert.y + p.y; insert = wrline(font, t3); } void rio_modes_2(void) { char* t = "If you're going to have modes, there are ways to make them less (or more) confusing."; insert = wrline(font, t); } void rio_modes_3(void) { char* t = "Rio has two notable modes; one does this well, one poorly."; insert = wrline(font, t); } void rio_holdmode(void) { Image *holdimg; int holdfd; char* t = "Rio: hold mode"; char* holdfile = "nile.img/holdmode.img"; Point p; Rectangle holdrect; holdfd = open(holdfile, OREAD); holdimg = readimage(display, holdfd, 0); /* Don't set insert here, so we can use it to blank just the screenshots. */ p = wrline(font, t); holdrect = Rect(screen->r.min.x + margin, p.y, screen->r.min.x + margin + (Dx(screen->r) * 0.5), screen->r.max.y); draw(screen, holdrect, holdimg, nil, ZP); close(holdfd); } void rio_scrollmode(void) { Image *scrollimg; int scrollfd; char* t = "Rio: scroll mode"; char* scrollfile = "nile.img/scrollmode.img"; Rectangle scrollrect; scrollfd = open(scrollfile, OREAD); scrollimg = readimage(display, scrollfd, 0); print("%d %d\n", scrollimg->r.max.x, scrollimg->r.max.y); draw(screen, Rect(screen->r.min.x, insert.y, screen->r.max.x, screen->r.max.y), background, nil, ZP); insert = wordwrap(screen, insert, display->black, ZP, font, t, margin); scrollrect = Rect(screen->r.min.x + margin, insert.y + margin, screen->r.max.x - margin, screen->r.max.y - margin); draw(screen, scrollrect, scrollimg, nil, ZP); close(scrollfd); } void no_scroll_mode(void) { char* head = "So... what about scroll mode?"; char* body[] = { "We get rid of it!", "Plan 9 from User Space did this and it works great.", "If the user's already seeing the bottom of the output, scroll. Otherwise, don't.", "No explicit state for the user to manage.", "Behavior is predictable based on what's visible on screen.", "Single keystroke to stop scrolling (up arrow) or start (end).", nil, }; head_body_stepwise(font, head, body); } void perq_lineage(void) { char* head = "One more thing on Larry Tesler..."; char* body[] = { "Worked at Xerox PARC on their Alto workstation.", "The Alto inspired... seemingly everyone in the industry?", "Apple saw it in '79 and went of to create the Macintosh.", "Niklaus Wirth took a sabatical there, saw the Alto, made Lilith.", "Took another sabatical there, went home and made Oberon.", "The Alto inspired the PERQ, which inspired the jerq...", nil, }; head_body_stepwise(font, head, body); insert = newline(font, insert); wrline(font, "Alto→PERQ→jerq/blit→mpx→mux→sam, 8½, &c"); } void transparent(void) { char* head = "Transparent window creation and resizing"; char* body[] = { "→When creating a new window, only draw the border as the user is selecting the size.", "→Rio fills the rectangle when creating, and *sometimes* when resizing.", "→This can make a noticeable difference with large screens and slow systems.", "→It makes an even bigger difference over bad networks.", nil, }; char* credit[] = { "See also: https://9fans.topicbox.com/groups/9fans/Te5bccc2756ef6b37-M6c7739d800aabc2a27997800/", nil }; head_body(font, head, body); footer(smallfont, credit); } void darker(void) { char* head = "Make things darker"; char* body[] = { "→Mostly because I work in a dimly lit space.", "→Use a darker grey for the background, (roughly) invert text windows.", "→Lower contrast with surrounding space is more comfortable.", "→Less easy to read in brighter environments.", "→Results: one size fits few.", nil, }; head_body(font, head, body); } void thin_borders(void) { char* head = "Make the borders thinner"; char* body[] = { "→Rio's borders can feel chunky on smaller screens; what if we shrank them?", "→This experiment mostly didn't work out.", "→Maybe a mild improvement on small screens, but not as much as hoped.", "→Just as comfortable on the system I initially wrote it on.", "→Much more irritating to use on much higher-resolution displays.", nil, }; head_body(font, head, body); } void wsys_font(void) { char* head = "Add $wsys/font"; char* body[] = { "→Holds the current font for each window.", "→Tools have to be updated to use it (although not many care).", "→An updated 'mc' avoids issues with 'lc' looking junky under 'cpu'.", nil, }; head_body(font, head, body); } void ls_screenshots(void) { } void non_interactive(void) { char* head = "Non–interactive mode"; char* body[] = { "→No menus, even the menu of hidden windows.", "→No borders; no interactive way to resize windows.", "→All windows start with a set size.", "→Use with 'winwatch' as a workspace switcher.", nil, }; head_body(font, head, body); } void ni_depricated(void) { insert = newline(font, insert); char* s[] = { "I was using this on a specific small device; I don't any more.", "It really should be its own thing.", nil, }; char* credit[] = { "See also: /n/sources/contrib/yiyus/cmd/rio", nil }; insert = wrlines(font, s); footer(smallfont, credit); } void future_work(void) { char* future = "“We are all interested in the future, for that is where you and I are going to spend the rest of our lives.”"; char* criswell = "—Criswell"; insert = wrline(font, future); insert.x = screen->r.max.x - margin*2 - stringwidth(font, criswell); string(screen, insert, display->black, ZP, font, criswell); insert = newline(font, insert); } void future_todo(void) { char* head = "So... what next?"; char* body[] = { "→Make $wsys/font writeable.", "→Remove non–interactive mode (into its own thing).", "→Import one of the theming patches.", "→Look? (Leap?)", "→Make the file system a library?", nil, }; head_body_stepwise(font, head, body); } void ack(void) { char* head = "With thanks to:"; char* body[] = { "Rob Pike (for rio, 8½, mux, jerq...)", "Russ Cox (the menuless inspiration, p9p's scrolling)", "Andrey Mirtchovski (transparent resize)", "Jesús Galán López (non–interactive mode)", nil, }; head_body(font, head, body); } void thanks(void) { Point center, w; char* thanks = "Thank you! ☺"; char* f[] = { "Nile: http://a.9srv.net/src/nile", "Presentation: http://a.9srv.net/src/slideshow", nil, }; center = addpt(screen->r.min, Pt((screen->r.max.x - screen->r.min.x)/2, (screen->r.max.y - screen->r.min.y)/2)); w = stringsize(font, thanks); insert = subpt(center, Pt(w.x/2, w.y/2)); string(screen, insert, display->black, ZP, font, thanks); footer(smallfont, f); } Step steptab[] = { {content_init, step0_main, reset, nil}, {blankreset, toc_1, nil, nil}, {nil, toc_ui, nil, toc_1}, {nil, toc_lf, nil, toc_1}, {nil, toc_other, page_end, toc_1}, {eliminate_menus, why_menus, nil, nil}, {eliminate_menus, button2_gone, page_end, eliminate_menus}, {eliminate_menus, button3_gone, page_end, eliminate_menus}, {eliminate_menus, hidden_windows, page_end, eliminate_menus}, {blankreset, new_ui, page_end, nil}, {blankreset, what_about_scroll, reset, nil}, {blank, rio_modes_1, nil, nil}, {nil, rio_modes_2, nil, rio_modes_1}, {nil, rio_modes_3, nil, rio_modes_1}, {nil, rio_holdmode, nil, rio_modes_1}, {nil, rio_scrollmode, page_end, rio_modes_1}, {blankreset, no_scroll_mode, nil, nil}, {blankreset, perq_lineage, page_end, nil}, {blankreset, transparent, page_end, nil}, {blankreset, darker, page_end, nil}, {blankreset, thin_borders, page_end, nil}, {blankreset, wsys_font, page_end, nil}, // {nil, ls_screenshot, nil, wsys_font}, {blankreset, non_interactive, page_end, nil}, {nil, ni_depricated, page_end, non_interactive}, {blankreset, future_work, nil, nil}, {nil, future_todo, page_end, future_work}, {blankreset, ack, reset, nil}, {blankreset, thanks, reset, nil}, }; /* Last becuase we need steptab already initialized. */ void content_init(void) { margin = 100; blank(); nsteps = sizeof(steptab)/sizeof(Step); loadfonts(); }