viewport.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #ifdef _WIN32
  11. #include <windows.h>
  12. #endif
  13. #include <assert.h>
  14. #include "viewport.h"
  15. #include "draw.h"
  16. #include <common/color.h>
  17. #include <glade/glade.h>
  18. #include "gui.h"
  19. #include <limits.h>
  20. #include "menucallbacks.h"
  21. #include <stdbool.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include "glcompui.h"
  25. #include "gltemplate.h"
  26. #include <common/colorprocs.h>
  27. #include "topviewsettings.h"
  28. #include "arcball.h"
  29. #include "hotkeymap.h"
  30. #include "topviewfuncs.h"
  31. #include <util/alloc.h>
  32. #include <util/exit.h>
  33. #include <util/strcasecmp.h>
  34. static colorschemaset create_color_theme(int themeid);
  35. ViewInfo *view;
  36. static void clear_viewport(ViewInfo *vi) {
  37. if (vi->graphCount)
  38. agclose(vi->g[vi->activeGraph]);
  39. }
  40. static void *get_glut_font(int ind)
  41. {
  42. switch (ind) {
  43. case 0:
  44. return GLUT_BITMAP_9_BY_15;
  45. break;
  46. case 1:
  47. return GLUT_BITMAP_8_BY_13;
  48. break;
  49. case 2:
  50. return GLUT_BITMAP_TIMES_ROMAN_10;
  51. break;
  52. case 3:
  53. return GLUT_BITMAP_HELVETICA_10;
  54. break;
  55. case 4:
  56. return GLUT_BITMAP_HELVETICA_12;
  57. break;
  58. case 5:
  59. return GLUT_BITMAP_HELVETICA_18;
  60. break;
  61. default:
  62. return GLUT_BITMAP_TIMES_ROMAN_10;
  63. }
  64. }
  65. void close_graph(ViewInfo *vi) {
  66. if (vi->activeGraph < 0)
  67. return;
  68. clear_viewport(vi);
  69. }
  70. char *get_attribute_value(char *attr, ViewInfo *vi, Agraph_t *g) {
  71. char *buf;
  72. buf = agget(g, attr);
  73. if (!buf || *buf == '\0')
  74. buf = agget(vi->systemGraphs.def_attrs, attr);
  75. return buf;
  76. }
  77. void set_viewport_settings_from_template(ViewInfo *vi, Agraph_t *g) {
  78. gvcolor_t cl;
  79. colorxlate(get_attribute_value("bordercolor", vi, g), &cl,
  80. RGBA_DOUBLE);
  81. vi->borderColor.R = (float)cl.u.RGBA[0];
  82. vi->borderColor.G = (float)cl.u.RGBA[1];
  83. vi->borderColor.B = (float)cl.u.RGBA[2];
  84. vi->borderColor.A =
  85. (float)atof(get_attribute_value("bordercoloralpha", vi, g));
  86. vi->bdVisible = atoi(get_attribute_value("bordervisible", vi, g));
  87. const char *buf = get_attribute_value("gridcolor", vi, g);
  88. colorxlate(buf, &cl, RGBA_DOUBLE);
  89. vi->gridColor.R = (float)cl.u.RGBA[0];
  90. vi->gridColor.G = (float)cl.u.RGBA[1];
  91. vi->gridColor.B = (float)cl.u.RGBA[2];
  92. vi->gridColor.A =
  93. (float) atof(get_attribute_value("gridcoloralpha", vi, g));
  94. vi->gridSize = (float)atof(buf = get_attribute_value("gridsize", vi, g));
  95. vi->gridVisible = atoi(get_attribute_value("gridvisible", vi, g));
  96. //background color , default white
  97. colorxlate(get_attribute_value("bgcolor", vi, g), &cl, RGBA_DOUBLE);
  98. vi->bgColor.R = (float)cl.u.RGBA[0];
  99. vi->bgColor.G = (float)cl.u.RGBA[1];
  100. vi->bgColor.B = (float)cl.u.RGBA[2];
  101. vi->bgColor.A = 1.0f;
  102. //selected nodes are drawn with this color
  103. colorxlate(get_attribute_value("selectednodecolor", vi, g), &cl,
  104. RGBA_DOUBLE);
  105. vi->selectedNodeColor.R = (float)cl.u.RGBA[0];
  106. vi->selectedNodeColor.G = (float)cl.u.RGBA[1];
  107. vi->selectedNodeColor.B = (float)cl.u.RGBA[2];
  108. vi->selectedNodeColor.A = (float)
  109. atof(get_attribute_value("selectednodecoloralpha", vi, g));
  110. vi->defaultnodealpha = (float)
  111. atof(get_attribute_value("defaultnodealpha", vi, g));
  112. /*default line width */
  113. vi->LineWidth =
  114. (float) atof(get_attribute_value("defaultlinewidth", vi, g));
  115. vi->drawnodes = atoi(get_attribute_value("drawnodes", vi, g));
  116. vi->drawedges = atoi(get_attribute_value("drawedges", vi, g));
  117. vi->drawnodelabels=atoi(get_attribute_value("labelshownodes", vi, g));
  118. vi->drawedgelabels=atoi(get_attribute_value("labelshowedges", vi, g));
  119. vi->nodeScale=atof(get_attribute_value("nodesize", vi, g))*.30;
  120. vi->glutfont =
  121. get_glut_font(atoi(get_attribute_value("labelglutfont", vi, g)));
  122. colorxlate(get_attribute_value("nodelabelcolor", vi, g), &cl,
  123. RGBA_DOUBLE);
  124. vi->nodelabelcolor.R = (float)cl.u.RGBA[0];
  125. vi->nodelabelcolor.G = (float)cl.u.RGBA[1];
  126. vi->nodelabelcolor.B = (float)cl.u.RGBA[2];
  127. vi->nodelabelcolor.A =
  128. (float) atof(get_attribute_value("defaultnodealpha", vi, g));
  129. colorxlate(get_attribute_value("edgelabelcolor", vi, g), &cl,
  130. RGBA_DOUBLE);
  131. vi->edgelabelcolor.R = (float)cl.u.RGBA[0];
  132. vi->edgelabelcolor.G = (float)cl.u.RGBA[1];
  133. vi->edgelabelcolor.B = (float)cl.u.RGBA[2];
  134. vi->edgelabelcolor.A =
  135. (float) atof(get_attribute_value("defaultedgealpha", vi, g));
  136. vi->labelnumberofnodes =
  137. atof(get_attribute_value("labelnumberofnodes", vi, g));
  138. vi->labelshownodes = atoi(get_attribute_value("labelshownodes", vi, g));
  139. vi->labelshowedges = atoi(get_attribute_value("labelshowedges", vi, g));
  140. vi->colschms =
  141. create_color_theme(atoi
  142. (get_attribute_value("colortheme", vi, g)));
  143. if (vi->graphCount > 0)
  144. glClearColor(vi->bgColor.R, vi->bgColor.G, vi->bgColor.B, vi->bgColor.A); //background color
  145. }
  146. static gboolean gl_main_expose(void *data) {
  147. (void)data;
  148. if (view->activeGraph >= 0) {
  149. if (view->Topview->fisheyeParams.animate == 1)
  150. expose_event(view->drawing_area, NULL, NULL);
  151. return 1;
  152. }
  153. return 1;
  154. }
  155. static void get_data_dir(void)
  156. {
  157. free(view->template_file);
  158. view->template_file = smyrnaPath("template.dot");
  159. }
  160. static void clear_color_theme(colorschemaset *cs) {
  161. free(cs->s);
  162. *cs = (colorschemaset){0};
  163. }
  164. void init_viewport(ViewInfo *vi) {
  165. FILE *input_file = NULL;
  166. FILE *input_file2 = NULL;
  167. get_data_dir();
  168. input_file = fopen(vi->template_file, "rb");
  169. if (!input_file) {
  170. fprintf(stderr,
  171. "default attributes template graph file \"%s\" not found\n",
  172. vi->template_file);
  173. graphviz_exit(-1);
  174. }
  175. vi->systemGraphs.def_attrs = agread(input_file, NULL);
  176. fclose (input_file);
  177. if (!vi->systemGraphs.def_attrs) {
  178. fprintf(stderr,
  179. "could not load default attributes template graph file \"%s\"\n",
  180. vi->template_file);
  181. graphviz_exit(-1);
  182. }
  183. {
  184. char *path = smyrnaPath("attr_widgets.dot");
  185. input_file2 = fopen(path, "rb");
  186. free(path);
  187. }
  188. if (!input_file2) {
  189. char *attrwidgets = smyrnaPath("attr_widgets.dot");
  190. fprintf(stderr, "default attributes template graph file \"%s\" not found\n", attrwidgets);
  191. free(attrwidgets);
  192. graphviz_exit(-1);
  193. }
  194. vi->systemGraphs.attrs_widgets = agread(input_file2, NULL);
  195. fclose (input_file2);
  196. if (!vi->systemGraphs.attrs_widgets) {
  197. char *attrwidgets = smyrnaPath("attr_widgets.dot");
  198. fprintf(stderr,"could not load default attribute widgets graph file \"%s\"\n", attrwidgets);
  199. free(attrwidgets);
  200. graphviz_exit(-1);
  201. }
  202. //init graphs
  203. vi->g = NULL; //no graph, gl screen should check it
  204. vi->graphCount = 0; //and disable interactivity if count is zero
  205. vi->bdxLeft = 0;
  206. vi->bdxRight = 500;
  207. vi->bdyBottom = 0;
  208. vi->bdyTop = 500;
  209. vi->borderColor.R = 1;
  210. vi->borderColor.G = 0;
  211. vi->borderColor.B = 0;
  212. vi->borderColor.A = 1;
  213. vi->bdVisible = 1; //show borders red
  214. vi->gridSize = 10;
  215. vi->gridColor.R = 0.5;
  216. vi->gridColor.G = 0.5;
  217. vi->gridColor.B = 0.5;
  218. vi->gridColor.A = 1;
  219. vi->gridVisible = 0; //show grids in light gray
  220. //mouse mode=pan
  221. //pen color
  222. vi->penColor.R = 0;
  223. vi->penColor.G = 0;
  224. vi->penColor.B = 0;
  225. vi->penColor.A = 1;
  226. vi->fillColor.R = 1;
  227. vi->fillColor.G = 0;
  228. vi->fillColor.B = 0;
  229. vi->fillColor.A = 1;
  230. //background color , default white
  231. vi->bgColor.R = 1;
  232. vi->bgColor.G = 1;
  233. vi->bgColor.B = 1;
  234. vi->bgColor.A = 1;
  235. //selected objets are drawn with this color
  236. vi->selectedNodeColor.R = 1;
  237. vi->selectedNodeColor.G = 0;
  238. vi->selectedNodeColor.B = 0;
  239. vi->selectedNodeColor.A = 1;
  240. //default line width;
  241. vi->LineWidth = 1;
  242. //default view settings, camera is not active
  243. vi->panx = 0;
  244. vi->pany = 0;
  245. vi->panz = 0;
  246. vi->zoom = -20;
  247. vi->mouse.down = 0;
  248. vi->activeGraph = -1;
  249. vi->Topview = gv_alloc(sizeof(topview));
  250. vi->Topview->fisheyeParams.fs = 0;
  251. vi->Topview->xDot=NULL;
  252. /* init topfish parameters */
  253. vi->Topview->fisheyeParams.level.num_fine_nodes = 10;
  254. vi->Topview->fisheyeParams.level.coarsening_rate = 2.5;
  255. vi->Topview->fisheyeParams.hier.dist2_limit = 1;
  256. vi->Topview->fisheyeParams.repos.width = (int)(vi->bdxRight - vi->bdxLeft);
  257. vi->Topview->fisheyeParams.repos.height = (int)(vi->bdyTop - vi->bdyBottom);
  258. vi->Topview->fisheyeParams.repos.distortion = 1.0;
  259. /*create timer */
  260. vi->timer = g_timer_new();
  261. vi->timer2 = g_timer_new();
  262. vi->timer3 = g_timer_new();
  263. g_timer_stop(vi->timer);
  264. vi->active_frame = 0;
  265. vi->total_frames = 1500;
  266. /*add a call back to the main() */
  267. g_timeout_add_full(G_PRIORITY_DEFAULT, 100u, gl_main_expose, NULL, NULL);
  268. vi->cameras = NULL;
  269. vi->camera_count = 0;
  270. vi->active_camera = SIZE_MAX;
  271. set_viewport_settings_from_template(vi, vi->systemGraphs.def_attrs);
  272. vi->Topview->Graphdata.GraphFileName = NULL;
  273. clear_color_theme(&vi->colschms);
  274. vi->arcball = gv_alloc(sizeof(ArcBall_t));
  275. load_mouse_actions(vi);
  276. if(vi->guiMode!=GUI_FULLSCREEN)
  277. vi->guiMode=GUI_WINDOWED;
  278. /*create glcomp menu system */
  279. vi->widgets = glcreate_gl_topview_menu();
  280. }
  281. /* update_graph_params:
  282. * adds gledit params
  283. * assumes custom_graph_data has been attached to the graph.
  284. */
  285. static void update_graph_params(Agraph_t * graph)
  286. {
  287. agattr(graph, AGRAPH, "GraphFileName",
  288. view->Topview->Graphdata.GraphFileName);
  289. }
  290. static Agraph_t *loadGraph(char *filename)
  291. {
  292. Agraph_t *g;
  293. FILE *input_file;
  294. if (!(input_file = fopen(filename, "r"))) {
  295. g_print("Cannot open %s\n", filename);
  296. return 0;
  297. }
  298. g = agread(input_file, NULL);
  299. fclose (input_file);
  300. if (!g) {
  301. g_print("Cannot read graph in %s\n", filename);
  302. return 0;
  303. }
  304. /* If no position info, run layout with -Txdot
  305. */
  306. if (!agattr(g, AGNODE, "pos", NULL)) {
  307. g_print("There is no position info in graph %s in %s\n", agnameof(g), filename);
  308. agclose (g);
  309. return 0;
  310. }
  311. view->Topview->Graphdata.GraphFileName = gv_strdup(filename);
  312. return g;
  313. }
  314. /* add_graph_to_viewport_from_file:
  315. * returns 1 if successful else 0
  316. */
  317. int add_graph_to_viewport_from_file(char *fileName)
  318. {
  319. Agraph_t *graph = loadGraph(fileName);
  320. return add_graph_to_viewport(graph, fileName);
  321. }
  322. /* updateRecord:
  323. * Update fields which may be added dynamically.
  324. */
  325. void updateRecord (Agraph_t* g)
  326. {
  327. GN_size(g) = agattr (g, AGNODE, "size", 0);
  328. GN_visible(g) = agattr (g, AGNODE, "visible", 0);
  329. GN_selected(g) = agattr (g, AGNODE, "selected", 0);
  330. GN_labelattribute(g) = agattr (g, AGNODE, "nodelabelattribute", 0);
  331. GE_pos(g)=agattr(g,AGEDGE,"pos",0);
  332. GE_visible(g) = agattr (g, AGEDGE, "visible", 0);
  333. GE_selected(g) = agattr (g, AGEDGE, "selected", 0);
  334. GE_labelattribute(g) = agattr (g, AGEDGE, "edgelabelattribute", 0);
  335. }
  336. /* graphRecord:
  337. * add graphRec to graph if necessary.
  338. * update fields of graphRec.
  339. * We assume the graph has attributes nodelabelattribute, edgelabelattribute,
  340. * nodelabelcolor and edgelabelcolor from template.dot.
  341. * We assume nodes have pos attributes.
  342. * Only size, visible, selected and edge pos may or may not be defined.
  343. */
  344. static void
  345. graphRecord (Agraph_t* g)
  346. {
  347. agbindrec(g, "graphRec", sizeof(graphRec), true);
  348. GG_nodelabelcolor(g) = agattr (g, AGRAPH, "nodelabelcolor", 0);
  349. GG_edgelabelcolor(g) = agattr (g, AGRAPH, "edgelabelcolor", 0);
  350. GG_labelattribute(g) = agattr (g, AGRAPH, "nodelabelattribute", 0);
  351. GG_elabelattribute(g) = agattr (g, AGRAPH, "edgelabelattribute", 0);
  352. GN_pos(g) = agattr (g, AGNODE, "pos", 0);
  353. updateRecord (g);
  354. }
  355. void refreshViewport(void)
  356. {
  357. Agraph_t *graph = view->g[view->activeGraph];
  358. load_settings_from_graph();
  359. if(view->guiMode!=GUI_FULLSCREEN)
  360. update_graph_from_settings(graph);
  361. set_viewport_settings_from_template(view, graph);
  362. graphRecord(graph);
  363. initSmGraph(graph,view->Topview);
  364. expose_event(view->drawing_area, NULL, NULL);
  365. }
  366. static void activate(int id)
  367. {
  368. view->activeGraph = id;
  369. refreshViewport();
  370. }
  371. int add_graph_to_viewport(Agraph_t * graph, char *id)
  372. {
  373. if (graph) {
  374. view->g = gv_recalloc(view->g, view->graphCount, view->graphCount + 1,
  375. sizeof(Agraph_t*));
  376. view->graphCount = view->graphCount + 1;
  377. view->g[view->graphCount - 1] = graph;
  378. gtk_combo_box_append_text(view->graphComboBox, id);
  379. assert(view->graphCount <= INT_MAX);
  380. gtk_combo_box_set_active(view->graphComboBox, (int)view->graphCount - 1);
  381. activate((int)view->graphCount - 1);
  382. return 1;
  383. } else {
  384. return 0;
  385. }
  386. }
  387. void switch_graph(int graphId)
  388. {
  389. if (graphId < 0 || (size_t)graphId >= view->graphCount)
  390. return; /*wrong entry */
  391. else
  392. activate(graphId);
  393. }
  394. /* save_graph_with_file_name:
  395. * saves graph with file name; if file name is NULL save as is
  396. */
  397. int save_graph_with_file_name(Agraph_t * graph, char *fileName)
  398. {
  399. int ret;
  400. FILE *output_file;
  401. update_graph_params(graph);
  402. if (fileName)
  403. output_file = fopen(fileName, "w");
  404. else if (view->Topview->Graphdata.GraphFileName)
  405. output_file = fopen(view->Topview->Graphdata.GraphFileName, "w");
  406. else {
  407. g_print("there is no file name to save! Programmer error\n");
  408. return 0;
  409. }
  410. if (output_file == NULL) {
  411. g_print("Cannot create file \n");
  412. return 0;
  413. }
  414. ret = agwrite(graph, output_file);
  415. fclose (output_file);
  416. if (ret) {
  417. g_print("%s successfully saved \n", fileName);
  418. return 1;
  419. }
  420. return 0;
  421. }
  422. /* save_graph:
  423. * save without prompt
  424. */
  425. int save_graph(void)
  426. {
  427. //check if there is an active graph
  428. if (view->activeGraph > -1)
  429. {
  430. //check if active graph has a file name
  431. if (view->Topview->Graphdata.GraphFileName) {
  432. return save_graph_with_file_name(view->g[view->activeGraph],
  433. view->Topview->Graphdata.
  434. GraphFileName);
  435. } else
  436. return save_as_graph();
  437. }
  438. return 1;
  439. }
  440. /* save_as_graph:
  441. * save with prompt
  442. */
  443. int save_as_graph(void)
  444. {
  445. //check if there is an active graph
  446. if (view->activeGraph > -1) {
  447. GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
  448. NULL,
  449. GTK_FILE_CHOOSER_ACTION_SAVE,
  450. GTK_STOCK_CANCEL,
  451. GTK_RESPONSE_CANCEL,
  452. GTK_STOCK_SAVE,
  453. GTK_RESPONSE_ACCEPT, NULL);
  454. gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
  455. (dialog), TRUE);
  456. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  457. char *filename =
  458. gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  459. save_graph_with_file_name(view->g[view->activeGraph],
  460. filename);
  461. g_free(filename);
  462. gtk_widget_destroy(dialog);
  463. return 1;
  464. } else {
  465. gtk_widget_destroy(dialog);
  466. return 0;
  467. }
  468. }
  469. return 0;
  470. }
  471. void glexpose(void)
  472. {
  473. expose_event(view->drawing_area, NULL, NULL);
  474. }
  475. static float interpol(float minv, float maxv, float minc, float maxc, float x)
  476. {
  477. return (x - minv) * (maxc - minc) / (maxv - minv) + minc;
  478. }
  479. void getcolorfromschema(const colorschemaset sc, float l, float maxl,
  480. glCompColor *c) {
  481. size_t ind;
  482. float percl = l / maxl;
  483. // For smooth schemas, s[0].perc = 0, so we start with ind=1
  484. for (ind = 1; ind + 1 < sc.schemacount; ind++) {
  485. if (percl < sc.s[ind].perc)
  486. break;
  487. }
  488. c->R = interpol(sc.s[ind - 1].perc, sc.s[ind].perc, sc.s[ind - 1].c.R,
  489. sc.s[ind].c.R, percl);
  490. c->G = interpol(sc.s[ind - 1].perc, sc.s[ind].perc, sc.s[ind - 1].c.G,
  491. sc.s[ind].c.G, percl);
  492. c->B = interpol(sc.s[ind - 1].perc, sc.s[ind].perc, sc.s[ind - 1].c.B,
  493. sc.s[ind].c.B, percl);
  494. c->A = 1;
  495. }
  496. /* set_color_theme_color:
  497. * Convert colors as strings to RGB
  498. */
  499. static void set_color_theme_color(colorschemaset * sc, char **colorstr)
  500. {
  501. const size_t colorcnt = sc->schemacount;
  502. gvcolor_t cl;
  503. float av_perc;
  504. av_perc = 1.0 / (float) (colorcnt-1);
  505. for (size_t ind = 0; ind < colorcnt; ind++) {
  506. colorxlate(colorstr[ind], &cl, RGBA_DOUBLE);
  507. sc->s[ind].c.R = cl.u.RGBA[0];
  508. sc->s[ind].c.G = cl.u.RGBA[1];
  509. sc->s[ind].c.B = cl.u.RGBA[2];
  510. sc->s[ind].c.A = cl.u.RGBA[3];
  511. sc->s[ind].perc = (float)ind * av_perc;
  512. }
  513. }
  514. static char *deep_blue[] = {
  515. "#C8CBED", "#9297D3", "#0000FF", "#2C2E41"
  516. };
  517. static char *pastel[] = {
  518. "#EBBE29", "#D58C4A", "#74AE09", "#893C49"
  519. };
  520. static char *magma[] = {
  521. "#E0061E", "#F0F143", "#95192B", "#EB712F"
  522. };
  523. static char *rain_forest[] = {
  524. "#1E6A10", "#2ABE0E", "#AEDD39", "#5EE88B"
  525. };
  526. #define CSZ(x) (sizeof(x)/sizeof(char*))
  527. typedef struct {
  528. size_t cnt;
  529. char **colors;
  530. } colordata;
  531. static colordata palette[] = {
  532. {CSZ(deep_blue), deep_blue},
  533. {CSZ(pastel), pastel},
  534. {CSZ(magma), magma},
  535. {CSZ(rain_forest), rain_forest},
  536. };
  537. #define NUM_SCHEMES (sizeof(palette)/sizeof(colordata))
  538. static colorschemaset create_color_theme(int themeid) {
  539. if (themeid < 0 || (int)NUM_SCHEMES <= themeid) {
  540. fprintf (stderr, "colorschemaset: illegal themeid %d\n", themeid);
  541. return view->colschms;
  542. }
  543. colorschemaset s = {0};
  544. clear_color_theme(&view->colschms);
  545. s.schemacount = palette[themeid].cnt;
  546. s.s = gv_calloc(s.schemacount, sizeof(colorschema));
  547. set_color_theme_color(&s, palette[themeid].colors);
  548. return s;
  549. }