window.c 9.2 KB

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