twn | Simple terminal multiplexer |
| download: https://git.y1.nz/archives/twn.tar.gz | |
| README | Files | Log | Refs |
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
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.