window.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* window.c, Ait, Kevin Bloom, BSD 3-Clause, 2023-2024 */
  2. #include "header.h"
  3. #include "termbox.h"
  4. int win_cnt = 0;
  5. window_t* new_window()
  6. {
  7. window_t *wp = (window_t *)malloc(sizeof(window_t));
  8. assert(wp != NULL); /* call fatal instead XXX */
  9. wp->w_next = NULL;
  10. wp->w_bufp = NULL;
  11. wp->w_point = 0;
  12. wp->w_mark = NOMARK;
  13. wp->w_top = 0;
  14. wp->w_left = 0;
  15. wp->w_rows = 0;
  16. wp->w_cols = 0;
  17. wp->w_update = FALSE;
  18. wp->w_mcol = 0;
  19. wp->w_mlen = 0;
  20. wp->w_recenter = 0;
  21. sprintf(wp->w_name, "W%d", ++win_cnt);
  22. return wp;
  23. }
  24. void one_window(window_t *wp)
  25. {
  26. window_mode = WINDOW_DEFAULT;
  27. wp->w_top = 0;
  28. wp->w_left = 0;
  29. wp->w_rows = LINES - 2;
  30. wp->w_cols = COLS;
  31. wp->w_next = NULL;
  32. wp->w_update = TRUE;
  33. wp->w_mcol = 0;
  34. }
  35. void delete_other_windows_local(int showmsg)
  36. {
  37. if (wheadp->w_next == NULL) {
  38. if(showmsg)
  39. msg("Only 1 window");
  40. return;
  41. }
  42. free_other_windows(curwp);
  43. }
  44. void split_window_local(int internal)
  45. {
  46. window_t *wp, *wp2;
  47. int ntru, ntrl;
  48. /* if(!internal && window_mode == WINDOW_HORIZ) {
  49. msg("Already in horizontal mode!");
  50. return;
  51. }
  52. */ if(!internal) {
  53. window_mode = WINDOW_HORIZ;
  54. delete_other_windows_local(FALSE);
  55. }
  56. if (curwp->w_rows < 3) {
  57. msg("Cannot split a %d line window", curwp->w_rows);
  58. return;
  59. }
  60. wp = new_window();
  61. if(curwp->w_bufp->b_next != NULL)
  62. associate_b2w(curwp->w_bufp->b_next,wp);
  63. else
  64. associate_b2w(curwp->w_bufp,wp);
  65. b2w(wp); /* inherit buffer settings */
  66. ntru = (curwp->w_rows - 1) / 2; /* Upper size */
  67. ntrl = (curwp->w_rows - 1) - ntru; /* Lower size */
  68. /* Old is upper window */
  69. curwp->w_rows = ntru;
  70. wp->w_top = curwp->w_top + ntru + 1;
  71. wp->w_rows = ntrl;
  72. wp->w_cols = curwp->w_cols;
  73. wp->w_left = curwp->w_left;
  74. /* insert it in the list */
  75. wp2 = curwp->w_next;
  76. curwp->w_next = wp;
  77. wp->w_next = wp2;
  78. curbp->b_reframe = TRUE;
  79. redraw(); /* mark the lot for update */
  80. }
  81. void split_window()
  82. {
  83. split_window_local(FALSE);
  84. }
  85. void tri_split_window()
  86. {
  87. window_t *wp, *wp2, *wp3;
  88. int ntru, leftovers = 0;
  89. window_mode = WINDOW_TRIHORIZ;
  90. delete_other_windows_local(FALSE);
  91. if (curwp->w_rows < 3) {
  92. msg("Cannot split a %d line window", curwp->w_rows);
  93. return;
  94. }
  95. wp = new_window();
  96. if(curwp->w_bufp->b_next != NULL)
  97. associate_b2w(curwp->w_bufp->b_next,wp);
  98. else
  99. associate_b2w(curwp->w_bufp,wp);
  100. b2w(wp); /* inherit buffer settings */
  101. wp2 = new_window();
  102. if(wp->w_bufp->b_next != NULL)
  103. associate_b2w(wp->w_bufp->b_next,wp2);
  104. else
  105. associate_b2w(curwp->w_bufp,wp2);
  106. b2w(wp2); /* inherit buffer settings */
  107. ntru = (LINES - 4) / 3; /* Upper size */
  108. // ntrl = (curwp->w_rows - 3) - ntru; /* Lower size */
  109. /* Old is upper window */
  110. curwp->w_rows = ntru;
  111. leftovers = LINES - (2*ntru) - 4;
  112. wp->w_top = curwp->w_top + ntru + 1;
  113. wp->w_rows = ntru;
  114. wp->w_cols = curwp->w_cols;
  115. wp->w_left = curwp->w_left;
  116. wp2->w_top = wp->w_top + ntru + 1;
  117. wp2->w_rows = leftovers;
  118. wp2->w_cols = curwp->w_cols;
  119. wp2->w_left = curwp->w_left;
  120. curbp->b_reframe = TRUE;
  121. /* If there is more than 1 line left over, distribute the
  122. difference to make it look cleaner
  123. */
  124. if(leftovers - ntru == 2) {
  125. wp->w_rows++;
  126. wp2->w_top++;
  127. wp2->w_rows--;
  128. }
  129. /* insert it in the list */
  130. wp3 = curwp->w_next;
  131. curwp->w_next = wp;
  132. wp->w_next = wp2;
  133. wp2->w_next = wp3;
  134. // curwp->w_next->w_next->w_bufp->b_reframe = TRUE;
  135. redraw(); /* mark the lot for update */
  136. }
  137. void chop_window_local(int internal)
  138. {
  139. window_t *wp, *wp2;
  140. int ntru, ntrl;
  141. /* if(!internal && window_mode == WINDOW_VERT) {
  142. msg("Already in vertical mode!");
  143. return;
  144. }
  145. */ if(!internal) {
  146. window_mode = WINDOW_VERT;
  147. delete_other_windows_local(FALSE);
  148. }
  149. if (curwp->w_cols < 22) {
  150. msg("Cannot split a %d columned window", curwp->w_cols);
  151. return;
  152. }
  153. wp = new_window();
  154. if(curwp->w_bufp->b_next != NULL)
  155. associate_b2w(curwp->w_bufp->b_next,wp);
  156. else
  157. associate_b2w(curwp->w_bufp,wp);
  158. b2w(wp); /* inherit buffer settings */
  159. ntru = (curwp->w_cols - 1) / 2; /* Upper size */
  160. ntrl = (curwp->w_cols - 1) - ntru; /* Lower size */
  161. /* Old is upper window */
  162. curwp->w_cols = ntru;
  163. wp->w_rows = curwp->w_rows;
  164. wp->w_top = curwp->w_top;
  165. wp->w_left = curwp->w_left + ntru + 1;
  166. wp->w_cols = ntrl;
  167. /* insert it in the list */
  168. wp2 = curwp->w_next;
  169. curwp->w_next = wp;
  170. wp->w_next = wp2;
  171. redraw(); /* mark the lot for update */
  172. }
  173. void chop_window()
  174. {
  175. chop_window_local(FALSE);
  176. }
  177. void tri_chop_window()
  178. {
  179. window_t *wp, *wp2, *wp3;
  180. int ntru, leftovers;
  181. window_mode = WINDOW_TRIVERT;
  182. delete_other_windows_local(FALSE);
  183. if (curwp->w_cols < 22) {
  184. msg("Cannot split a %d columned window", curwp->w_cols);
  185. return;
  186. }
  187. wp = new_window();
  188. if(curwp->w_bufp->b_next != NULL)
  189. associate_b2w(curwp->w_bufp->b_next,wp);
  190. else
  191. associate_b2w(curwp->w_bufp,wp);
  192. b2w(wp); /* inherit buffer settings */
  193. wp2 = new_window();
  194. if(wp->w_bufp->b_next != NULL)
  195. associate_b2w(wp->w_bufp->b_next,wp2);
  196. else
  197. associate_b2w(curwp->w_bufp,wp2);
  198. b2w(wp2); /* inherit buffer settings */
  199. ntru = (COLS - 2) / 3; /* Upper size */
  200. /* Old is upper window */
  201. curwp->w_cols = ntru;
  202. leftovers = COLS - (2*ntru) - 2;
  203. wp->w_rows = curwp->w_rows;
  204. wp->w_top = curwp->w_top;
  205. wp->w_left = curwp->w_left + ntru + 1;
  206. wp->w_cols = ntru;
  207. wp2->w_rows = curwp->w_rows;
  208. wp2->w_top = curwp->w_top;
  209. wp2->w_left = curwp->w_left + wp->w_left + ntru + 1;
  210. wp2->w_cols = leftovers;
  211. /* If there is more than 1 column left over, distribute the
  212. difference to make it look cleaner
  213. */
  214. if(leftovers - ntru == 2) {
  215. wp->w_cols++;
  216. wp2->w_left++;
  217. wp2->w_cols--;
  218. }
  219. /* insert it in the list */
  220. wp3 = curwp->w_next;
  221. curwp->w_next = wp;
  222. wp->w_next = wp2;
  223. wp2->w_next = wp3;
  224. redraw(); /* mark the lot for update */
  225. }
  226. void next_window()
  227. {
  228. curwp->w_update = TRUE; /* make sure modeline gets updated */
  229. curwp = (curwp->w_next == NULL ? wheadp : curwp->w_next);
  230. curbp = curwp->w_bufp;
  231. if (curbp->b_cnt > 1)
  232. w2b(curwp); /* push win vars to buffer */
  233. curwp->w_update = TRUE; /* make sure modeline gets updated */
  234. if(curbp->b_point > curbp->b_epage ||
  235. curbp->b_point < curbp->b_page) {
  236. curbp->b_reframe = TRUE;
  237. }
  238. }
  239. void fib_left()
  240. {
  241. window_mode = WINDOW_FIBLEFT;
  242. delete_other_windows_local(FALSE);
  243. chop_window_local(TRUE);
  244. split_window_local(TRUE);
  245. next_window();
  246. next_window();
  247. next_buffer();
  248. next_window();
  249. }
  250. void fib_right()
  251. {
  252. window_mode = WINDOW_FIBRIGHT;
  253. delete_other_windows_local(FALSE);
  254. chop_window_local(TRUE);
  255. next_window();
  256. split_window_local(TRUE);
  257. next_window();
  258. next_window();
  259. }
  260. void quad_window()
  261. {
  262. window_mode = WINDOW_QUAD;
  263. delete_other_windows_local(FALSE);
  264. chop_window_local(TRUE);
  265. split_window_local(TRUE);
  266. next_window();
  267. next_window();
  268. next_buffer();
  269. split_window_local(TRUE);
  270. next_window();
  271. next_window();
  272. }
  273. void delete_other_windows()
  274. {
  275. delete_other_windows_local(TRUE);
  276. }
  277. void free_other_windows(window_t *winp)
  278. {
  279. window_t *wp, *next;
  280. for (wp = next = wheadp; next != NULL; wp = next) {
  281. next = wp->w_next; /* get next before a call to free() makes wp undefined */
  282. if (wp != winp) {
  283. disassociate_b(wp); /* this window no longer references its buffer */
  284. free(wp);
  285. }
  286. }
  287. wheadp = curwp = winp;
  288. one_window(winp);
  289. }
  290. void associate_b2w(buffer_t *bp, window_t *wp) {
  291. assert(bp != NULL);
  292. assert(wp != NULL);
  293. wp->w_bufp = bp;
  294. bp->b_cnt++;
  295. }
  296. void disassociate_b(window_t *wp) {
  297. assert(wp != NULL);
  298. assert(wp->w_bufp != NULL);
  299. wp->w_bufp->b_cnt--;
  300. }
  301. /* Recenters the screen whilst keeping the point.
  302. Will cycled from center, top, bottom.
  303. Because of odd number of rows, "middle" is considered anything that is in
  304. the range of [-1, 1].
  305. */
  306. void recenter()
  307. {
  308. int i = curwp->w_rows / 2;
  309. point_t new_page = curbp->b_page;
  310. int row = curwp->w_row - curwp->w_top;
  311. int shift = row - i;
  312. int current, lastln;
  313. assert(curwp != NULL);
  314. assert(curbp != NULL);
  315. get_line_stats(&current, &lastln, curbp);
  316. if(current == 0) {
  317. msg("Beginning of buffer, can't recenter");
  318. return;
  319. }
  320. if(shift == 0 || shift == 1 || shift == -1) // middle of screen
  321. {
  322. shift = curwp->w_rows / 2;
  323. } else if(row == curwp->w_rows - 1) // end of screen
  324. {
  325. shift = curwp->w_rows / 2;
  326. } else if(row == 0) // start of screen
  327. {
  328. shift = -1 * (curwp->w_rows - 1);
  329. }
  330. if(shift < 0) {
  331. for(int k = shift ; k < 0; k++) {
  332. new_page = upup(curbp, curwp, new_page);
  333. }
  334. if(*ptr(curbp, new_page) == '\n')
  335. new_page++;
  336. } else {
  337. for(int k = shift; k > 0; k--) {
  338. new_page = dndn(curbp, curwp, new_page);
  339. }
  340. }
  341. curbp->b_page = new_page;
  342. }
  343. void resize()
  344. {
  345. switch(window_mode) {
  346. case WINDOW_HORIZ:
  347. split_window();
  348. break;
  349. case WINDOW_VERT:
  350. chop_window();
  351. break;
  352. case WINDOW_TRIHORIZ:
  353. tri_split_window();
  354. break;
  355. case WINDOW_TRIVERT:
  356. tri_chop_window();
  357. break;
  358. case WINDOW_FIBLEFT:
  359. fib_left();
  360. break;
  361. case WINDOW_FIBRIGHT:
  362. fib_right();
  363. break;
  364. case WINDOW_QUAD:
  365. quad_window();
  366. break;
  367. default:
  368. one_window(curwp);
  369. break;
  370. }
  371. return;
  372. }