window.c 9.2 KB

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