Temporary prototypes of a document management program and gui toolkit I'm working on.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1394 lines
36KB

  1. #define _DEFAULT_SOURCE
  2. #include <dirent.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8. #include "btk/btk.h"
  9. /* for filesystem navigation */
  10. /* change depending on your system */
  11. #define NAME_SIZE 255
  12. #define PATH_SIZE 4096
  13. /* buffer increments */
  14. #define DIR_BUFFER_INC 100
  15. #define DATA_BUFFER_INC 2
  16. #define READ_SIZE 2048
  17. #define TEXT_SIZE 4096
  18. #define ITEM_SIZE 256
  19. #define TAG_COL 0
  20. #define UID_COL 1
  21. #define NAME_COL 2
  22. #define DATA_COLS_N 9 /* excludes id, filename and tag */
  23. enum tag_type {
  24. TAG_NONE = 0,
  25. TAG_STRAY = 1U << 0,
  26. TAG_NEW = 1U << 1,
  27. TAG_DEL = 1U << 2,
  28. TAG_EDITED = 1U << 3,
  29. TAG_VISIBILITY = 1U << 4
  30. };
  31. enum status {
  32. STATUS_NONE,
  33. STATUS_ERROR,
  34. STATUS_LATEST,
  35. STATUS_EDITED,
  36. STATUS_BUSY
  37. };
  38. enum dir_mode {
  39. DIR_FILES = 1U << 0,
  40. DIR_HIDDEN = 1U << 1
  41. };
  42. typedef struct {
  43. char uid[ITEM_SIZE];
  44. char filename[ITEM_SIZE];
  45. char misc[DATA_COLS_N][ITEM_SIZE];
  46. char notes[TEXT_SIZE];
  47. unsigned int notes_w;
  48. } data_entry_t;
  49. /* window creation functions */
  50. void build_entry_form ();
  51. void build_file_picker ();
  52. void build_main_window ();
  53. void build_settings ();
  54. /* functions */
  55. void clean_string_copy (char *, char *, unsigned int, int);
  56. int cmp_str_for_qsort (const void *, const void*);
  57. void entry_form_apply ();
  58. void entry_form_close ();
  59. void entry_form_open ();
  60. int file_exists ();
  61. void file_picker_close ();
  62. void file_picker_open (int);
  63. void file_picker_open_entry ();
  64. void file_picker_open_open ();
  65. void file_picker_open_new ();
  66. void file_picker_select ();
  67. int find_dir_spot (char *, char *);
  68. char* get_data_item (unsigned int, unsigned int);
  69. void hotpot_close ();
  70. void hotpot_load ();
  71. void hotpot_reload ();
  72. void hotpot_sync ();
  73. void hotpot_unload ();
  74. void move_dir (int);
  75. void open_ext_dir ();
  76. void open_ext_entry (int);
  77. void quit ();
  78. int parse_dir (char *, int);
  79. void push_entry (int, data_entry_t);
  80. void settings_close ();
  81. void settings_open ();
  82. void set_activity_status (int, int);
  83. void set_entry_tag_col (unsigned int, int);
  84. void set_main_win_states (int);
  85. void set_file_picker_states (int);
  86. void str_to_lower_case (char *);
  87. void toggle_del_tag ();
  88. void toggle_col (int, btk_arg_t);
  89. void toggle_hidden (int, btk_arg_t);
  90. void toggle_notes (int, btk_arg_t);
  91. void toggle_visibility_tag ();
  92. void update_select_data (int);
  93. /* btk windows */
  94. btk_session_t *session;
  95. btk_window_t *entry_form;
  96. btk_window_t *file_picker;
  97. btk_window_t *main_win;
  98. btk_window_t *settings;
  99. btk_window_t *windows[4];
  100. /* btk important cells */
  101. btk_cell_t *table_cell;
  102. btk_cell_t *dir_list_cell;
  103. btk_cell_t *notes_view_cell;
  104. btk_cell_t *file_select_cell;
  105. btk_cell_t *activity_cell;
  106. btk_cell_t *edited_note_cell;
  107. unsigned int table_cell_id;
  108. unsigned int dir_list_cell_id;
  109. unsigned int notes_view_cell_id;
  110. unsigned int file_select_cell_id;
  111. unsigned int activity_cell_id;
  112. unsigned int edited_note_cell_id;
  113. /* file navigation */
  114. char dir_current[PATH_SIZE];
  115. char *dir_list = NULL;
  116. int *dir_spot = NULL;
  117. unsigned int dir_list_n = 0;
  118. int nav_select = -1;
  119. int nav_mode;
  120. /* hotpot data */
  121. int file_picker_mode;
  122. char open_dir[PATH_SIZE] = "";
  123. int hotpot_open = 0;
  124. char *data = NULL;
  125. char *data_notes = NULL;
  126. int *data_tags = NULL;
  127. int *data_spot = NULL;
  128. char *data_rename = NULL;
  129. unsigned int data_n = 0;
  130. unsigned int data_buffer_n = 0;
  131. unsigned int last_uid = 0;
  132. /* selected data */
  133. int select_data = -1;
  134. char select_note[TEXT_SIZE];
  135. /* edited data */
  136. char edited_uid[ITEM_SIZE];
  137. char edited_filename[ITEM_SIZE];
  138. char edited_misc[DATA_COLS_N][ITEM_SIZE];
  139. char edited_note[TEXT_SIZE];
  140. /* misc gui stuff */
  141. char status_open_file[PATH_SIZE + NAME_SIZE];
  142. char status_files_n[15];
  143. char status_activity[9];
  144. char misc_titles[DATA_COLS_N][ITEM_SIZE];
  145. char misc_switches[DATA_COLS_N][ITEM_SIZE];
  146. unsigned int data_cols_cw[DATA_COLS_N + 3] = {1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2};
  147. int data_cols_ena[DATA_COLS_N + 3] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
  148. char data_header[DATA_COLS_N + 3][ITEM_SIZE] = {
  149. "TAGS",
  150. "UID",
  151. "FILENAME",
  152. "TOPICS",
  153. "AUTHORS",
  154. "INSTITUTIONS",
  155. "PUBLISHER",
  156. "YEAR",
  157. "VOL",
  158. "NO",
  159. "PAGES",
  160. "ACCESSED"
  161. };
  162. /* misc */
  163. btk_arg_t dummy_arg = {.i = 0, .f = 0.0f, .c = NULL, .p = NULL};
  164. /*******************************************************************/
  165. void
  166. build_entry_form()
  167. {
  168. entry_form = btk_window_create(session->x_con,
  169. session->x_scr,
  170. session->x_vis,
  171. 8, 6 + DATA_COLS_N,
  172. 4, 3 + DATA_COLS_N,
  173. 100, 0,
  174. 10 + 2 * DATA_COLS_N,
  175. entry_form_close);
  176. btk_window_set_name(entry_form, "hotpot - entry form");
  177. edited_note_cell_id = 0;
  178. edited_note_cell = &(entry_form->cells[edited_note_cell_id]);
  179. btk_cell_set_editor(edited_note_cell, 2, 2 + DATA_COLS_N, 6, 4, (char*)&edited_note, TEXT_SIZE);
  180. btk_cell_set_mark (&(entry_form->cells[1]), 0, 0, 2, BTK_JUSTIFY_RIGHT, "uid :");
  181. btk_cell_set_mark (&(entry_form->cells[2]), 0, 1, 2, BTK_JUSTIFY_RIGHT, "filename :");
  182. btk_cell_set_mark (&(entry_form->cells[3]), 2, 0, 6, BTK_JUSTIFY_LEFT, edited_uid);
  183. btk_cell_set_input (&(entry_form->cells[4]), 2, 1, 6, (char*)edited_filename, NAME_SIZE);
  184. btk_cell_set_mark (&(entry_form->cells[5]), 0, 2 + DATA_COLS_N, 2, BTK_JUSTIFY_RIGHT, "notes :");
  185. btk_cell_set_empty (&(entry_form->cells[6]), 0, 3 + DATA_COLS_N, 2, 1);
  186. btk_cell_set_button (&(entry_form->cells[7]), 0, 4 + DATA_COLS_N, 2, "apply", entry_form_apply);
  187. btk_cell_set_button (&(entry_form->cells[8]), 0, 5 + DATA_COLS_N, 2, "close", entry_form_close);
  188. /* generate input fields for misc data */
  189. for (int i = 0; i < DATA_COLS_N; i++) {
  190. strcpy(misc_titles[i], data_header[i + 3]);
  191. str_to_lower_case(misc_titles[i]);
  192. strcat(misc_titles[i], " :");
  193. btk_cell_set_mark (&(entry_form->cells[9 + i]), 0, 2 + i, 2, BTK_JUSTIFY_RIGHT, misc_titles[i]);
  194. btk_cell_set_input (&(entry_form->cells[10 + DATA_COLS_N + i]), 2, 2 + i, 6, (char*)edited_misc[i], NAME_SIZE);
  195. }
  196. }
  197. void
  198. build_file_picker()
  199. {
  200. file_picker = btk_window_create(session->x_con,
  201. session->x_scr,
  202. session->x_vis,
  203. 4, 9,
  204. 2, 2,
  205. 0, 300,
  206. 5,
  207. file_picker_close);
  208. btk_window_set_name(file_picker, "hotpot - file picker");
  209. dir_list_cell_id = 0;
  210. dir_list_cell = &(file_picker->cells[dir_list_cell_id]);
  211. btk_cell_set_list (dir_list_cell,
  212. 0, 1, 4, 5,
  213. &dir_list,
  214. &dir_list_n,
  215. NAME_SIZE,
  216. NULL, NULL,
  217. &dir_spot,
  218. move_dir,
  219. set_file_picker_states);
  220. file_select_cell_id = 1;
  221. file_select_cell = &(file_picker->cells[file_select_cell_id]);
  222. btk_cell_set_button (file_select_cell, 0, 7, 4, "select", file_picker_select);
  223. btk_cell_set_mark (&(file_picker->cells[2]), 0, 0, 4, BTK_JUSTIFY_RIGHT, (char*)&dir_current);
  224. btk_cell_set_switch (&(file_picker->cells[3]), 0, 6, 4, "show hidden", toggle_hidden, dummy_arg);
  225. btk_cell_set_button (&(file_picker->cells[4]), 0, 8, 4, "cancel", file_picker_close);
  226. }
  227. void
  228. build_main_window()
  229. {
  230. main_win = btk_window_create(session->x_con,
  231. session->x_scr,
  232. session->x_vis,
  233. 13, 16,
  234. 4, 7,
  235. 400, 0,
  236. 21,
  237. quit);
  238. btk_window_set_name(main_win, "hotpot");
  239. table_cell_id = 0;
  240. table_cell = &(main_win->cells[table_cell_id]);
  241. btk_cell_set_table(table_cell,
  242. 3, 0, 10, 15,
  243. (char*)data_header,
  244. &data,
  245. ITEM_SIZE,
  246. DATA_COLS_N + 3,
  247. &data_n,
  248. (int*)data_cols_ena,
  249. data_cols_cw,
  250. 2,
  251. NULL, NULL,
  252. &data_spot,
  253. open_ext_entry,
  254. update_select_data);
  255. strcpy(select_note, "");
  256. notes_view_cell_id = 1;
  257. notes_view_cell = &(main_win->cells[notes_view_cell_id]);
  258. btk_cell_set_editor(notes_view_cell,
  259. 3, 9, 10, 6,
  260. select_note,
  261. TEXT_SIZE);
  262. main_win->cells[notes_view_cell_id].state |= BTK_CELL_STATE_DISABLED;
  263. main_win->cells[notes_view_cell_id].state |= BTK_CELL_STATE_HIDDEN;
  264. activity_cell_id = 18;
  265. activity_cell = &(main_win->cells[activity_cell_id]);
  266. btk_cell_set_mark (activity_cell,
  267. 11, 15, 2,
  268. BTK_JUSTIFY_RIGHT,
  269. (char*)&status_activity);
  270. btk_cell_set_button (&(main_win->cells[2]), 0, 0, 3, "open", file_picker_open_open);
  271. btk_cell_set_button (&(main_win->cells[3]), 0, 1, 3, "new", file_picker_open_new);
  272. btk_cell_set_button (&(main_win->cells[4]), 0, 2, 3, "sync", hotpot_sync);
  273. btk_cell_set_button (&(main_win->cells[5]), 0, 3, 3, "view directory", open_ext_dir);
  274. btk_cell_set_button (&(main_win->cells[6]), 0, 4, 3, "reload", hotpot_reload);
  275. btk_cell_set_button (&(main_win->cells[7]), 0, 5, 3, "close", hotpot_close);
  276. btk_cell_set_button (&(main_win->cells[8]), 0, 6, 3, "quit", quit);
  277. btk_cell_set_empty (&(main_win->cells[9]), 0, 7, 3, 1);
  278. btk_cell_set_button (&(main_win->cells[10]), 0, 8, 3, "add file", file_picker_open_entry);
  279. btk_cell_set_button (&(main_win->cells[11]), 0, 9, 3, "edit entry", entry_form_open);
  280. btk_cell_set_button (&(main_win->cells[12]), 0, 10, 3, "tag for deletion", toggle_del_tag);
  281. btk_cell_set_button (&(main_win->cells[19]), 0, 11, 3, "tag for visibility", toggle_visibility_tag);
  282. btk_cell_set_button (&(main_win->cells[20]), 0, 12, 3, "export citation", NULL);
  283. btk_cell_set_empty (&(main_win->cells[13]), 0, 13, 3, 1);
  284. btk_cell_set_switch (&(main_win->cells[14]), 0, 14, 3, "show notes", toggle_notes, dummy_arg);
  285. btk_cell_set_button (&(main_win->cells[15]), 0, 15, 3, "settings", settings_open);
  286. btk_cell_set_mark (&(main_win->cells[16]), 3, 15, 6, BTK_JUSTIFY_RIGHT, (char*)&status_open_file);
  287. btk_cell_set_mark (&(main_win->cells[17]), 9, 15, 2, BTK_JUSTIFY_RIGHT, (char*)&status_files_n);
  288. main_win->cells[15].state |= BTK_CELL_STATE_ON;
  289. main_win->cells[20].state |= BTK_CELL_STATE_DISABLED;
  290. set_main_win_states(0);
  291. }
  292. void
  293. build_settings()
  294. {
  295. settings = btk_window_create(session->x_con,
  296. session->x_scr,
  297. session->x_vis,
  298. 3, 3 + DATA_COLS_N,
  299. -1, -1,
  300. 0, 0,
  301. 3 + DATA_COLS_N,
  302. settings_close);
  303. btk_window_set_name(settings, "hotpot - settings");
  304. btk_arg_t col_arg= {.i = TAG_COL};
  305. btk_cell_set_switch (&(settings->cells[0]), 0, 0, 3, "show tags", toggle_col, col_arg);
  306. btk_cell_set_empty (&(settings->cells[1 + DATA_COLS_N]), 0, 1 + DATA_COLS_N, 3, 1);
  307. btk_cell_set_button (&(settings->cells[2 + DATA_COLS_N]), 0, 2 + DATA_COLS_N, 3, "close", settings_close);
  308. settings->cells[0].state |= BTK_CELL_STATE_ON;
  309. /* generate col toggles for misc data */
  310. for (int i = 0; i < DATA_COLS_N; i++) {
  311. sprintf(misc_switches[i], "show %s", data_header[i + 3]);
  312. str_to_lower_case(misc_switches[i]);
  313. btk_arg_t col_arg = {.i = i + 3};
  314. btk_cell_set_switch (&(settings->cells[1 + i]), 0, 1 + i, 3, misc_switches[i], toggle_col, col_arg);
  315. settings->cells[1 + i].state |= BTK_CELL_STATE_ON;
  316. }
  317. }
  318. /****************************************************************************************/
  319. int
  320. main()
  321. {
  322. getcwd(dir_current, PATH_SIZE);
  323. strcat(dir_current, "/");
  324. /* btk init */
  325. session = btk_open();
  326. build_entry_form();
  327. build_file_picker();
  328. build_main_window();
  329. build_settings();
  330. windows[0] = main_win;
  331. windows[1] = file_picker;
  332. windows[2] = entry_form;
  333. windows[3] = settings;
  334. btk_map(session, main_win);
  335. btk_loop(session, windows, 4);
  336. btk_close(session);
  337. quit();
  338. return 0;
  339. }
  340. /****************************************************************************************/
  341. void
  342. clean_string_copy(char* dest, char* src, unsigned int max_size, int del_newline)
  343. {
  344. if (!max_size)
  345. return;
  346. char mid[max_size];
  347. strncpy(mid, src, max_size);
  348. if (del_newline)
  349. *strchr(mid, '\n') = '\0';
  350. mid[max_size - 1] = '\0';
  351. strcpy(dest, mid);
  352. }
  353. int
  354. cmp_str_for_qsort(const void *a, const void *b)
  355. {
  356. return strcmp((char*)a, (char*)b);
  357. }
  358. /* check if any data changed, copy it and update status if so */
  359. void
  360. entry_form_apply()
  361. {
  362. int changed = 0;
  363. if (strcmp(edited_filename, get_data_item(NAME_COL, select_data))) {
  364. strcpy(data_rename + select_data * ITEM_SIZE, get_data_item(NAME_COL, select_data));
  365. strcpy(get_data_item(NAME_COL, select_data), edited_filename);
  366. changed = 1;
  367. }
  368. for (int i = 0; i < DATA_COLS_N; i++) {
  369. if (strcmp(edited_misc[i], get_data_item(i + 3, select_data))) {
  370. strcpy(get_data_item(i + 3, select_data), edited_misc[i]);
  371. changed = 1;
  372. }
  373. }
  374. if (strcmp(edited_note, select_note)) {
  375. strcpy(data_notes + select_data * TEXT_SIZE, edited_note);
  376. strcpy(select_note, edited_note);
  377. btk_cell_editor_update_text(notes_view_cell);
  378. changed = 1;
  379. }
  380. if (changed) {
  381. data_tags[select_data] |= TAG_EDITED;
  382. set_entry_tag_col(select_data, data_tags[select_data]);
  383. set_activity_status(STATUS_EDITED, 1);
  384. btk_window_redraw(main_win);
  385. }
  386. }
  387. void
  388. entry_form_open()
  389. {
  390. if (select_data < 0 || select_data >= data_n)
  391. return;
  392. strcpy(edited_note, select_note);
  393. btk_cell_editor_reset_caret(edited_note_cell);
  394. strcpy(edited_uid, get_data_item(1, select_data));
  395. strcpy(edited_filename, get_data_item(2, select_data));
  396. btk_cell_input_reset_caret(&(entry_form->cells[4]));
  397. for (int i = 0; i < DATA_COLS_N; i++) {
  398. strcpy(edited_misc[i], get_data_item(i + 3, select_data));
  399. btk_cell_input_reset_caret(&(entry_form->cells[10 + DATA_COLS_N + i]));
  400. }
  401. btk_cell_editor_update_text(edited_note_cell);
  402. btk_window_disable(main_win);
  403. btk_map(session, entry_form);
  404. }
  405. void
  406. entry_form_close()
  407. {
  408. btk_window_enable(main_win);
  409. btk_unmap(session, entry_form);
  410. }
  411. /* checks if currently selected file in the file picker
  412. * exists in the open hotpot directory */
  413. int
  414. file_exists()
  415. {
  416. DIR *d;
  417. struct dirent *dir;
  418. d = opendir(open_dir);
  419. if (!d) {
  420. printf("ERROR - couldn't read directory");
  421. return 0;
  422. }
  423. while ((dir = readdir(d))) {
  424. if (!strcmp(dir->d_name, dir_list + nav_select * NAME_SIZE))
  425. return 1;
  426. }
  427. return 0;
  428. }
  429. void
  430. file_picker_close()
  431. {
  432. btk_window_enable(main_win);
  433. btk_unmap(session, file_picker);
  434. }
  435. void
  436. file_picker_open(int mode)
  437. {
  438. btk_cell_list_deselect(dir_list_cell);
  439. set_file_picker_states(-1);
  440. file_picker_mode = mode;
  441. if (!file_picker_mode) {
  442. nav_mode |= DIR_FILES;
  443. } else {
  444. nav_mode &= ~DIR_FILES;
  445. }
  446. btk_window_disable(main_win);
  447. btk_map(session, file_picker);
  448. parse_dir(dir_current, nav_mode);
  449. }
  450. void file_picker_open_entry() { file_picker_open(0); }
  451. void file_picker_open_open() { file_picker_open(1); }
  452. void file_picker_open_new() { file_picker_open(2); }
  453. void
  454. file_picker_select()
  455. {
  456. if (nav_select < 0 || nav_select >= dir_list_n) {
  457. printf("ERROR -> tried to open out of bound selection\n");
  458. return;
  459. }
  460. switch(file_picker_mode) {
  461. /* copy selected file into open hotpot directory, then add it to data */
  462. case 0:;
  463. /* compose command */
  464. char cmd[12 + 2 * PATH_SIZE + NAME_SIZE];
  465. sprintf(cmd,
  466. "cp -n \'%s%s\' \'%s\'",
  467. dir_current,
  468. dir_list + nav_select * NAME_SIZE,
  469. open_dir);
  470. system(cmd);
  471. /* create new entry */
  472. data_entry_t new_entry;
  473. new_entry.notes_w = 0;
  474. new_entry.notes[0] = '\0';
  475. new_entry.uid[0] = '\0';
  476. for (int i = 0; i < DATA_COLS_N; i++)
  477. new_entry.misc[i][0] = '\0';
  478. strcpy(new_entry.filename, dir_list + nav_select * NAME_SIZE);
  479. push_entry(TAG_NEW, new_entry);
  480. /* update window */
  481. set_activity_status(STATUS_EDITED, 0);
  482. set_entry_tag_col(data_n - 1, data_tags[data_n - 1]);
  483. set_main_win_states(1);
  484. break;
  485. /* open hotpot */
  486. case 1:
  487. strcpy(open_dir, dir_current);
  488. strcat(open_dir, dir_list + nav_select * NAME_SIZE);
  489. hotpot_load();
  490. break;
  491. /* create hotpot file, then open it */
  492. case 2:
  493. strcpy(open_dir, dir_current);
  494. strcat(open_dir, dir_list + nav_select * NAME_SIZE);
  495. char hotpot_file[PATH_SIZE + NAME_SIZE];
  496. strcpy(hotpot_file, open_dir);
  497. strcat(hotpot_file, "/.htpt");
  498. FILE *f = fopen(hotpot_file, "w");
  499. if (!f) {
  500. set_activity_status(STATUS_ERROR, 1);
  501. printf("ERROR - couldn't create new hotpot file");
  502. return;
  503. }
  504. fclose(f);
  505. hotpot_load();
  506. break;
  507. }
  508. file_picker_close();
  509. set_main_win_states(1);
  510. }
  511. /* returns the hilight color index of the directory */
  512. int
  513. find_dir_spot(char *search_dir, char *sub_dir)
  514. {
  515. char search_path[PATH_SIZE];
  516. strcpy(search_path, search_dir);
  517. strcat(search_path, sub_dir);
  518. strcat(search_path, "/");
  519. DIR *d;
  520. struct dirent *dir;
  521. struct stat file_stats;
  522. char file_path[PATH_SIZE + NAME_SIZE];
  523. d = opendir(search_path);
  524. if (!d) {
  525. printf("ERROR - couldn't read directory");
  526. return 0;
  527. }
  528. while ((dir = readdir(d))) {
  529. strcpy(file_path, search_path);
  530. strcat(file_path, dir->d_name);
  531. stat(file_path, &file_stats);
  532. if ((file_stats.st_mode & S_IFMT) != S_IFDIR) {
  533. if (strcmp(dir->d_name, ".htpt") == 0) {
  534. return 1;
  535. }
  536. }
  537. }
  538. return 2;
  539. }
  540. char*
  541. get_data_item(unsigned int col, unsigned int row)
  542. {
  543. return data + ITEM_SIZE * (col + row * (DATA_COLS_N + 3));
  544. }
  545. void
  546. hotpot_close()
  547. {
  548. hotpot_unload();
  549. select_data = -1;
  550. strcpy(select_note, "");
  551. strcpy(open_dir, "");
  552. set_main_win_states(1);
  553. }
  554. void
  555. hotpot_load()
  556. {
  557. set_activity_status(STATUS_BUSY, 1);
  558. char hotpot_file[PATH_SIZE + NAME_SIZE];
  559. strcpy(hotpot_file, open_dir);
  560. strcat(hotpot_file, "/.htpt");
  561. FILE *f = fopen(hotpot_file, "r");
  562. if (!f) {
  563. printf("ERROR - couldn't read hotpot file\n");
  564. set_activity_status(STATUS_ERROR, 1);
  565. return;
  566. }
  567. hotpot_unload();
  568. /* arrays preparation for on the go resizing */
  569. data_buffer_n = DATA_BUFFER_INC;
  570. data = malloc(data_buffer_n * ITEM_SIZE * (DATA_COLS_N + 3));
  571. data_notes = malloc(data_buffer_n * TEXT_SIZE);
  572. data_tags = malloc(data_buffer_n * sizeof(int));
  573. data_spot = malloc(data_buffer_n * sizeof(int));
  574. data_rename = malloc(data_buffer_n * ITEM_SIZE); /* used for syncing later */
  575. data_entry_t entry_read;
  576. char line_read[READ_SIZE];
  577. char *last_newline;
  578. int in_section = 0, col = 0, w = 0;
  579. /* get lastest used uid on the first line */
  580. /* if it is not present it will be regenerated after the rest of the file has
  581. * been parsed */
  582. if (fgets(line_read, READ_SIZE, f) && line_read[0] == '-') {
  583. last_uid = strtol(line_read + 1, NULL, 16);
  584. } else {
  585. last_uid = 0; /* to be regenerated */
  586. }
  587. /* parse rest of .htpt file */
  588. while (fgets(line_read, READ_SIZE, f)) {
  589. switch (line_read[0]) {
  590. /* open section, reset entry_read */
  591. case '[':
  592. if (in_section)
  593. break;
  594. in_section = 1;
  595. col = 0;
  596. w = 0;
  597. entry_read.notes_w = 0;
  598. entry_read.notes[0] = '\0';
  599. entry_read.uid[0] = '\0';
  600. entry_read.filename[0] = '\0';
  601. for (int i = 0; i < DATA_COLS_N; i++)
  602. entry_read.misc[i][0] = '\0';
  603. break;
  604. /* close section, push entry_read to data */
  605. case ']':
  606. if (!in_section)
  607. break;
  608. in_section = 0;
  609. last_newline = strrchr(entry_read.notes, '\n');
  610. if (last_newline) /* remove last unecessary newline */
  611. *last_newline = '\0';
  612. push_entry(TAG_STRAY, entry_read);
  613. break;
  614. /* get uid */
  615. case '-':
  616. if (!in_section)
  617. break;
  618. clean_string_copy(entry_read.uid, line_read + 1, ITEM_SIZE, 1);
  619. break;
  620. /* get filename */
  621. case '+':
  622. if (!in_section)
  623. break;
  624. clean_string_copy(entry_read.filename, line_read + 1, ITEM_SIZE, 1);
  625. break;
  626. /* get other data */
  627. case '.':
  628. if (!in_section || col >= DATA_COLS_N)
  629. break;
  630. clean_string_copy(entry_read.misc[col], line_read + 1, ITEM_SIZE, 1);
  631. col++;
  632. break;
  633. /* get notes on multiple lines until section close or reaching TEXT_SIZE
  634. * character limit */
  635. case '*':
  636. if (!in_section)
  637. break;
  638. w = strlen(line_read + 1);
  639. if (entry_read.notes_w + w >= TEXT_SIZE) {
  640. w = TEXT_SIZE - entry_read.notes_w;
  641. } else {
  642. strncat(entry_read.notes, line_read + 1, w);
  643. }
  644. entry_read.notes_w += w;
  645. break;
  646. default:
  647. break;
  648. }
  649. }
  650. fclose(f);
  651. /* regenerate uid if needed */
  652. if (!last_uid) {
  653. for (int i = 0; i < data_n; i++)
  654. if (last_uid < strtol(get_data_item(UID_COL, i), NULL, 16))
  655. last_uid = strtol(get_data_item(UID_COL, i), NULL, 16);
  656. }
  657. /* parse all files in hotpot directory and match them to parsed data */
  658. DIR *d = opendir(open_dir);
  659. struct dirent *dir;
  660. struct stat file_stats;
  661. char file_path[PATH_SIZE + NAME_SIZE];
  662. int found = 0;
  663. int new_files = 0;
  664. int n = data_n;
  665. int is_dir;
  666. data_entry_t dummy_entry;
  667. dummy_entry.uid[0] = '\0';
  668. dummy_entry.notes[0] = '\0';
  669. dummy_entry.notes_w = 0;
  670. for (int i = 0; i < DATA_COLS_N; i++)
  671. dummy_entry.misc[i][0] = '\0';
  672. /* scan found files */
  673. while ((dir = readdir(d))) {
  674. found = 0;
  675. strcpy(file_path, open_dir);
  676. strcat(file_path, dir->d_name);
  677. stat(file_path, &file_stats);
  678. is_dir = (file_stats.st_mode & S_IFMT) == S_IFDIR ? 1 : 0;
  679. //printf("%i\t%s\n", is_dir, dir->d_name); TODO fix directory detection
  680. if (is_dir || dir->d_name[0] == '.') {
  681. continue;
  682. }
  683. for (int i = 0; i < n; i++) {
  684. if (strcmp(dir->d_name, get_data_item(NAME_COL, i)) == 0) {
  685. data_tags[i] = TAG_NONE;
  686. found = 1;
  687. break;
  688. }
  689. }
  690. /* if file not found, create new entry */
  691. if (!found) {
  692. clean_string_copy(dummy_entry.filename, dir->d_name, ITEM_SIZE, 0);
  693. push_entry(TAG_NEW, dummy_entry);
  694. new_files = 1;
  695. }
  696. }
  697. /* set tag values in data */
  698. for (int i = 0; i < data_n; i++) {
  699. set_entry_tag_col(i, data_tags[i]);
  700. }
  701. btk_cell_table_deselect(table_cell);
  702. strcpy(select_note, "");
  703. set_activity_status((new_files ? STATUS_EDITED : STATUS_LATEST), 1);
  704. return;
  705. }
  706. void
  707. hotpot_reload()
  708. {
  709. hotpot_unload();
  710. select_data = -1;
  711. strcpy(select_note, "");
  712. hotpot_load();
  713. set_main_win_states(1);
  714. }
  715. void
  716. hotpot_sync()
  717. {
  718. set_activity_status(STATUS_BUSY, 1);
  719. char hotpot_file[PATH_SIZE + NAME_SIZE];
  720. strcpy(hotpot_file, open_dir);
  721. strcat(hotpot_file, "/.htpt");
  722. FILE *f = fopen(hotpot_file, "w");
  723. if (!f) {
  724. printf("ERROR - couldn't write hotpot file\n");
  725. set_activity_status(STATUS_ERROR, 1);
  726. return;
  727. }
  728. /* output last uid */
  729. fprintf(f, "-%X\n\n", last_uid);
  730. /* output rows of data */
  731. char *note_token;
  732. char note[TEXT_SIZE];
  733. for (int i = 0; i < data_n; i++) {
  734. if ((data_tags[i] & TAG_DEL))
  735. continue;
  736. fprintf(f, "[\n");
  737. fprintf(f, "-%s\n", get_data_item(UID_COL, i));
  738. fprintf(f, "+%s\n", get_data_item(NAME_COL, i));
  739. for (int j = 0; j < DATA_COLS_N; j++)
  740. fprintf(f, ".%s\n", get_data_item(j + 3, i));
  741. // TODO
  742. /*
  743. strcpy(note, data_notes + i * TEXT_SIZE);
  744. char *lim = strchr(note, '\n');
  745. while (lim) {
  746. *lim = '\0';
  747. printf("%lu >> \'%s\'\n", strlen(note), note);
  748. fprintf(f, "*%s\n", note);
  749. strcpy(note, ++lim);
  750. lim = strchr(note, '\n');
  751. }
  752. */
  753. strcpy(note, data_notes + i * TEXT_SIZE);
  754. note_token = strtok(note, "\n");
  755. while (note_token) {
  756. fprintf(f, "*%s\n", note_token);
  757. note_token = strtok(NULL, "\n");
  758. }
  759. fprintf(f, "]\n\n");
  760. }
  761. fclose(f);
  762. /* rename edited files if those are not stray entries */
  763. char cmd_mv[11 + 2 * (PATH_SIZE + NAME_SIZE)];
  764. for (int i = 0; i < data_n; i++) {
  765. if (!(data_tags[i] & TAG_STRAY) && strcmp(data_rename + i * ITEM_SIZE, "")) {
  766. sprintf(cmd_mv,
  767. "mv \'%s/%s\' \'%s/%s\'",
  768. open_dir,
  769. data_rename + i * ITEM_SIZE,
  770. open_dir,
  771. get_data_item(NAME_COL, i));
  772. system(cmd_mv);
  773. }
  774. }
  775. /* delete rows with DEL tag by shifting down */
  776. int c = 0;
  777. char mid[TEXT_SIZE]; /* just to get rid of pointer overlap warning */
  778. char cmd_rm[5 + PATH_SIZE + NAME_SIZE];
  779. for (int i = 0; i < data_n; i++) {
  780. if (c) {
  781. data_tags[i - c] = data_tags[i];
  782. strcpy(mid, data_notes + i * TEXT_SIZE);
  783. strcpy(data_notes + (i - c) * TEXT_SIZE, mid);
  784. for (int j = 0; j < DATA_COLS_N + 3; j++)
  785. strcpy(get_data_item(j, i - c), get_data_item(j, i));
  786. }
  787. if ((data_tags[i] & TAG_DEL)) {
  788. if (!(data_tags[i] & TAG_STRAY)) {
  789. sprintf(cmd_rm,
  790. "rm \'%s/%s\'",
  791. open_dir,
  792. get_data_item(NAME_COL, i));
  793. system(cmd_rm);
  794. }
  795. c++;
  796. }
  797. }
  798. data_n -= c;
  799. /* remove EDIT and NEW tags */
  800. for (int i = 0; i < data_n; i++) {
  801. data_tags[i] &= ~(TAG_EDITED | TAG_NEW);
  802. }
  803. /* update tag values in data */
  804. for (int i = 0; i < data_n; i++) {
  805. set_entry_tag_col(i, data_tags[i]);
  806. }
  807. set_activity_status(STATUS_LATEST, 0);
  808. btk_window_redraw(main_win);
  809. return;
  810. }
  811. void
  812. hotpot_unload()
  813. {
  814. if (data_n) {
  815. free(data);
  816. free(data_tags);
  817. free(data_spot);
  818. free(data_notes);
  819. free(data_rename);
  820. data_n = 0;
  821. }
  822. }
  823. void
  824. move_dir(int dir_sel)
  825. {
  826. if (dir_sel < 0 || !dir_spot[dir_sel])
  827. return;
  828. /* if first item selected ("..") go one dir up, unless at / */
  829. if (!dir_sel) {
  830. if (strlen(dir_current) <= 1)
  831. return;
  832. dir_current[strlen(dir_current) - 1] = '\0';
  833. *(strrchr(dir_current, '/')) = '\0';
  834. } else {
  835. char dir_sel_name[PATH_SIZE];
  836. strcpy(dir_sel_name, dir_list + dir_sel * NAME_SIZE);
  837. strcat(dir_current, dir_sel_name);
  838. }
  839. strcat(dir_current, "/");
  840. parse_dir(dir_current, nav_mode);
  841. btk_window_redraw_cell(file_picker, dir_list_cell_id);
  842. btk_window_redraw_cell(file_picker, 2);
  843. if (dir_sel) {
  844. btk_cell_list_deselect(dir_list_cell);
  845. set_file_picker_states(-1);
  846. }
  847. }
  848. void
  849. open_ext_dir()
  850. {
  851. char *args[PATH_SIZE]={"./EXEC", open_dir, NULL};
  852. int pid = fork();
  853. if (pid == 0) {
  854. execvp("xdg-open", args);
  855. } else if (pid < 0) {
  856. printf("ERROR - couldn't open hotpot directory in file explorer\n");
  857. }
  858. }
  859. void
  860. open_ext_entry(int sel)
  861. {
  862. if (sel < 0)
  863. return;
  864. char file[PATH_SIZE + ITEM_SIZE];
  865. strcpy(file, open_dir);
  866. strcat(file, "/");
  867. strcat(file, get_data_item(NAME_COL, sel));
  868. char *args[PATH_SIZE]={"./EXEC", file, NULL};
  869. int pid = fork();
  870. if (pid == 0) {
  871. execvp("xdg-open", args);
  872. } else if (pid < 0) {
  873. printf("ERROR - couldn't open item externaly\n");
  874. }
  875. }
  876. int
  877. parse_dir(char *dir_path, int mode)
  878. {
  879. DIR *d = opendir(dir_path);
  880. if (!d) {
  881. printf("ERROR - couldn't read directory");
  882. return 1;
  883. }
  884. struct dirent *dir;
  885. struct stat file_stats;
  886. char file_path[PATH_SIZE + NAME_SIZE];
  887. unsigned int dir_buffer_n = DIR_BUFFER_INC;
  888. int c = 0;
  889. int is_dir;
  890. if (dir_list_n) {
  891. free(dir_list);
  892. free(dir_spot);
  893. }
  894. dir_list_n = 0;
  895. dir_list = malloc(dir_buffer_n * NAME_SIZE);
  896. dir_spot = malloc(dir_buffer_n * sizeof(int));
  897. while ((dir = readdir(d))) {
  898. sprintf(file_path, "%s%s", dir_path, dir->d_name);
  899. stat(file_path, &file_stats);
  900. is_dir = (file_stats.st_mode & S_IFMT) == S_IFDIR ? 1 : 0;
  901. if (((mode & DIR_FILES) || is_dir) && c &&
  902. ((mode & DIR_HIDDEN) || dir->d_name[0] != '.' || c < 2)) {
  903. strcpy(dir_list + dir_list_n * NAME_SIZE, dir->d_name);
  904. if (is_dir) /* adding '/' to dir items to easily detect them when sorting */
  905. strcat(dir_list + dir_list_n * NAME_SIZE, "/");
  906. dir_spot[dir_list_n] = 0;
  907. dir_list_n++;
  908. }
  909. c++;
  910. if (dir_list_n >= dir_buffer_n - 1) {
  911. dir_buffer_n += DIR_BUFFER_INC;
  912. dir_spot = realloc(dir_spot, dir_buffer_n * sizeof(int));
  913. dir_list = realloc(dir_list, dir_buffer_n * NAME_SIZE);
  914. }
  915. }
  916. /* sort dir list and set hilights */
  917. char *a;
  918. qsort(dir_list, dir_list_n, NAME_SIZE, cmp_str_for_qsort);
  919. for (int i = 0; i < dir_list_n; i++) {
  920. a = strchr(dir_list + i * NAME_SIZE, '/');
  921. if (a) {
  922. *a = '\0';
  923. dir_spot[i] = find_dir_spot(dir_path, dir_list + i * NAME_SIZE);
  924. }
  925. }
  926. return 0;
  927. }
  928. void
  929. push_entry(int tag, data_entry_t entry)
  930. {
  931. if (!data) {
  932. printf("ERROR - tried to push entry into NULL data array\n");
  933. return;
  934. }
  935. if (data_n >= data_buffer_n - 1) {
  936. data_buffer_n += DATA_BUFFER_INC;
  937. data = realloc(data, data_buffer_n * ITEM_SIZE * (DATA_COLS_N + 3));
  938. data_notes = realloc(data_notes, data_buffer_n * TEXT_SIZE);
  939. data_tags = realloc(data_tags, data_buffer_n * sizeof(int));
  940. data_spot = realloc(data_spot, data_buffer_n * sizeof(int));
  941. data_rename = realloc(data_rename, data_buffer_n * ITEM_SIZE);
  942. }
  943. if (!strcmp(entry.uid, "")) {
  944. char new_uid[64];
  945. sprintf(new_uid, "%X", ++last_uid);
  946. strcpy(get_data_item(UID_COL, data_n), new_uid);
  947. } else {
  948. strcpy(get_data_item(UID_COL, data_n), entry.uid);
  949. }
  950. data_tags[data_n] = tag;
  951. strcpy(data_rename + data_n * ITEM_SIZE, "");
  952. strcpy(get_data_item(NAME_COL, data_n), entry.filename);
  953. for (int i = 0; i < DATA_COLS_N; i++)
  954. strcpy(get_data_item(i + 3, data_n), entry.misc[i]);
  955. strcpy(data_notes + data_n * TEXT_SIZE, entry.notes);
  956. data_n++;
  957. }
  958. void
  959. quit()
  960. {
  961. hotpot_unload();
  962. if (dir_list_n) {
  963. free(dir_list);
  964. free(dir_spot);
  965. }
  966. btk_window_destroy(entry_form);
  967. btk_window_destroy(file_picker);
  968. btk_window_destroy(main_win);
  969. btk_window_destroy(settings);
  970. btk_close(session);
  971. exit(0);
  972. }
  973. void
  974. settings_close()
  975. {
  976. btk_window_enable(main_win);
  977. btk_unmap(session, settings);
  978. }
  979. void
  980. settings_open()
  981. {
  982. btk_window_disable(main_win);
  983. btk_map(session, settings);
  984. }
  985. void
  986. set_activity_status(int status, int redraw)
  987. {
  988. switch (status) {
  989. case STATUS_NONE:
  990. strcpy(status_activity, "n/a");
  991. activity_cell->state |= BTK_CELL_STATE_DISABLED;
  992. activity_cell->state &= ~BTK_CELL_STATE_BELL;
  993. activity_cell->state &= ~BTK_CELL_STATE_ON;
  994. break;
  995. case STATUS_ERROR:
  996. strcpy(status_activity, "error");
  997. activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
  998. activity_cell->state |= BTK_CELL_STATE_BELL;
  999. activity_cell->state &= ~BTK_CELL_STATE_ON;
  1000. break;
  1001. case STATUS_LATEST:
  1002. strcpy(status_activity, "synced");
  1003. activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
  1004. activity_cell->state &= ~BTK_CELL_STATE_BELL;
  1005. activity_cell->state &= ~BTK_CELL_STATE_ON;
  1006. break;
  1007. case STATUS_EDITED:
  1008. strcpy(status_activity, "unsynced");
  1009. activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
  1010. activity_cell->state &= ~BTK_CELL_STATE_BELL;
  1011. activity_cell->state |= BTK_CELL_STATE_ON;
  1012. break;
  1013. case STATUS_BUSY:
  1014. strcpy(status_activity, "busy");
  1015. activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
  1016. activity_cell->state |= BTK_CELL_STATE_BELL;
  1017. activity_cell->state &= ~BTK_CELL_STATE_ON;
  1018. break;
  1019. }
  1020. if (redraw)
  1021. btk_window_redraw_cell(main_win, activity_cell_id);
  1022. }
  1023. void
  1024. set_edit_tag()
  1025. {
  1026. if (select_data < 0 || select_data >= data_n) {
  1027. printf("ERROR - can't tag out of bounds selection\n");
  1028. return;
  1029. }
  1030. data_tags[select_data] |= TAG_DEL;
  1031. btk_window_redraw_cell(main_win, table_cell_id);
  1032. }
  1033. void
  1034. set_entry_tag_col(unsigned int id, int tag)
  1035. {
  1036. if (tag & TAG_DEL) {
  1037. strcpy(get_data_item(TAG_COL, id), "DEL");
  1038. data_spot[id] = 1;
  1039. } else if (tag & TAG_VISIBILITY) {
  1040. strcpy(get_data_item(TAG_COL, id), "FOCUS");
  1041. data_spot[id] = 4;
  1042. } else if (tag & TAG_EDITED){
  1043. strcpy(get_data_item(TAG_COL, id), "EDIT");
  1044. data_spot[id] = 1;
  1045. } else if (tag & TAG_STRAY){
  1046. strcpy(get_data_item(TAG_COL, id), "STRAY");
  1047. data_spot[id] = 3;
  1048. } else if (tag & TAG_NEW){
  1049. strcpy(get_data_item(TAG_COL, id), "NEW");
  1050. data_spot[id] = 2;
  1051. } else {
  1052. strcpy(get_data_item(TAG_COL, id), "");
  1053. data_spot[id] = 0;
  1054. }
  1055. }
  1056. void
  1057. set_file_picker_states(int sel)
  1058. {
  1059. nav_select = sel;
  1060. if (sel < 1) { /* separate to avoid segfault */
  1061. file_select_cell->state |= BTK_CELL_STATE_DISABLED;
  1062. btk_window_redraw_cell(file_picker, file_select_cell_id);
  1063. return;
  1064. }
  1065. switch (file_picker_mode) {
  1066. case 0:;
  1067. char forbidden_path[PATH_SIZE];
  1068. strcpy(forbidden_path, open_dir);
  1069. strcat(forbidden_path, "/");
  1070. if(!dir_spot[sel] && strcmp(dir_current, forbidden_path) != 0 && !file_exists()) {
  1071. file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
  1072. } else {
  1073. file_select_cell->state |= BTK_CELL_STATE_DISABLED;
  1074. }
  1075. break;
  1076. case 1:
  1077. if (dir_spot[sel] == 1) {
  1078. file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
  1079. } else {
  1080. file_select_cell->state |= BTK_CELL_STATE_DISABLED;
  1081. }
  1082. break;
  1083. case 2:
  1084. if (dir_spot[sel] == 1) {
  1085. file_select_cell->state |= BTK_CELL_STATE_DISABLED;
  1086. } else {
  1087. file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
  1088. }
  1089. break;
  1090. }
  1091. btk_window_redraw_cell(file_picker, file_select_cell_id);
  1092. }
  1093. void
  1094. set_main_win_states(int redraw)
  1095. {
  1096. if (!(strcmp(open_dir, ""))) {
  1097. main_win->cells[4].state |= BTK_CELL_STATE_DISABLED;
  1098. main_win->cells[5].state |= BTK_CELL_STATE_DISABLED;
  1099. main_win->cells[6].state |= BTK_CELL_STATE_DISABLED;
  1100. main_win->cells[7].state |= BTK_CELL_STATE_DISABLED;
  1101. main_win->cells[10].state |= BTK_CELL_STATE_DISABLED;
  1102. main_win->cells[16].state |= BTK_CELL_STATE_DISABLED;
  1103. main_win->cells[17].state |= BTK_CELL_STATE_DISABLED;
  1104. strcpy(status_open_file, "no hotpot opened");
  1105. strcpy(status_files_n, "n/a entries");
  1106. set_activity_status(STATUS_NONE, redraw);
  1107. } else {
  1108. main_win->cells[4].state &= ~BTK_CELL_STATE_DISABLED;
  1109. main_win->cells[5].state &= ~BTK_CELL_STATE_DISABLED;
  1110. main_win->cells[6].state &= ~BTK_CELL_STATE_DISABLED;
  1111. main_win->cells[7].state &= ~BTK_CELL_STATE_DISABLED;
  1112. main_win->cells[10].state &= ~BTK_CELL_STATE_DISABLED;
  1113. main_win->cells[16].state &= ~BTK_CELL_STATE_DISABLED;
  1114. main_win->cells[17].state &= ~BTK_CELL_STATE_DISABLED;
  1115. strcpy(status_open_file, open_dir);
  1116. sprintf(status_files_n, "%i entries", data_n);
  1117. }
  1118. if (data_n < 1 || select_data < 0) {
  1119. main_win->cells[11].state |= BTK_CELL_STATE_DISABLED;
  1120. main_win->cells[12].state |= BTK_CELL_STATE_DISABLED;
  1121. main_win->cells[19].state |= BTK_CELL_STATE_DISABLED;
  1122. } else {
  1123. main_win->cells[11].state &= ~BTK_CELL_STATE_DISABLED;
  1124. main_win->cells[12].state &= ~BTK_CELL_STATE_DISABLED;
  1125. main_win->cells[19].state &= ~BTK_CELL_STATE_DISABLED;
  1126. }
  1127. if (redraw)
  1128. btk_window_redraw(main_win);
  1129. }
  1130. void
  1131. str_to_lower_case(char *str)
  1132. {
  1133. for (int i = 0; str[i] != '\0'; i++)
  1134. if(str[i] >= 'A' && str[i] <= 'Z')
  1135. str[i] += 32;
  1136. }
  1137. void
  1138. toggle_col(int val, btk_arg_t arg)
  1139. {
  1140. data_cols_ena[arg.i] = val;
  1141. btk_cell_table_update_geometry(table_cell);
  1142. btk_window_redraw_cell(main_win, table_cell_id);
  1143. }
  1144. void
  1145. toggle_del_tag()
  1146. {
  1147. if (select_data < 0 || select_data >= data_n) {
  1148. printf("ERROR - can't tag out of bounds selection\n");
  1149. return;
  1150. }
  1151. data_tags[select_data] ^= TAG_DEL;
  1152. set_entry_tag_col(select_data, data_tags[select_data]);
  1153. set_activity_status(STATUS_EDITED, 1);
  1154. btk_window_redraw_cell(main_win, table_cell_id);
  1155. }
  1156. void
  1157. toggle_hidden(int i, btk_arg_t arg)
  1158. {
  1159. if (i) {
  1160. nav_mode |= DIR_HIDDEN;
  1161. } else {
  1162. nav_mode &= ~DIR_HIDDEN;
  1163. }
  1164. parse_dir(dir_current, nav_mode);
  1165. btk_window_redraw_cell(file_picker, dir_list_cell_id);
  1166. }
  1167. void
  1168. toggle_notes(int val, btk_arg_t arg)
  1169. {
  1170. if (val) {
  1171. table_cell->ca.h = 9;
  1172. notes_view_cell->state &= ~BTK_CELL_STATE_HIDDEN;
  1173. } else {
  1174. table_cell->ca.h = 15;
  1175. notes_view_cell->state |= BTK_CELL_STATE_HIDDEN;
  1176. }
  1177. btk_window_update_cell_area(main_win, table_cell);
  1178. btk_window_redraw(main_win);
  1179. }
  1180. void
  1181. toggle_visibility_tag()
  1182. {
  1183. if (select_data < 0 || select_data >= data_n) {
  1184. printf("ERROR - can't tag out of bounds selection\n");
  1185. return;
  1186. }
  1187. data_tags[select_data] ^= TAG_VISIBILITY;
  1188. set_entry_tag_col(select_data, data_tags[select_data]);
  1189. btk_window_redraw_cell(main_win, table_cell_id);
  1190. }
  1191. void
  1192. update_select_data(int sel)
  1193. {
  1194. select_data = sel;
  1195. if (sel > data_n)
  1196. select_data = -1;
  1197. if (select_data < 0) {
  1198. strcpy(select_note, "");
  1199. main_win->cells[11].state |= BTK_CELL_STATE_DISABLED;
  1200. main_win->cells[12].state |= BTK_CELL_STATE_DISABLED;
  1201. main_win->cells[19].state |= BTK_CELL_STATE_DISABLED;
  1202. } else {
  1203. strcpy(select_note,data_notes + sel * TEXT_SIZE);
  1204. main_win->cells[11].state &= ~BTK_CELL_STATE_DISABLED;
  1205. main_win->cells[12].state &= ~BTK_CELL_STATE_DISABLED;
  1206. main_win->cells[19].state &= ~BTK_CELL_STATE_DISABLED;
  1207. }
  1208. btk_cell_editor_update_text(notes_view_cell);
  1209. btk_window_redraw_cell(main_win, notes_view_cell_id);
  1210. btk_window_redraw_cell(main_win, 11);
  1211. btk_window_redraw_cell(main_win, 12);
  1212. btk_window_redraw_cell(main_win, 19);
  1213. }