window.c
1 #include <stdio.h> /* for stdin/out, fprintf, etc */ 2 #include <stdlib.h> /* for malloc, free */ 3 4 #include "config.h" 5 #include "window.h" 6 #include "direction.h" 7 8 /* interior bounds, inclusive. */ 9 /* min and max cursor positions in the text area of the given subterm */ 10 #define IN_L(win_ptr) ((win_ptr)->l + (win_ptr)->pl) 11 #define IN_U(win_ptr) ((win_ptr)->u + (win_ptr)->pu) 12 #define IN_R(win_ptr) ((win_ptr)->r - (win_ptr)->pr) 13 #define IN_D(win_ptr) ((win_ptr)->d - (win_ptr)->pd) 14 15 /* collision check */ 16 #define IN_WINDOW(w, x, y) (w->l <= x && x <= w->r && w->u <= y && y <= w->d) 17 18 /* get cursor position within window, in base-terminal coordinates */ 19 // TODO use actual cursor instead of top-left corner 20 #define ABS_CURS_X(w) (w)->l 21 #define ABS_CURS_Y(w) (w)->u 22 23 24 /* recursive helper for close_window */ 25 void 26 resize_others(Window *w, Window *other) 27 { 28 if (other->l == w->r+1) other->l = w->l; 29 if (other->r == w->l-1) other->r = w->r; 30 if (other->u == w->d+1) other->u = w->u; 31 if (other->d == w->u-1) other->d = w->d; 32 if (other->child1 != NULL) { 33 resize_others(w, other->child1); 34 resize_others(w, other->child2); 35 } 36 } 37 38 /* FOCUS MUST BE A LEAF */ 39 /* returns the new focus */ 40 Window * 41 close_window(Window *root, Window *focus) { 42 Window *parent = focus->parent; 43 Window *sibling; 44 Window *new_focus; 45 46 if (parent == NULL) return NULL; 47 48 sibling = focus == parent->child1 ? 49 parent->child2 : parent->child1; 50 51 /* merge sibling and parent */ 52 parent->child1 = sibling->child1; 53 parent->child2 = sibling->child2; 54 if (parent->child1 != NULL) { 55 parent->child1->parent = parent; 56 parent->child2->parent = parent; 57 } 58 // TODO set parent's subterm, cursor, etc to sibling's 59 resize_others(focus, parent); 60 new_focus = find_window(root, ABS_CURS_X(focus), ABS_CURS_Y(focus)); 61 free(focus); 62 free(sibling); 63 64 return new_focus; 65 } 66 67 Window * 68 clone_window(Window *a) 69 { 70 Window *b = (Window *) malloc(sizeof(Window)); 71 b->l = a->l; b->u = a->u; 72 b->r = a->r; b->d = a->d; 73 b->pl = a->pl; b->pu = a->pu; 74 b->pr = a->pr; b->pd = a->pd; 75 b->parent = NULL; 76 b->child1 = NULL; 77 b->child2 = NULL; 78 b->t = NULL; 79 return b; 80 } 81 82 /* Shrink the given window and create a new one. */ 83 /* Returns the pointer to the new focused window. */ 84 Window * 85 split_window(Window *parent, int direction) 86 { 87 Window *c1 = clone_window(parent), *c2 = clone_window(parent); 88 89 /* calculate the new windows' geometries */ 90 int xmid = (parent->l + parent->r) / 2; 91 int ymid = (parent->u + parent->d) / 2; 92 switch (direction) { 93 case down: 94 c1->d = ymid; c1->pd = SPLIT_DOWN_PAD; 95 c2->u = ymid+1; c2->pu = SPLIT_UP_PAD; 96 break; 97 case up: 98 c1->u = ymid; c1->pu = SPLIT_UP_PAD; 99 c2->d = ymid-1; c2->pd = SPLIT_DOWN_PAD; 100 break; 101 case right: 102 c1->r = xmid; c1->pr = SPLIT_RIGHT_PAD; 103 c2->l = xmid+1; c2->pl = SPLIT_LEFT_PAD; 104 break; 105 case left: 106 c1->l = xmid; c1->pl = SPLIT_LEFT_PAD; 107 c2->r = xmid-1; c2->pr = SPLIT_RIGHT_PAD; 108 break; 109 } 110 111 /* update the window tree */ 112 parent->t = NULL; 113 c1->parent = parent; c2->parent = parent; 114 parent->child1 = c1; parent->child2 = c2; 115 116 // TODO open a new subterm for c2 117 // c2->t = ... 118 119 return c2; 120 } 121 122 /* Find the leaf window containing the given point, or else NULL */ 123 /* Recursing helper method for find_window_in_direction */ 124 Window * 125 find_window(Window *w, int x, int y) 126 { 127 // TODO may be unnecessary: only check root window? 128 if (!IN_WINDOW(w, x, y)) return NULL; 129 130 /* no children */ 131 if (w->child1 == NULL) return w; 132 133 return find_window(IN_WINDOW(w->child1, x, y) ? w->child1 : w->child2, x, y); 134 } 135 136 /* Find the next window in a given direction */ 137 Window * 138 find_next_window(Window *root, Window *focus, int direction) 139 { 140 int x, y; /* target position */ 141 switch(direction) { 142 case left: x = focus->l - 1; y = ABS_CURS_Y(focus); break; 143 case up: y = focus->u - 1; x = ABS_CURS_X(focus); break; 144 case right: x = focus->r + 1; y = ABS_CURS_Y(focus); break; 145 case down: y = focus->d + 1; x = ABS_CURS_X(focus); break; 146 } 147 return find_window(root, x, y); 148 } 149 150 void 151 fill_rect(int l, int u, int r, int d, char c) 152 { 153 int x = l, y = u; 154 for (;;) { 155 /* CSI sequence HVP: move cursor to row,col */ 156 printf("\033[%d;%df", y, x); 157 158 putchar(c); 159 160 x++; 161 if (x > r) { 162 x = l; 163 y++; 164 } 165 if (y > d) break; 166 } 167 } 168 169 void 170 fill_window_pad(Window *w) 171 { 172 if (w->pu > 0) fill_rect(IN_L(w), w->u, IN_R(w), IN_U(w) - 1, V_PAD_CHAR); 173 if (w->pd > 0) fill_rect(IN_L(w), IN_D(w) + 1, IN_R(w), w->d, V_PAD_CHAR); 174 175 if (w->pl > 0) fill_rect(w->l, IN_U(w), IN_L(w) - 1, IN_D(w), H_PAD_CHAR); 176 if (w->pr > 0) fill_rect(IN_R(w) + 1, IN_U(w), w->r, IN_D(w), H_PAD_CHAR); 177 178 if (w->pl > 0 && w->pu > 0) fill_rect(w->l, w->u, IN_L(w) - 1, IN_U(w) - 1, CORNER_PAD_CHAR); 179 if (w->pl > 0 && w->pd > 0) fill_rect(w->l, IN_D(w)+1, IN_L(w) - 1, w->d, CORNER_PAD_CHAR); 180 if (w->pr > 0 && w->pu > 0) fill_rect(IN_R(w) + 1, w->u, w->r, IN_U(w) - 1, CORNER_PAD_CHAR); 181 if (w->pr > 0 && w->pd > 0) fill_rect(IN_R(w) + 1, IN_D(w)+1, w->r, w->d, CORNER_PAD_CHAR); 182 // TODO draw corners... 183 } 184 185 void 186 fill_window(Window *w, char c) 187 { 188 fill_rect(IN_L(w), IN_U(w), IN_R(w), IN_D(w), c); 189 } 190 191 void 192 render(Window *w, Window *focus) 193 { 194 int r; 195 if (w == NULL) return; 196 197 if (w->child1 != NULL) { 198 render(w->child1, focus); 199 render(w->child2, focus); 200 return; 201 } 202 203 /* reset bg */ 204 fprintf(stdout, "\033[49m"); 205 206 fill_window(w, ' '); 207 208 /* show border in a color... */ 209 if (w == focus) fprintf(stdout, "\033[41m"); 210 211 fill_window_pad(w); 212 fflush(stdout); 213 } 214