gui_frame.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924
  1. /*
  2. * gui_frame.c - GUI, frame window
  3. *
  4. * Written 2009, 2010, 2012, 2015 by Werner Almesberger
  5. * Copyright 2009, 2010, 2012, 2015 by Werner Almesberger
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. */
  12. #include <string.h>
  13. #include <gtk/gtk.h>
  14. #include "util.h"
  15. #include "error.h"
  16. #include "dump.h"
  17. #include "inst.h"
  18. #include "obj.h"
  19. #include "delete.h"
  20. #include "unparse.h"
  21. #include "gui_util.h"
  22. #include "gui_style.h"
  23. #include "gui_status.h"
  24. #include "gui_tool.h"
  25. #include "gui_canvas.h"
  26. #include "gui.h"
  27. #include "gui_frame_drag.h"
  28. #include "gui_frame.h"
  29. enum sidebar sidebar = sidebar_var;
  30. /* ----- add elements, shared ---------------------------------------------- */
  31. /* @@@ merge with fpd.y */
  32. static void add_table(struct frame *frame, struct table **anchor)
  33. {
  34. struct table *table, **walk;
  35. table = zalloc_type(struct table);
  36. table->vars = zalloc_type(struct var);
  37. table->vars->name = unique("_");
  38. table->vars->frame = frame;
  39. table->vars->table = table;
  40. table->rows = zalloc_type(struct row);
  41. table->rows->table = table;
  42. table->rows->values = zalloc_type(struct value);
  43. table->rows->values->expr = parse_expr("0");
  44. table->rows->values->row = table->rows;
  45. table->active_row = table->rows;
  46. if (anchor) {
  47. table->next = *anchor;
  48. *anchor = table;
  49. } else {
  50. for (walk = &frame->tables; *walk; walk = &(*walk)->next);
  51. *walk = table;
  52. }
  53. change_world();
  54. }
  55. static void add_loop(struct frame *frame, struct loop **anchor)
  56. {
  57. struct loop *loop, **walk;
  58. loop = zalloc_type(struct loop);
  59. loop->var.name = unique("_");
  60. loop->var.frame = frame;
  61. loop->from.expr = parse_expr("0");
  62. loop->to.expr = parse_expr("0");
  63. if (anchor) {
  64. loop->next = *anchor;
  65. *anchor = loop;
  66. } else {
  67. loop->next = NULL;
  68. for (walk = &frame->loops; *walk; walk = &(*walk)->next);
  69. *walk = loop;
  70. }
  71. change_world();
  72. }
  73. /* ----- popup dispatcher -------------------------------------------------- */
  74. static void *popup_data;
  75. static void pop_up(GtkWidget *menu, GdkEventButton *event, void *data)
  76. {
  77. popup_data = data;
  78. gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
  79. event->button, event->time);
  80. }
  81. /* ----- popup: frame ------------------------------------------------------ */
  82. static GtkItemFactory *factory_frame;
  83. static GtkWidget *popup_frame_widget;
  84. static void popup_add_frame(void)
  85. {
  86. struct frame *parent = popup_data;
  87. struct frame *new;
  88. new = zalloc_type(struct frame);
  89. new->name = unique("_");
  90. new->next = parent->next;
  91. parent->next = new;
  92. change_world();
  93. }
  94. static void popup_del_frame(void)
  95. {
  96. struct frame *frame = popup_data;
  97. assert(frame != frames);
  98. delete_frame(frame);
  99. if (active_frame == frame)
  100. select_frame(frames);
  101. change_world();
  102. }
  103. static void popup_add_table(void)
  104. {
  105. add_table(popup_data, NULL);
  106. }
  107. static void popup_add_loop(void)
  108. {
  109. add_loop(popup_data, NULL);
  110. }
  111. static GtkItemFactoryEntry popup_frame_entries[] = {
  112. { "/Add frame", NULL, popup_add_frame,0, "<Item>" },
  113. { "/sep0", NULL, NULL, 0, "<Separator>" },
  114. { "/Add variable", NULL, popup_add_table,0, "<Item>" },
  115. { "/Add loop", NULL, popup_add_loop, 0, "<Item>" },
  116. { "/sep1", NULL, NULL, 0, "<Separator>" },
  117. { "/Delete frame", NULL, popup_del_frame,0, "<Item>" },
  118. { "/sep2", NULL, NULL, 0, "<Separator>" },
  119. { "/Close", NULL, NULL, 0, "<Item>" },
  120. { NULL }
  121. };
  122. static gboolean can_add_frame(void)
  123. {
  124. const struct frame *frame;
  125. for (frame = frames->next; frame; frame = frame->next)
  126. if (!strcmp(frame->name, "_"))
  127. return FALSE;
  128. return TRUE;
  129. }
  130. static gboolean can_add_var(const struct frame *frame)
  131. {
  132. const struct table *table;
  133. const struct var *var;
  134. const struct loop *loop;
  135. for (table = frame->tables; table; table = table->next)
  136. for (var = table->vars; var; var = var->next)
  137. if (!strcmp(var->name, "_"))
  138. return FALSE;
  139. for (loop = frame->loops; loop; loop = loop->next)
  140. if (!strcmp(loop->var.name, "_"))
  141. return FALSE;
  142. return TRUE;
  143. }
  144. static void enable_add_var(struct frame *frame, GtkItemFactory *factory)
  145. {
  146. gboolean add_var;
  147. add_var = can_add_var(frame);
  148. gtk_widget_set_sensitive(
  149. gtk_item_factory_get_item(factory, "/Add variable"), add_var);
  150. gtk_widget_set_sensitive(
  151. gtk_item_factory_get_item(factory, "/Add loop"), add_var);
  152. }
  153. static void pop_up_frame(struct frame *frame, GdkEventButton *event)
  154. {
  155. gtk_widget_set_sensitive(
  156. gtk_item_factory_get_item(factory_frame, "/Delete frame"),
  157. frame != frames);
  158. gtk_widget_set_sensitive(
  159. gtk_item_factory_get_item(factory_frame, "/Add frame"),
  160. can_add_frame());
  161. enable_add_var(frame, factory_frame);
  162. pop_up(popup_frame_widget, event, frame);
  163. }
  164. /* ----- popup: single variable -------------------------------------------- */
  165. static GtkItemFactory *factory_single_var;
  166. static GtkWidget *popup_single_var_widget;
  167. static void add_row_here(struct table *table, struct row **anchor)
  168. {
  169. struct row *row;
  170. const struct value *walk;
  171. struct value *value;
  172. row = zalloc_type(struct row);
  173. row->table = table;
  174. /* @@@ future: adjust type */
  175. for (walk = table->rows->values; walk; walk = walk->next) {
  176. value = zalloc_type(struct value);
  177. value->expr = parse_expr("0");
  178. value->row = row;
  179. value->next = row->values;
  180. row->values = value;
  181. }
  182. row->next = *anchor;
  183. *anchor = row;
  184. change_world();
  185. }
  186. static void add_column_here(struct table *table, struct var **anchor)
  187. {
  188. const struct var *walk;
  189. struct var *var;
  190. struct row *row;
  191. struct value *value;
  192. struct value **value_anchor;
  193. int n = 0, i;
  194. for (walk = table->vars; walk != *anchor; walk = walk->next)
  195. n++;
  196. var = zalloc_type(struct var);
  197. var->name = unique("_");
  198. var->frame = table->vars->frame;
  199. var->table = table;
  200. var->next = *anchor;
  201. *anchor = var;
  202. for (row = table->rows; row; row = row->next) {
  203. value_anchor = &row->values;
  204. for (i = 0; i != n; i++)
  205. value_anchor = &(*value_anchor)->next;
  206. value = zalloc_type(struct value);
  207. value->expr = parse_expr("0");
  208. value->row = row;
  209. value->next = *value_anchor;
  210. *value_anchor = value;
  211. }
  212. change_world();
  213. }
  214. static void popup_add_row(void)
  215. {
  216. struct var *var = popup_data;
  217. add_row_here(var->table, &var->table->rows);
  218. }
  219. static void popup_add_column(void)
  220. {
  221. struct var *var = popup_data;
  222. add_column_here(var->table, &var->next);
  223. }
  224. static void popup_del_table(void)
  225. {
  226. struct var *var = popup_data;
  227. delete_table(var->table);
  228. change_world();
  229. }
  230. static void popup_add_table_from_var(void)
  231. {
  232. struct var *var = popup_data;
  233. add_table(var->frame, &var->table->next);
  234. }
  235. static void popup_add_loop_from_var(void)
  236. {
  237. struct var *var = popup_data;
  238. add_loop(var->frame, NULL);
  239. }
  240. static GtkItemFactoryEntry popup_single_var_entries[] = {
  241. { "/Add row", NULL, popup_add_row, 0, "<Item>" },
  242. { "/Add column", NULL, popup_add_column, 0, "<Item>" },
  243. { "/sep1", NULL, NULL, 0, "<Separator>" },
  244. { "/Delete variable", NULL, popup_del_table,0, "<Item>" },
  245. { "/sep2", NULL, NULL, 0, "<Separator>" },
  246. { "/Add variable", NULL, popup_add_table_from_var,
  247. 0, "<Item>" },
  248. { "/Add loop", NULL, popup_add_loop_from_var,
  249. 0, "<Item>" },
  250. { "/sep3", NULL, NULL, 0, "<Separator>" },
  251. { "/Close", NULL, NULL, 0, "<Item>" },
  252. { NULL }
  253. };
  254. static void pop_up_single_var(struct var *var, GdkEventButton *event)
  255. {
  256. gtk_widget_set_sensitive(
  257. gtk_item_factory_get_item(factory_single_var, "/Add column"),
  258. can_add_var(var->frame));
  259. enable_add_var(var->frame, factory_single_var);
  260. pop_up(popup_single_var_widget, event, var);
  261. }
  262. /* ----- popup: table variable --------------------------------------------- */
  263. static GtkItemFactory *factory_table_var;
  264. static GtkWidget *popup_table_var_widget;
  265. static void popup_del_column(void)
  266. {
  267. struct var *var = popup_data;
  268. const struct var *walk;
  269. int n = 0;
  270. for (walk = var->table->vars; walk != var; walk = walk->next)
  271. n++;
  272. delete_column(var->table, n);
  273. change_world();
  274. }
  275. static GtkItemFactoryEntry popup_table_var_entries[] = {
  276. { "/Add row", NULL, popup_add_row, 0, "<Item>" },
  277. { "/Add column", NULL, popup_add_column, 0, "<Item>" },
  278. { "/sep1", NULL, NULL, 0, "<Separator>" },
  279. { "/Delete table", NULL, popup_del_table,0, "<Item>" },
  280. { "/Delete column", NULL, popup_del_column, 0, "<Item>" },
  281. { "/sep2", NULL, NULL, 0, "<Separator>" },
  282. { "/Add variable", NULL, popup_add_table_from_var,
  283. 0, "<Item>" },
  284. { "/Add loop", NULL, popup_add_loop_from_var,
  285. 0, "<Item>" },
  286. { "/sep3", NULL, NULL, 0, "<Separator>" },
  287. { "/Close", NULL, NULL, 0, "<Item>" },
  288. { NULL }
  289. };
  290. static void pop_up_table_var(struct var *var, GdkEventButton *event)
  291. {
  292. gtk_widget_set_sensitive(
  293. gtk_item_factory_get_item(factory_table_var, "/Delete column"),
  294. var->table->vars->next != NULL);
  295. gtk_widget_set_sensitive(
  296. gtk_item_factory_get_item(factory_table_var, "/Add column"),
  297. can_add_var(var->frame));
  298. enable_add_var(var->frame, factory_table_var);
  299. pop_up(popup_table_var_widget, event, var);
  300. }
  301. /* ----- popup: table value ------------------------------------------------ */
  302. static GtkItemFactory *factory_table_value;
  303. static GtkWidget *popup_table_value_widget;
  304. static void popup_add_column_by_value(void)
  305. {
  306. struct value *value = popup_data;
  307. const struct value *walk;
  308. struct table *table = value->row->table;
  309. struct var *var = table->vars;
  310. for (walk = value->row->values; walk != value; walk = walk->next)
  311. var = var->next;
  312. add_column_here(table, &var->next);
  313. }
  314. static void popup_add_row_by_value(void)
  315. {
  316. struct value *value = popup_data;
  317. add_row_here(value->row->table, &value->row->next);
  318. }
  319. static void popup_del_row(void)
  320. {
  321. struct value *value = popup_data;
  322. struct table *table = value->row->table;
  323. delete_row(value->row);
  324. if (table->active_row == value->row)
  325. table->active_row = table->rows;
  326. change_world();
  327. }
  328. static void popup_del_column_by_value(void)
  329. {
  330. struct value *value = popup_data;
  331. const struct value *walk;
  332. int n = 0;
  333. for (walk = value->row->values; walk != value; walk = walk->next)
  334. n++;
  335. delete_column(value->row->table, n);
  336. change_world();
  337. }
  338. static GtkItemFactoryEntry popup_table_value_entries[] = {
  339. { "/Add row", NULL, popup_add_row_by_value, 0, "<Item>" },
  340. { "/Add column", NULL, popup_add_column_by_value,
  341. 0, "<Item>" },
  342. { "/sep1", NULL, NULL, 0, "<Separator>" },
  343. { "/Delete row", NULL, popup_del_row, 0, "<Item>" },
  344. { "/Delete column", NULL, popup_del_column_by_value,
  345. 0, "<Item>" },
  346. { "/sep2", NULL, NULL, 0, "<Separator>" },
  347. { "/Close", NULL, NULL, 0, "<Item>" },
  348. { NULL }
  349. };
  350. static void pop_up_table_value(struct value *value, GdkEventButton *event)
  351. {
  352. gtk_widget_set_sensitive(
  353. gtk_item_factory_get_item(factory_table_value, "/Delete row"),
  354. value->row->table->rows->next != NULL);
  355. gtk_widget_set_sensitive(
  356. gtk_item_factory_get_item(factory_table_value, "/Delete column"),
  357. value->row->table->vars->next != NULL);
  358. pop_up(popup_table_value_widget, event, value);
  359. }
  360. /* ----- popup: loop ------------------------------------------------------- */
  361. static GtkItemFactory *factory_loop_var;
  362. static GtkWidget *popup_loop_var_widget;
  363. static void popup_del_loop(void)
  364. {
  365. struct loop *loop = popup_data;
  366. delete_loop(loop);
  367. change_world();
  368. }
  369. static void popup_add_table_from_loop(void)
  370. {
  371. struct loop *loop = popup_data;
  372. add_table(loop->var.frame, NULL);
  373. }
  374. static void popup_add_loop_from_loop(void)
  375. {
  376. struct loop *loop = popup_data;
  377. add_loop(loop->var.frame, &loop->next);
  378. }
  379. static GtkItemFactoryEntry popup_loop_var_entries[] = {
  380. { "/Delete loop", NULL, popup_del_loop, 0, "<Item>" },
  381. { "/sep1", NULL, NULL, 0, "<Separator>" },
  382. { "/Add variable", NULL, popup_add_table_from_loop,
  383. 0, "<Item>" },
  384. { "/Add loop", NULL, popup_add_loop_from_loop,
  385. 0, "<Item>" },
  386. { "/sep2", NULL, NULL, 0, "<Separator>" },
  387. { "/Close", NULL, NULL, 0, "<Item>" },
  388. { NULL }
  389. };
  390. static void pop_up_loop_var(struct loop *loop, GdkEventButton *event)
  391. {
  392. enable_add_var(loop->var.frame, factory_loop_var);
  393. pop_up(popup_loop_var_widget, event, loop);
  394. }
  395. /* ----- make popups ------------------------------------------------------- */
  396. static GtkWidget *make_popup(const char *name, GtkItemFactory **factory,
  397. GtkItemFactoryEntry *entries)
  398. {
  399. GtkWidget *popup;
  400. int n;
  401. n = 0;
  402. for (n = 0; entries[n].path; n++);
  403. *factory = gtk_item_factory_new(GTK_TYPE_MENU, name, NULL);
  404. gtk_item_factory_create_items(*factory, n, entries, NULL);
  405. popup = gtk_item_factory_get_widget(*factory, name);
  406. return popup;
  407. }
  408. void make_popups(void)
  409. {
  410. popup_frame_widget = make_popup("<FpedFramePopUp>",
  411. &factory_frame, popup_frame_entries);
  412. popup_single_var_widget = make_popup("<FpedSingleVarPopUp>",
  413. &factory_single_var, popup_single_var_entries);
  414. popup_table_var_widget = make_popup("<FpedTableVarPopUp>",
  415. &factory_table_var, popup_table_var_entries);
  416. popup_table_value_widget = make_popup("<FpedTableValusPopUp>",
  417. &factory_table_value, popup_table_value_entries);
  418. popup_loop_var_widget = make_popup("<FpedLoopVarPopUp>",
  419. &factory_loop_var, popup_loop_var_entries);
  420. }
  421. /* ----- variable list ----------------------------------------------------- */
  422. static void add_sep(GtkWidget *box, int size)
  423. {
  424. GtkWidget *sep;
  425. GdkColor black = { 0, 0, 0, 0 };
  426. sep = gtk_drawing_area_new();
  427. gtk_box_pack_start(GTK_BOX(box), sep, FALSE, TRUE, size);
  428. gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
  429. }
  430. /* ----- variable name editor ---------------------------------------------- */
  431. static int find_var_in_frame(const struct frame *frame, const char *name,
  432. const struct var *self)
  433. {
  434. const struct table *table;
  435. const struct loop *loop;
  436. const struct var *var;
  437. for (table = frame->tables; table; table = table->next)
  438. for (var = table->vars; var; var = var->next)
  439. if (var != self && !var->key &&
  440. !strcmp(var->name, name))
  441. return 1;
  442. for (loop = frame->loops; loop; loop = loop->next)
  443. if (&loop->var != self && !strcmp(loop->var.name, name))
  444. return 1;
  445. return 0;
  446. }
  447. static int validate_var_name(const char *s, void *ctx)
  448. {
  449. struct var *var = ctx;
  450. if (!is_id(s))
  451. return 0;
  452. if (var->key)
  453. return 1;
  454. return !find_var_in_frame(var->frame, s, var);
  455. }
  456. static void unselect_var(void *data)
  457. {
  458. struct var *var = data;
  459. label_in_box_bg(var->widget, COLOR_VAR_PASSIVE);
  460. }
  461. static void show_value(const struct expr *expr, const struct frame *frame)
  462. {
  463. const char *value_string;
  464. struct num value;
  465. status_set_type_x(NULL, "value =");
  466. value_string = eval_str(expr, frame);
  467. if (value_string) {
  468. status_set_x(NULL, "\"%s\"", value_string);
  469. } else {
  470. value = eval_num(expr, frame);
  471. if (is_undef(value))
  472. status_set_x(NULL, "undefined");
  473. else
  474. status_set_x(NULL, "%lg%s", value.n, str_unit(value));
  475. }
  476. }
  477. static void show_var_value(const struct var *var, const struct frame *frame)
  478. {
  479. const struct var *walk;
  480. const struct value *value;
  481. if (!var->table)
  482. return;
  483. value = var->table->active_row->values;
  484. for (walk = var->table->vars; walk != var; walk = walk->next)
  485. value = value->next;
  486. show_value(value->expr, frame);
  487. }
  488. static void edit_var(struct var *var,
  489. void (*set_values)(void *user, const struct value *values, int n_values),
  490. void *user, int max_values)
  491. {
  492. inst_select_outside(var, unselect_var);
  493. label_in_box_bg(var->widget, COLOR_VAR_EDITING);
  494. status_set_type_entry(NULL, "name =");
  495. status_set_name("Variable name", "%s", var->name);
  496. show_var_value(var, var->frame);
  497. edit_nothing();
  498. edit_var_type(var);
  499. edit_unique_with_values(&var->name, validate_var_name, var,
  500. set_values, user, max_values,
  501. "Variable name. "
  502. "Shortcut:<b><i>name</i>=<i>value</i>,<i>...</i> </b>");
  503. }
  504. static void set_col_values(void *user, const struct value *values,
  505. int n_values);
  506. void reselect_var(struct var *var)
  507. {
  508. edit_var(var, set_col_values, var, -1);
  509. }
  510. /* ----- value editor ------------------------------------------------------ */
  511. static void unselect_value(void *data)
  512. {
  513. struct value *value = data;
  514. /*
  515. * This condition is a little cryptic. Here is what it does:
  516. *
  517. * IF table/assignment (not loop)
  518. * AND the current row is the active (selected) row
  519. * AND it's an assignment (not a table).
  520. *
  521. * We need the last condition because the expressions of assignments
  522. * are drawn with COLOR_EXPR_PASSIVE. (See build_assignment.)
  523. */
  524. label_in_box_bg(value->widget,
  525. value->row && value->row->table->active_row == value->row &&
  526. (value->row->table->rows->next || value->row->table->vars->next) ?
  527. COLOR_CHOICE_SELECTED : COLOR_EXPR_PASSIVE);
  528. }
  529. static void edit_value(struct value *value, const struct frame *frame)
  530. {
  531. inst_select_outside(value, unselect_value);
  532. label_in_box_bg(value->widget, COLOR_EXPR_EDITING);
  533. show_value(value->expr, frame);
  534. edit_nothing();
  535. edit_expr(&value->expr, "Value");
  536. }
  537. static void edit_value_list(struct value *value, const struct frame *frame,
  538. void (*set_values)(void *user, const struct value *values, int n_values),
  539. void *user)
  540. {
  541. inst_select_outside(value, unselect_value);
  542. label_in_box_bg(value->widget, COLOR_EXPR_EDITING);
  543. show_value(value->expr, frame);
  544. edit_nothing();
  545. edit_expr_list(value->expr, set_values, user, "Value(s)");
  546. }
  547. /* ----- activator --------------------------------------------------------- */
  548. static GtkWidget *add_activator(GtkWidget *hbox, int active,
  549. gboolean (*cb)(GtkWidget *widget, GdkEventButton *event, gpointer data),
  550. gpointer user, const char *tooltip, const char *fmt, ...)
  551. {
  552. GtkWidget *label;
  553. va_list ap;
  554. char buf[100];
  555. va_start(ap, fmt);
  556. vsprintf(buf, fmt, ap);
  557. va_end(ap);
  558. label = label_in_box_new(buf, tooltip);
  559. gtk_misc_set_padding(GTK_MISC(label), 2, 2);
  560. gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  561. label_in_box_bg(label,
  562. active ? COLOR_CHOICE_SELECTED : COLOR_CHOICE_UNSELECTED);
  563. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(label),
  564. FALSE, FALSE, 2);
  565. g_signal_connect(G_OBJECT(box_of_label(label)),
  566. "button_press_event", G_CALLBACK(cb), user);
  567. return label;
  568. }
  569. /* ----- assignments ------------------------------------------------------- */
  570. static void set_col_values(void *user, const struct value *values,
  571. int n_values)
  572. {
  573. struct var *var = user;
  574. struct table *table = var->table;
  575. struct value *value;
  576. const struct var *walk;
  577. struct row **row;
  578. row = &table->rows;
  579. while (values) {
  580. if (!*row)
  581. add_row_here(table, row);
  582. value = (*row)->values;
  583. for (walk = table->vars; walk != var; walk = walk->next)
  584. value = value->next;
  585. free_expr(value->expr);
  586. value->expr = values->expr;
  587. values = values->next;
  588. row = &(*row)->next;
  589. }
  590. }
  591. static gboolean assignment_var_select_event(GtkWidget *widget,
  592. GdkEventButton *event, gpointer data)
  593. {
  594. struct var *var = data;
  595. switch (event->button) {
  596. case 1:
  597. edit_var(var, set_col_values, var, -1);
  598. break;
  599. case 3:
  600. pop_up_single_var(var, event);
  601. break;
  602. }
  603. return TRUE;
  604. }
  605. static gboolean assignment_value_select_event(GtkWidget *widget,
  606. GdkEventButton *event, gpointer data)
  607. {
  608. struct value *value = data;
  609. switch (event->button) {
  610. case 1:
  611. edit_nothing();
  612. edit_value(value, value->row->table->vars->frame);
  613. break;
  614. }
  615. return TRUE;
  616. }
  617. /*
  618. * In tables, expressions in the active row have a COLOR_CHOICE_SELECTED
  619. * background. While expressions in assignments are technically on the active
  620. * (and only) row, we use COLOR_VAR_PASSIVE for better readability.
  621. */
  622. static void build_assignment(GtkWidget *vbox, struct frame *frame,
  623. struct table *table)
  624. {
  625. GtkWidget *hbox, *field;
  626. char *name, *expr;
  627. if (!table->vars || table->vars->next)
  628. return;
  629. if (!table->rows || table->rows->next)
  630. return;
  631. hbox = gtk_hbox_new(FALSE, 0);
  632. gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  633. name = stralloc_printf("%s%s", table->vars->key ? "?" : "",
  634. table->vars->name);
  635. field = label_in_box_new(name, "Variable name. Click to edit.");
  636. free(name);
  637. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
  638. label_in_box_bg(field, COLOR_VAR_PASSIVE);
  639. table->vars->widget = field;
  640. g_signal_connect(G_OBJECT(box_of_label(field)),
  641. "button_press_event",
  642. G_CALLBACK(assignment_var_select_event), table->vars);
  643. gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
  644. FALSE, FALSE, 0);
  645. expr = unparse(table->rows->values->expr);
  646. field = label_in_box_new(expr, "Variable value. Click to edit.");
  647. free(expr);
  648. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
  649. label_in_box_bg(field, COLOR_EXPR_PASSIVE);
  650. table->rows->values->widget = field;
  651. g_signal_connect(G_OBJECT(box_of_label(field)),
  652. "button_press_event",
  653. G_CALLBACK(assignment_value_select_event), table->rows->values);
  654. }
  655. /* ----- tables ------------------------------------------------------------ */
  656. static void select_row(struct row *row)
  657. {
  658. struct table *table = row->table;
  659. struct value *value;
  660. for (value = table->active_row->values; value; value = value->next)
  661. label_in_box_bg(value->widget, COLOR_ROW_UNSELECTED);
  662. table->active_row = row;
  663. for (value = table->active_row->values; value; value = value->next)
  664. label_in_box_bg(value->widget, COLOR_ROW_SELECTED);
  665. }
  666. static void set_row_values(void *user, const struct value *values,
  667. int n_values)
  668. {
  669. struct value *value = user;
  670. struct row *row = value->row;
  671. struct table *table = row->table;
  672. struct var **var;
  673. const struct value *walk;
  674. int first = 1;
  675. var = &table->vars;
  676. for (walk = row->values; walk != value; walk = walk->next)
  677. var = &(*var)->next;
  678. while (values) {
  679. if (!*var)
  680. add_column_here(table, var);
  681. if (first)
  682. first = 0;
  683. else
  684. value = value->next;
  685. free_expr(value->expr);
  686. value->expr = values->expr;
  687. values = values->next;
  688. var = &(*var)->next;
  689. }
  690. }
  691. static gboolean table_var_press_event(GtkWidget *widget,
  692. GdkEventButton *event, gpointer data)
  693. {
  694. struct var *var = data;
  695. switch (event->button) {
  696. case 3:
  697. pop_up_table_var(var, event);
  698. return TRUE;
  699. }
  700. return FALSE;
  701. }
  702. static gboolean table_var_release_event(GtkWidget *widget,
  703. GdkEventButton *event, gpointer data)
  704. {
  705. struct var *var = data;
  706. switch (event->button) {
  707. case 1:
  708. if (is_dragging(var))
  709. return FALSE;
  710. edit_var(var, set_col_values, var, -1);
  711. return TRUE;
  712. }
  713. return FALSE;
  714. }
  715. static gboolean table_value_press_event(GtkWidget *widget,
  716. GdkEventButton *event, gpointer data)
  717. {
  718. struct value *value = data;
  719. switch (event->button) {
  720. case 3:
  721. pop_up_table_value(value, event);
  722. return TRUE;
  723. }
  724. return FALSE;
  725. }
  726. static gboolean table_value_release_event(GtkWidget *widget,
  727. GdkEventButton *event, gpointer data)
  728. {
  729. struct value *value = data;
  730. switch (event->button) {
  731. case 1:
  732. if (is_dragging(value))
  733. return FALSE;
  734. if (!value->row ||
  735. value->row->table->active_row == value->row) {
  736. edit_nothing();
  737. edit_value_list(value, value->row->table->vars->frame,
  738. set_row_values, value);
  739. } else {
  740. select_row(value->row);
  741. change_world();
  742. }
  743. return TRUE;
  744. }
  745. return FALSE;
  746. }
  747. static gboolean table_scroll_event(GtkWidget *widget, GdkEventScroll *event,
  748. gpointer data)
  749. {
  750. struct table *table = data;
  751. struct row *row, *last;
  752. switch (event->direction) {
  753. case GDK_SCROLL_UP:
  754. last = NULL;
  755. for (row = table->rows;
  756. row && (!last || row != table->active_row); row = row->next)
  757. last = row;
  758. table->active_row = last;
  759. change_world();
  760. break;
  761. case GDK_SCROLL_DOWN:
  762. table->active_row = table->active_row->next;
  763. if (!table->active_row)
  764. table->active_row = table->rows;
  765. change_world();
  766. break;
  767. default:
  768. /* ignore */;
  769. }
  770. return TRUE;
  771. }
  772. /* @@@ this function is too long */
  773. static void build_table(GtkWidget *vbox, struct frame *frame,
  774. struct table *table, int wrap_width)
  775. {
  776. GtkWidget *tab, *field;
  777. GtkWidget *evbox, *align, *sep;
  778. struct var *var;
  779. struct row *row;
  780. struct value *value;
  781. int n_vars = 0, n_rows = 0;
  782. int n_var, n_row, pos;
  783. char *name, *expr;
  784. GdkColor color;
  785. for (var = table->vars; var; var = var->next)
  786. n_vars++;
  787. for (row = table->rows; row; row = row->next)
  788. n_rows++;
  789. if (n_vars == 1 && n_rows == 1)
  790. return;
  791. var = table->vars;
  792. n_var = 0;
  793. n_vars = 0;
  794. while (var) {
  795. if (n_vars) {
  796. gtk_table_resize(GTK_TABLE(tab), n_rows, n_vars+1);
  797. } else {
  798. evbox = gtk_event_box_new();
  799. align = gtk_alignment_new(0, 0, 0, 0);
  800. gtk_container_add(GTK_CONTAINER(align), evbox);
  801. gtk_box_pack_start(GTK_BOX(vbox), align,
  802. FALSE, FALSE, 0);
  803. tab = gtk_table_new(n_rows+1, n_vars, FALSE);
  804. gtk_container_add(GTK_CONTAINER(evbox), tab);
  805. color = get_color(COLOR_VAR_TABLE_SEP);
  806. gtk_widget_modify_bg(GTK_WIDGET(evbox),
  807. GTK_STATE_NORMAL, &color);
  808. gtk_table_set_row_spacings(GTK_TABLE(tab), 1);
  809. gtk_table_set_col_spacings(GTK_TABLE(tab), 1);
  810. }
  811. name = stralloc_printf("%s%s", var->key ? "?" : "", var->name);
  812. field = label_in_box_new(name,
  813. "Variable (column) name. Click to edit.");
  814. free(name);
  815. gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(field),
  816. n_vars, n_vars+1, 0, 1);
  817. label_in_box_bg(field, COLOR_VAR_PASSIVE);
  818. g_signal_connect(G_OBJECT(box_of_label(field)),
  819. "button_press_event",
  820. G_CALLBACK(table_var_press_event), var);
  821. g_signal_connect(G_OBJECT(box_of_label(field)),
  822. "button_release_event",
  823. G_CALLBACK(table_var_release_event), var);
  824. g_signal_connect(G_OBJECT(box_of_label(field)),
  825. "scroll_event",
  826. G_CALLBACK(table_scroll_event), table);
  827. var->widget = field;
  828. setup_var_drag(var);
  829. n_row = 0;
  830. for (row = table->rows; row; row = row->next) {
  831. value = row->values;
  832. for (pos = 0; pos != n_var; pos++)
  833. value = value->next;
  834. expr = unparse(value->expr);
  835. field = label_in_box_new(expr,
  836. "Variable value. Click to select row or to edit.");
  837. free(expr);
  838. gtk_table_attach_defaults(GTK_TABLE(tab),
  839. box_of_label(field),
  840. n_vars, n_vars+1,
  841. n_row+1, n_row+2);
  842. label_in_box_bg(field, table->active_row == row ?
  843. COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED);
  844. g_signal_connect(G_OBJECT(box_of_label(field)),
  845. "button_press_event",
  846. G_CALLBACK(table_value_press_event), value);
  847. g_signal_connect(G_OBJECT(box_of_label(field)),
  848. "button_release_event",
  849. G_CALLBACK(table_value_release_event), value);
  850. g_signal_connect(G_OBJECT(box_of_label(field)),
  851. "scroll_event",
  852. G_CALLBACK(table_scroll_event), table);
  853. value->widget = field;
  854. setup_value_drag(value);
  855. n_row++;
  856. }
  857. /*
  858. * Wrap tables wider than the screen area available for
  859. * variables and tables. Don't wrap before having output at
  860. * least one column.
  861. */
  862. if (n_vars && get_widget_width(tab) > wrap_width) {
  863. /*
  864. * Resizing alone doesn't hide extra columns. We have
  865. * to explicitly remove their content as well.
  866. */
  867. gtk_container_remove(GTK_CONTAINER(tab),
  868. box_of_label(var->widget));
  869. for (row = table->rows; row; row = row->next) {
  870. value = row->values;
  871. for (pos = 0; pos != n_var; pos++)
  872. value = value->next;
  873. gtk_container_remove(GTK_CONTAINER(tab),
  874. box_of_label(value->widget));
  875. }
  876. gtk_table_resize(GTK_TABLE(tab), n_rows, n_vars);
  877. sep = gtk_vbox_new(FALSE, 0);
  878. gtk_box_pack_start(GTK_BOX(vbox), sep,
  879. FALSE, FALSE, 1);
  880. n_vars = 0;
  881. continue;
  882. }
  883. var = var->next;
  884. n_var++;
  885. n_vars++;
  886. }
  887. }
  888. /* ----- loops ------------------------------------------------------------- */
  889. static void set_loop_values(void *user, const struct value *values,
  890. int n_values)
  891. {
  892. struct loop *loop = user;
  893. switch (n_values) {
  894. case 2:
  895. if (loop->to.expr)
  896. free_expr(loop->to.expr);
  897. loop->to.expr = values->next->expr;
  898. /* fall through */
  899. case 1:
  900. if (loop->from.expr)
  901. free_expr(loop->from.expr);
  902. loop->from.expr = values->expr;
  903. break;
  904. case 0:
  905. break;
  906. default:
  907. abort();
  908. }
  909. }
  910. static gboolean loop_var_select_event(GtkWidget *widget,
  911. GdkEventButton *event, gpointer data)
  912. {
  913. struct loop *loop = data;
  914. switch (event->button) {
  915. case 1:
  916. edit_var(&loop->var, set_loop_values, loop, 2);
  917. break;
  918. case 3:
  919. pop_up_loop_var(loop, event);
  920. break;
  921. }
  922. return TRUE;
  923. }
  924. static gboolean loop_from_select_event(GtkWidget *widget,
  925. GdkEventButton *event, gpointer data)
  926. {
  927. struct loop *loop = data;
  928. switch (event->button) {
  929. case 1:
  930. edit_nothing();
  931. edit_value(&loop->from, loop->var.frame);
  932. break;
  933. }
  934. return TRUE;
  935. }
  936. static gboolean loop_to_select_event(GtkWidget *widget,
  937. GdkEventButton *event, gpointer data)
  938. {
  939. struct loop *loop = data;
  940. switch (event->button) {
  941. case 1:
  942. edit_nothing();
  943. edit_value(&loop->to, loop->var.frame);
  944. break;
  945. }
  946. return TRUE;
  947. }
  948. static gboolean loop_select_event(GtkWidget *widget, GdkEventButton *event,
  949. gpointer data)
  950. {
  951. struct loop *loop = data;
  952. switch (event->button) {
  953. case 1:
  954. loop->active =
  955. (long) gtk_object_get_data(GTK_OBJECT(widget), "value");
  956. change_world();
  957. break;
  958. }
  959. return TRUE;
  960. }
  961. static gboolean loop_scroll_event(GtkWidget *widget, GdkEventScroll *event,
  962. gpointer data)
  963. {
  964. struct loop *loop = data;
  965. switch (event->direction) {
  966. case GDK_SCROLL_DOWN:
  967. if (loop->active < loop->iterations-1) {
  968. loop->active++;
  969. change_world();
  970. }
  971. break;
  972. case GDK_SCROLL_UP:
  973. if (loop->active) {
  974. loop->active--;
  975. change_world();
  976. }
  977. break;
  978. default:
  979. /* ignore */;
  980. }
  981. return TRUE;
  982. }
  983. static void build_loop(GtkWidget *vbox, struct frame *frame,
  984. struct loop *loop)
  985. {
  986. GtkWidget *hbox, *field, *label;
  987. char *expr;
  988. int i;
  989. hbox = gtk_hbox_new(FALSE, 0);
  990. gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  991. field = label_in_box_new(loop->var.name,
  992. "Variable name. Click to edit.");
  993. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
  994. label_in_box_bg(field, COLOR_VAR_PASSIVE);
  995. if (instantiation_error == loop)
  996. label_in_box_fg(field, COLOR_ITEM_ERROR);
  997. g_signal_connect(G_OBJECT(box_of_label(field)),
  998. "button_press_event",
  999. G_CALLBACK(loop_var_select_event), loop);
  1000. loop->var.widget = field;
  1001. gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
  1002. FALSE, FALSE, 0);
  1003. expr = unparse(loop->from.expr);
  1004. field = label_in_box_new(expr,
  1005. "Start value of loop. Click to edit.");
  1006. free(expr);
  1007. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
  1008. label_in_box_bg(field, COLOR_EXPR_PASSIVE);
  1009. g_signal_connect(G_OBJECT(box_of_label(field)),
  1010. "button_press_event",
  1011. G_CALLBACK(loop_from_select_event), loop);
  1012. loop->from.widget = field;
  1013. gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" ... "),
  1014. FALSE, FALSE, 0);
  1015. expr = unparse(loop->to.expr);
  1016. field = label_in_box_new(expr, "End value of loop. Click to edit.");
  1017. free(expr);
  1018. gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
  1019. label_in_box_bg(field, COLOR_EXPR_PASSIVE);
  1020. g_signal_connect(G_OBJECT(box_of_label(field)),
  1021. "button_press_event",
  1022. G_CALLBACK(loop_to_select_event), loop);
  1023. loop->to.widget = field;
  1024. gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" ("),
  1025. FALSE, FALSE, 0);
  1026. for (i = 0; i != loop->iterations; i++) {
  1027. label = add_activator(hbox, loop->active == i,
  1028. loop_select_event, loop,
  1029. "Loop value. Click to make active.",
  1030. "%g", loop->n+i);
  1031. gtk_object_set_data(GTK_OBJECT(box_of_label(label)), "value",
  1032. (gpointer) (long) i);
  1033. g_signal_connect(G_OBJECT(box_of_label(label)),
  1034. "scroll_event",
  1035. G_CALLBACK(loop_scroll_event), loop);
  1036. }
  1037. gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(")"),
  1038. FALSE, FALSE, 0);
  1039. }
  1040. /* ----- the list of variables, tables, and loops -------------------------- */
  1041. static GtkWidget *build_vars(struct frame *frame, int wrap_width)
  1042. {
  1043. GtkWidget *vbox;
  1044. struct table *table;
  1045. struct loop *loop;
  1046. vbox = gtk_vbox_new(FALSE, 0);
  1047. for (table = frame->tables; table; table = table->next) {
  1048. add_sep(vbox, 3);
  1049. build_assignment(vbox, frame, table);
  1050. build_table(vbox, frame, table, wrap_width);
  1051. }
  1052. for (loop = frame->loops; loop; loop = loop->next) {
  1053. add_sep(vbox, 3);
  1054. build_loop(vbox, frame, loop);
  1055. }
  1056. return vbox;
  1057. }
  1058. /* ----- items ------------------------------------------------------------- */
  1059. static void set_item_color(struct inst *inst, const char *color)
  1060. {
  1061. GtkWidget *label;
  1062. if (inst->vec)
  1063. label = inst->vec->list_widget;
  1064. else
  1065. label = inst->obj->list_widget;
  1066. if (label)
  1067. label_in_box_bg(box_of_label(label), color);
  1068. }
  1069. void gui_frame_select_inst(struct inst *inst)
  1070. {
  1071. set_item_color(inst, COLOR_ITEM_SELECTED);
  1072. }
  1073. void gui_frame_deselect_inst(struct inst *inst)
  1074. {
  1075. set_item_color(inst, COLOR_ITEM_NORMAL);
  1076. }
  1077. static gboolean item_select_vec(GtkWidget *widget, GdkEventButton *event,
  1078. gpointer data)
  1079. {
  1080. struct vec *vec = data;
  1081. switch (event->button) {
  1082. case 1:
  1083. inst_select_vec(vec);
  1084. redraw();
  1085. break;
  1086. }
  1087. return TRUE;
  1088. }
  1089. static gboolean item_select_obj(GtkWidget *widget, GdkEventButton *event,
  1090. gpointer data)
  1091. {
  1092. struct obj *obj = data;
  1093. switch (event->button) {
  1094. case 1:
  1095. inst_select_obj(obj);
  1096. redraw();
  1097. break;
  1098. }
  1099. return TRUE;
  1100. }
  1101. static GtkWidget *item_label(GtkWidget *tab, char *s, int col, int row,
  1102. gboolean (*cb)(GtkWidget *widget, GdkEventButton *event, gpointer data),
  1103. gpointer data)
  1104. {
  1105. GtkWidget *label;
  1106. label = label_in_box_new(s, "Click to select.");
  1107. gtk_misc_set_padding(GTK_MISC(label), 0, 0);
  1108. gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  1109. gtk_widget_modify_font(label, item_list_font);
  1110. gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(label),
  1111. col, col+1, row, row+1);
  1112. label_in_box_bg(box_of_label(label), COLOR_ITEM_NORMAL);
  1113. if (cb)
  1114. g_signal_connect(G_OBJECT(box_of_label(label)),
  1115. "button_press_event", G_CALLBACK(cb), data);
  1116. free(s);
  1117. return label;
  1118. }
  1119. static GtkWidget *build_items(struct frame *frame)
  1120. {
  1121. GtkWidget *vbox, *hbox, *tab;
  1122. struct order *order, *item;
  1123. struct vec *vec;
  1124. struct obj *obj;
  1125. int n;
  1126. char *s, *t;
  1127. n = 0;
  1128. for (vec = frame->vecs; vec; vec = vec->next)
  1129. n++;
  1130. for (obj = frame->objs; obj; obj = obj->next)
  1131. if (obj->type != ot_meas)
  1132. n++;
  1133. vbox = gtk_vbox_new(FALSE, 0);
  1134. add_sep(vbox, 3);
  1135. hbox = gtk_hbox_new(FALSE, 0);
  1136. gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  1137. tab = gtk_table_new(n, 2, FALSE);
  1138. gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
  1139. order = order_frame(frame);
  1140. n = 0;
  1141. for (item = order; item->vec || item->obj; item++) {
  1142. if (item->obj) {
  1143. s = print_obj(item->obj, item->vec);
  1144. item->obj->list_widget = item_label(tab, s, 1, n,
  1145. item_select_obj, item->obj);
  1146. if (item->obj == instantiation_error)
  1147. label_in_box_fg(item->obj->list_widget,
  1148. COLOR_ITEM_ERROR);
  1149. } else {
  1150. t = stralloc_printf("%s: ", print_label(item->vec));
  1151. item_label(tab, t, 0, n, NULL, NULL);
  1152. s = print_vec(item->vec);
  1153. item->vec->list_widget = item_label(tab, s, 1, n,
  1154. item_select_vec, item->vec);
  1155. if (item->vec == instantiation_error)
  1156. label_in_box_fg(item->vec->list_widget,
  1157. COLOR_ITEM_ERROR);
  1158. }
  1159. n++;
  1160. }
  1161. free(order);
  1162. return vbox;
  1163. }
  1164. static GtkWidget *build_meas(struct frame *frame)
  1165. {
  1166. GtkWidget *vbox, *hbox, *tab;
  1167. struct obj *obj;
  1168. int n;
  1169. char *s;
  1170. n = 0;
  1171. for (obj = frame->objs; obj; obj = obj->next)
  1172. if (obj->type == ot_meas)
  1173. n++;
  1174. vbox = gtk_vbox_new(FALSE, 0);
  1175. add_sep(vbox, 3);
  1176. hbox = gtk_hbox_new(FALSE, 0);
  1177. gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  1178. tab = gtk_table_new(n, 2, FALSE);
  1179. gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
  1180. n = 0;
  1181. for (obj = frame->objs; obj; obj = obj->next) {
  1182. if (obj->type != ot_meas)
  1183. continue;
  1184. s = print_meas(obj);
  1185. obj->list_widget = item_label(tab, s, 0, n,
  1186. item_select_obj, obj);
  1187. if (obj == instantiation_error)
  1188. label_in_box_fg(obj->list_widget, COLOR_ITEM_ERROR);
  1189. n++;
  1190. }
  1191. return vbox;
  1192. }
  1193. static void dont_build_items(struct frame *frame)
  1194. {
  1195. struct vec *vec;
  1196. struct obj *obj;
  1197. for (vec = frame->vecs; vec; vec = vec->next)
  1198. vec->list_widget = NULL;
  1199. for (obj = frame->objs; obj; obj = obj->next)
  1200. obj->list_widget = NULL;
  1201. }
  1202. /* ----- package name ------------------------------------------------------ */
  1203. static int validate_pkg_name(const char *s, void *ctx)
  1204. {
  1205. if (!*s)
  1206. return 0;
  1207. while (*s) {
  1208. if (*s < 32 || *s > 126)
  1209. return 0;
  1210. s++;
  1211. }
  1212. return 1;
  1213. }
  1214. static void unselect_pkg_name(void *data)
  1215. {
  1216. GtkWidget *widget = data;
  1217. label_in_box_bg(widget, COLOR_PART_NAME);
  1218. }
  1219. static gboolean pkg_scroll_event(GtkWidget *widget, GdkEventScroll *event,
  1220. gpointer data)
  1221. {
  1222. struct pkg *pkg, *last;
  1223. switch (event->direction) {
  1224. case GDK_SCROLL_DOWN:
  1225. if (active_pkg->next)
  1226. active_pkg = active_pkg->next;
  1227. else
  1228. active_pkg = pkgs->next;
  1229. change_world();
  1230. break;
  1231. case GDK_SCROLL_UP:
  1232. last = NULL;
  1233. for (pkg = pkgs->next; pkg && (!last || pkg != active_pkg);
  1234. pkg = pkg->next)
  1235. last = pkg;
  1236. active_pkg = last;
  1237. change_world();
  1238. break;
  1239. default:
  1240. /* ignore */;
  1241. }
  1242. return TRUE;
  1243. }
  1244. static gboolean pkg_name_edit_event(GtkWidget *widget, GdkEventButton *event,
  1245. gpointer data)
  1246. {
  1247. switch (event->button) {
  1248. case 1:
  1249. inst_select_outside(widget, unselect_pkg_name);
  1250. label_in_box_bg(widget, COLOR_PART_NAME_EDITING);
  1251. status_set_type_entry(NULL, "package =");
  1252. status_set_name("Package name (actual)", "%s", pkg_name);
  1253. edit_nothing();
  1254. edit_name(&pkg_name, validate_pkg_name, NULL,
  1255. "Package name (template)");
  1256. break;
  1257. }
  1258. return TRUE;
  1259. }
  1260. static GtkWidget *build_pkg_name(void)
  1261. {
  1262. GtkWidget *label;
  1263. label = label_in_box_new(pkg_name,
  1264. "Package name. (Template) Click to edit.");
  1265. gtk_misc_set_padding(GTK_MISC(label), 2, 2);
  1266. gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  1267. label_in_box_bg(label, COLOR_PART_NAME);
  1268. g_signal_connect(G_OBJECT(box_of_label(label)),
  1269. "button_press_event", G_CALLBACK(pkg_name_edit_event), NULL);
  1270. g_signal_connect(G_OBJECT(box_of_label(label)),
  1271. "scroll_event", G_CALLBACK(pkg_scroll_event), NULL);
  1272. return box_of_label(label);
  1273. }
  1274. /* ----- packages ---------------------------------------------------------- */
  1275. static gboolean pkg_select_event(GtkWidget *widget, GdkEventButton *event,
  1276. gpointer data)
  1277. {
  1278. struct pkg *pkg = data;
  1279. switch (event->button) {
  1280. case 1:
  1281. active_pkg = pkg;
  1282. /* @@@ we could actually skip instantiation here */
  1283. change_world();
  1284. break;
  1285. }
  1286. return TRUE;
  1287. }
  1288. static GtkWidget *build_pkg_names(void)
  1289. {
  1290. GtkWidget *hbox;
  1291. struct pkg *pkg;
  1292. GtkWidget *field;
  1293. hbox = gtk_hbox_new(FALSE, 0);
  1294. for (pkg = pkgs; pkg; pkg = pkg->next)
  1295. if (pkg->name) {
  1296. field = add_activator(hbox, pkg == active_pkg,
  1297. pkg_select_event, pkg,
  1298. "Package name. Click to make active.",
  1299. "%s", pkg->name);
  1300. g_signal_connect(G_OBJECT(box_of_label(field)),
  1301. "scroll_event",
  1302. G_CALLBACK(pkg_scroll_event), NULL);
  1303. }
  1304. return hbox;
  1305. }
  1306. /* ----- frame labels ------------------------------------------------------ */
  1307. static int validate_frame_name(const char *s, void *ctx)
  1308. {
  1309. struct frame *f;
  1310. if (!is_id(s))
  1311. return 0;
  1312. for (f = frames->next; f; f = f->next)
  1313. if (!strcmp(f->name, s))
  1314. return 0;
  1315. return 1;
  1316. }
  1317. static void unselect_frame(void *data)
  1318. {
  1319. struct frame *frame= data;
  1320. /*
  1321. * "unselect" means in this context that the selection has moved
  1322. * elsewhere. However, this does not necessarily change the frame.
  1323. * (And, in fact, since we rebuild the frame list anyway, the color
  1324. * change here doesn't matter if selecting a different frame.)
  1325. * So we revert from "editing" to "selected".
  1326. */
  1327. label_in_box_bg(frame->label, COLOR_FRAME_SELECTED);
  1328. }
  1329. static void edit_frame(struct frame *frame)
  1330. {
  1331. const char *tip;
  1332. inst_select_outside(frame, unselect_frame);
  1333. label_in_box_bg(frame->label, COLOR_FRAME_EDITING);
  1334. tip = "Frame name";
  1335. status_set_type_entry(NULL, "name =");
  1336. status_set_name(tip, "%s", frame->name);
  1337. edit_nothing();
  1338. edit_unique(&frame->name, validate_frame_name, frame, tip);
  1339. }
  1340. void select_frame(struct frame *frame)
  1341. {
  1342. if (active_frame)
  1343. label_in_box_bg(active_frame->label, COLOR_FRAME_UNSELECTED);
  1344. active_frame = frame;
  1345. change_world();
  1346. }
  1347. static gboolean frame_press_event(GtkWidget *widget, GdkEventButton *event,
  1348. gpointer data)
  1349. {
  1350. struct frame *frame = data;
  1351. switch (event->button) {
  1352. case 3:
  1353. pop_up_frame(frame, event);
  1354. return TRUE;
  1355. }
  1356. return FALSE;
  1357. }
  1358. static gboolean frame_release_event(GtkWidget *widget, GdkEventButton *event,
  1359. gpointer data)
  1360. {
  1361. struct frame *frame = data;
  1362. switch (event->button) {
  1363. case 1:
  1364. if (is_dragging(frame))
  1365. return FALSE;
  1366. if (active_frame != frame) {
  1367. select_frame(frame);
  1368. } else {
  1369. if (active_frame->name) {
  1370. edit_nothing();
  1371. edit_frame(frame);
  1372. }
  1373. }
  1374. return TRUE;
  1375. }
  1376. return FALSE;
  1377. }
  1378. static GtkWidget *build_frame_label(struct frame *frame)
  1379. {
  1380. GtkWidget *label;
  1381. label = label_in_box_new(frame->name ? frame->name : "(root)",
  1382. frame->name ? "Frame name. Click to select or edit." :
  1383. "Root frame. Click to select.");
  1384. gtk_misc_set_padding(GTK_MISC(label), 2, 2);
  1385. gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  1386. label_in_box_bg(label, active_frame == frame ?
  1387. COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED);
  1388. g_signal_connect(G_OBJECT(box_of_label(label)),
  1389. "button_press_event", G_CALLBACK(frame_press_event), frame);
  1390. g_signal_connect(G_OBJECT(box_of_label(label)),
  1391. "button_release_event", G_CALLBACK(frame_release_event), frame);
  1392. frame->label = label;
  1393. if (frame != frames)
  1394. setup_frame_drag(frame);
  1395. return box_of_label(label);
  1396. }
  1397. /* ----- frame references -------------------------------------------------- */
  1398. static gboolean frame_ref_select_event(GtkWidget *widget, GdkEventButton *event,
  1399. gpointer data)
  1400. {
  1401. struct obj *obj = data;
  1402. switch (event->button) {
  1403. case 1:
  1404. obj->u.frame.ref->active_ref = data;
  1405. change_world();
  1406. break;
  1407. }
  1408. return TRUE;
  1409. }
  1410. static GtkWidget *build_frame_refs(const struct frame *frame)
  1411. {
  1412. GtkWidget *hbox;
  1413. struct obj *obj;
  1414. char *tooltip;
  1415. hbox = gtk_hbox_new(FALSE, 0);
  1416. for (obj = frame->objs; obj; obj = obj->next)
  1417. if (obj->type == ot_frame &&
  1418. obj->u.frame.ref == active_frame) {
  1419. tooltip = stralloc_printf(
  1420. "Frame <b>%s</b> is referenced here. "
  1421. "Click to make active.", active_frame->name);
  1422. add_activator(hbox,
  1423. obj == obj->u.frame.ref->active_ref,
  1424. frame_ref_select_event, obj,
  1425. tooltip,
  1426. "%d", obj->u.frame.lineno);
  1427. free(tooltip);
  1428. }
  1429. return hbox;
  1430. }
  1431. /* ----- frames ------------------------------------------------------------ */
  1432. static void do_build_frames(GtkWidget *vbox, int wrap_width)
  1433. {
  1434. struct frame *frame;
  1435. GtkWidget *hbox, *tab, *label, *packages, *refs, *vars, *items, *meas;
  1436. int n = 0;
  1437. int max_name_width, name_width;
  1438. destroy_all_children(GTK_CONTAINER(vbox));
  1439. for (frame = frames; frame; frame = frame->next)
  1440. n++;
  1441. hbox = gtk_hbox_new(FALSE, 0);
  1442. tab = gtk_table_new(n*2+3, 2, FALSE);
  1443. gtk_table_set_row_spacings(GTK_TABLE(tab), 1);
  1444. gtk_table_set_col_spacings(GTK_TABLE(tab), 1);
  1445. gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
  1446. gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  1447. label = build_pkg_name();
  1448. gtk_table_attach_defaults(GTK_TABLE(tab), label, 0, 1, 0, 1);
  1449. max_name_width = get_widget_width(label);
  1450. packages = build_pkg_names();
  1451. gtk_table_attach_defaults(GTK_TABLE(tab), packages, 1, 2, 0, 1);
  1452. n = 0;
  1453. for (frame = frames; frame; frame = frame->next) {
  1454. label = build_frame_label(frame);
  1455. gtk_table_attach_defaults(GTK_TABLE(tab), label,
  1456. 0, 1, n*2+1, n*2+2);
  1457. n++;
  1458. name_width = get_widget_width(label);
  1459. if (name_width > max_name_width)
  1460. max_name_width = name_width;
  1461. }
  1462. wrap_width -= max_name_width+FRAME_AREA_MISC_WIDTH;
  1463. n = 0;
  1464. for (frame = frames; frame; frame = frame->next) {
  1465. refs = build_frame_refs(frame);
  1466. gtk_table_attach_defaults(GTK_TABLE(tab), refs,
  1467. 1, 2, n*2+1, n*2+2);
  1468. switch (sidebar) {
  1469. case sidebar_var:
  1470. vars = build_vars(frame, wrap_width);
  1471. gtk_table_attach_defaults(GTK_TABLE(tab), vars,
  1472. 1, 2, n*2+2, n*2+3);
  1473. dont_build_items(frame);
  1474. break;
  1475. case sidebar_code:
  1476. items = build_items(frame);
  1477. gtk_table_attach_defaults(GTK_TABLE(tab), items,
  1478. 1, 2, n*2+2, n*2+3);
  1479. break;
  1480. default:
  1481. abort();
  1482. }
  1483. n++;
  1484. }
  1485. if (sidebar == sidebar_code) {
  1486. meas = build_meas(frames);
  1487. gtk_table_attach_defaults(GTK_TABLE(tab), meas,
  1488. 1, 2, n*2+2, n*2+3);
  1489. }
  1490. gtk_widget_show_all(hbox);
  1491. }
  1492. /* ----- packages ---------------------------------------------------------- */
  1493. static void build_packages(GtkWidget *vbox, int wrap_width)
  1494. {
  1495. GtkWidget *label, *hbox, *field;
  1496. struct pkg *pkg;
  1497. destroy_all_children(GTK_CONTAINER(vbox));
  1498. label = build_pkg_name();
  1499. gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
  1500. for (pkg = pkgs; pkg; pkg = pkg->next)
  1501. if (pkg->name) {
  1502. hbox = gtk_hbox_new(FALSE, 0);
  1503. field = add_activator(hbox, pkg == active_pkg,
  1504. pkg_select_event, pkg,
  1505. "Package name. Click to make active.",
  1506. "%s", pkg->name);
  1507. g_signal_connect(G_OBJECT(box_of_label(field)),
  1508. "scroll_event",
  1509. G_CALLBACK(pkg_scroll_event), NULL);
  1510. gtk_box_pack_start(GTK_BOX(vbox), hbox,
  1511. FALSE, FALSE, 2);
  1512. }
  1513. gtk_widget_show_all(vbox);
  1514. }
  1515. /* ----- sidebar dispatcher ------------------------------------------------ */
  1516. void build_frames(GtkWidget *vbox, int wrap_width)
  1517. {
  1518. if (sidebar == sidebar_pkg)
  1519. build_packages(vbox, wrap_width);
  1520. else
  1521. do_build_frames(vbox, wrap_width);
  1522. }