1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924 |
- /*
- * gui_frame.c - GUI, frame window
- *
- * Written 2009, 2010, 2012, 2015 by Werner Almesberger
- * Copyright 2009, 2010, 2012, 2015 by Werner Almesberger
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- #include <string.h>
- #include <gtk/gtk.h>
- #include "util.h"
- #include "error.h"
- #include "dump.h"
- #include "inst.h"
- #include "obj.h"
- #include "delete.h"
- #include "unparse.h"
- #include "gui_util.h"
- #include "gui_style.h"
- #include "gui_status.h"
- #include "gui_tool.h"
- #include "gui_canvas.h"
- #include "gui.h"
- #include "gui_frame_drag.h"
- #include "gui_frame.h"
- enum sidebar sidebar = sidebar_var;
- /* ----- add elements, shared ---------------------------------------------- */
- /* @@@ merge with fpd.y */
- static void add_table(struct frame *frame, struct table **anchor)
- {
- struct table *table, **walk;
- table = zalloc_type(struct table);
- table->vars = zalloc_type(struct var);
- table->vars->name = unique("_");
- table->vars->frame = frame;
- table->vars->table = table;
- table->rows = zalloc_type(struct row);
- table->rows->table = table;
- table->rows->values = zalloc_type(struct value);
- table->rows->values->expr = parse_expr("0");
- table->rows->values->row = table->rows;
- table->active_row = table->rows;
- if (anchor) {
- table->next = *anchor;
- *anchor = table;
- } else {
- for (walk = &frame->tables; *walk; walk = &(*walk)->next);
- *walk = table;
- }
- change_world();
- }
- static void add_loop(struct frame *frame, struct loop **anchor)
- {
- struct loop *loop, **walk;
- loop = zalloc_type(struct loop);
- loop->var.name = unique("_");
- loop->var.frame = frame;
- loop->from.expr = parse_expr("0");
- loop->to.expr = parse_expr("0");
- if (anchor) {
- loop->next = *anchor;
- *anchor = loop;
- } else {
- loop->next = NULL;
- for (walk = &frame->loops; *walk; walk = &(*walk)->next);
- *walk = loop;
- }
- change_world();
- }
- /* ----- popup dispatcher -------------------------------------------------- */
- static void *popup_data;
- static void pop_up(GtkWidget *menu, GdkEventButton *event, void *data)
- {
- popup_data = data;
- gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
- event->button, event->time);
- }
- /* ----- popup: frame ------------------------------------------------------ */
- static GtkItemFactory *factory_frame;
- static GtkWidget *popup_frame_widget;
- static void popup_add_frame(void)
- {
- struct frame *parent = popup_data;
- struct frame *new;
- new = zalloc_type(struct frame);
- new->name = unique("_");
- new->next = parent->next;
- parent->next = new;
- change_world();
- }
- static void popup_del_frame(void)
- {
- struct frame *frame = popup_data;
- assert(frame != frames);
- delete_frame(frame);
- if (active_frame == frame)
- select_frame(frames);
- change_world();
- }
- static void popup_add_table(void)
- {
- add_table(popup_data, NULL);
- }
- static void popup_add_loop(void)
- {
- add_loop(popup_data, NULL);
- }
- static GtkItemFactoryEntry popup_frame_entries[] = {
- { "/Add frame", NULL, popup_add_frame,0, "<Item>" },
- { "/sep0", NULL, NULL, 0, "<Separator>" },
- { "/Add variable", NULL, popup_add_table,0, "<Item>" },
- { "/Add loop", NULL, popup_add_loop, 0, "<Item>" },
- { "/sep1", NULL, NULL, 0, "<Separator>" },
- { "/Delete frame", NULL, popup_del_frame,0, "<Item>" },
- { "/sep2", NULL, NULL, 0, "<Separator>" },
- { "/Close", NULL, NULL, 0, "<Item>" },
- { NULL }
- };
- static gboolean can_add_frame(void)
- {
- const struct frame *frame;
- for (frame = frames->next; frame; frame = frame->next)
- if (!strcmp(frame->name, "_"))
- return FALSE;
- return TRUE;
- }
- static gboolean can_add_var(const struct frame *frame)
- {
- const struct table *table;
- const struct var *var;
- const struct loop *loop;
- for (table = frame->tables; table; table = table->next)
- for (var = table->vars; var; var = var->next)
- if (!strcmp(var->name, "_"))
- return FALSE;
- for (loop = frame->loops; loop; loop = loop->next)
- if (!strcmp(loop->var.name, "_"))
- return FALSE;
- return TRUE;
- }
- static void enable_add_var(struct frame *frame, GtkItemFactory *factory)
- {
- gboolean add_var;
- add_var = can_add_var(frame);
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory, "/Add variable"), add_var);
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory, "/Add loop"), add_var);
- }
- static void pop_up_frame(struct frame *frame, GdkEventButton *event)
- {
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_frame, "/Delete frame"),
- frame != frames);
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_frame, "/Add frame"),
- can_add_frame());
- enable_add_var(frame, factory_frame);
- pop_up(popup_frame_widget, event, frame);
- }
- /* ----- popup: single variable -------------------------------------------- */
- static GtkItemFactory *factory_single_var;
- static GtkWidget *popup_single_var_widget;
- static void add_row_here(struct table *table, struct row **anchor)
- {
- struct row *row;
- const struct value *walk;
- struct value *value;
- row = zalloc_type(struct row);
- row->table = table;
- /* @@@ future: adjust type */
- for (walk = table->rows->values; walk; walk = walk->next) {
- value = zalloc_type(struct value);
- value->expr = parse_expr("0");
- value->row = row;
- value->next = row->values;
- row->values = value;
- }
- row->next = *anchor;
- *anchor = row;
- change_world();
- }
- static void add_column_here(struct table *table, struct var **anchor)
- {
- const struct var *walk;
- struct var *var;
- struct row *row;
- struct value *value;
- struct value **value_anchor;
- int n = 0, i;
- for (walk = table->vars; walk != *anchor; walk = walk->next)
- n++;
- var = zalloc_type(struct var);
- var->name = unique("_");
- var->frame = table->vars->frame;
- var->table = table;
- var->next = *anchor;
- *anchor = var;
- for (row = table->rows; row; row = row->next) {
- value_anchor = &row->values;
- for (i = 0; i != n; i++)
- value_anchor = &(*value_anchor)->next;
- value = zalloc_type(struct value);
- value->expr = parse_expr("0");
- value->row = row;
- value->next = *value_anchor;
- *value_anchor = value;
- }
- change_world();
- }
- static void popup_add_row(void)
- {
- struct var *var = popup_data;
- add_row_here(var->table, &var->table->rows);
- }
- static void popup_add_column(void)
- {
- struct var *var = popup_data;
- add_column_here(var->table, &var->next);
- }
- static void popup_del_table(void)
- {
- struct var *var = popup_data;
- delete_table(var->table);
- change_world();
- }
- static void popup_add_table_from_var(void)
- {
- struct var *var = popup_data;
- add_table(var->frame, &var->table->next);
- }
- static void popup_add_loop_from_var(void)
- {
- struct var *var = popup_data;
- add_loop(var->frame, NULL);
- }
- static GtkItemFactoryEntry popup_single_var_entries[] = {
- { "/Add row", NULL, popup_add_row, 0, "<Item>" },
- { "/Add column", NULL, popup_add_column, 0, "<Item>" },
- { "/sep1", NULL, NULL, 0, "<Separator>" },
- { "/Delete variable", NULL, popup_del_table,0, "<Item>" },
- { "/sep2", NULL, NULL, 0, "<Separator>" },
- { "/Add variable", NULL, popup_add_table_from_var,
- 0, "<Item>" },
- { "/Add loop", NULL, popup_add_loop_from_var,
- 0, "<Item>" },
- { "/sep3", NULL, NULL, 0, "<Separator>" },
- { "/Close", NULL, NULL, 0, "<Item>" },
- { NULL }
- };
- static void pop_up_single_var(struct var *var, GdkEventButton *event)
- {
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_single_var, "/Add column"),
- can_add_var(var->frame));
- enable_add_var(var->frame, factory_single_var);
- pop_up(popup_single_var_widget, event, var);
- }
- /* ----- popup: table variable --------------------------------------------- */
- static GtkItemFactory *factory_table_var;
- static GtkWidget *popup_table_var_widget;
- static void popup_del_column(void)
- {
- struct var *var = popup_data;
- const struct var *walk;
- int n = 0;
- for (walk = var->table->vars; walk != var; walk = walk->next)
- n++;
- delete_column(var->table, n);
- change_world();
- }
- static GtkItemFactoryEntry popup_table_var_entries[] = {
- { "/Add row", NULL, popup_add_row, 0, "<Item>" },
- { "/Add column", NULL, popup_add_column, 0, "<Item>" },
- { "/sep1", NULL, NULL, 0, "<Separator>" },
- { "/Delete table", NULL, popup_del_table,0, "<Item>" },
- { "/Delete column", NULL, popup_del_column, 0, "<Item>" },
- { "/sep2", NULL, NULL, 0, "<Separator>" },
- { "/Add variable", NULL, popup_add_table_from_var,
- 0, "<Item>" },
- { "/Add loop", NULL, popup_add_loop_from_var,
- 0, "<Item>" },
- { "/sep3", NULL, NULL, 0, "<Separator>" },
- { "/Close", NULL, NULL, 0, "<Item>" },
- { NULL }
- };
- static void pop_up_table_var(struct var *var, GdkEventButton *event)
- {
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_table_var, "/Delete column"),
- var->table->vars->next != NULL);
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_table_var, "/Add column"),
- can_add_var(var->frame));
- enable_add_var(var->frame, factory_table_var);
- pop_up(popup_table_var_widget, event, var);
- }
- /* ----- popup: table value ------------------------------------------------ */
- static GtkItemFactory *factory_table_value;
- static GtkWidget *popup_table_value_widget;
- static void popup_add_column_by_value(void)
- {
- struct value *value = popup_data;
- const struct value *walk;
- struct table *table = value->row->table;
- struct var *var = table->vars;
- for (walk = value->row->values; walk != value; walk = walk->next)
- var = var->next;
- add_column_here(table, &var->next);
- }
- static void popup_add_row_by_value(void)
- {
- struct value *value = popup_data;
- add_row_here(value->row->table, &value->row->next);
- }
- static void popup_del_row(void)
- {
- struct value *value = popup_data;
- struct table *table = value->row->table;
- delete_row(value->row);
- if (table->active_row == value->row)
- table->active_row = table->rows;
- change_world();
- }
- static void popup_del_column_by_value(void)
- {
- struct value *value = popup_data;
- const struct value *walk;
- int n = 0;
- for (walk = value->row->values; walk != value; walk = walk->next)
- n++;
- delete_column(value->row->table, n);
- change_world();
- }
- static GtkItemFactoryEntry popup_table_value_entries[] = {
- { "/Add row", NULL, popup_add_row_by_value, 0, "<Item>" },
- { "/Add column", NULL, popup_add_column_by_value,
- 0, "<Item>" },
- { "/sep1", NULL, NULL, 0, "<Separator>" },
- { "/Delete row", NULL, popup_del_row, 0, "<Item>" },
- { "/Delete column", NULL, popup_del_column_by_value,
- 0, "<Item>" },
- { "/sep2", NULL, NULL, 0, "<Separator>" },
- { "/Close", NULL, NULL, 0, "<Item>" },
- { NULL }
- };
- static void pop_up_table_value(struct value *value, GdkEventButton *event)
- {
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_table_value, "/Delete row"),
- value->row->table->rows->next != NULL);
- gtk_widget_set_sensitive(
- gtk_item_factory_get_item(factory_table_value, "/Delete column"),
- value->row->table->vars->next != NULL);
- pop_up(popup_table_value_widget, event, value);
- }
- /* ----- popup: loop ------------------------------------------------------- */
- static GtkItemFactory *factory_loop_var;
- static GtkWidget *popup_loop_var_widget;
- static void popup_del_loop(void)
- {
- struct loop *loop = popup_data;
- delete_loop(loop);
- change_world();
- }
- static void popup_add_table_from_loop(void)
- {
- struct loop *loop = popup_data;
- add_table(loop->var.frame, NULL);
- }
- static void popup_add_loop_from_loop(void)
- {
- struct loop *loop = popup_data;
- add_loop(loop->var.frame, &loop->next);
- }
- static GtkItemFactoryEntry popup_loop_var_entries[] = {
- { "/Delete loop", NULL, popup_del_loop, 0, "<Item>" },
- { "/sep1", NULL, NULL, 0, "<Separator>" },
- { "/Add variable", NULL, popup_add_table_from_loop,
- 0, "<Item>" },
- { "/Add loop", NULL, popup_add_loop_from_loop,
- 0, "<Item>" },
- { "/sep2", NULL, NULL, 0, "<Separator>" },
- { "/Close", NULL, NULL, 0, "<Item>" },
- { NULL }
- };
- static void pop_up_loop_var(struct loop *loop, GdkEventButton *event)
- {
- enable_add_var(loop->var.frame, factory_loop_var);
- pop_up(popup_loop_var_widget, event, loop);
- }
- /* ----- make popups ------------------------------------------------------- */
- static GtkWidget *make_popup(const char *name, GtkItemFactory **factory,
- GtkItemFactoryEntry *entries)
- {
- GtkWidget *popup;
- int n;
- n = 0;
- for (n = 0; entries[n].path; n++);
- *factory = gtk_item_factory_new(GTK_TYPE_MENU, name, NULL);
- gtk_item_factory_create_items(*factory, n, entries, NULL);
- popup = gtk_item_factory_get_widget(*factory, name);
- return popup;
- }
- void make_popups(void)
- {
- popup_frame_widget = make_popup("<FpedFramePopUp>",
- &factory_frame, popup_frame_entries);
- popup_single_var_widget = make_popup("<FpedSingleVarPopUp>",
- &factory_single_var, popup_single_var_entries);
- popup_table_var_widget = make_popup("<FpedTableVarPopUp>",
- &factory_table_var, popup_table_var_entries);
- popup_table_value_widget = make_popup("<FpedTableValusPopUp>",
- &factory_table_value, popup_table_value_entries);
- popup_loop_var_widget = make_popup("<FpedLoopVarPopUp>",
- &factory_loop_var, popup_loop_var_entries);
- }
- /* ----- variable list ----------------------------------------------------- */
- static void add_sep(GtkWidget *box, int size)
- {
- GtkWidget *sep;
- GdkColor black = { 0, 0, 0, 0 };
- sep = gtk_drawing_area_new();
- gtk_box_pack_start(GTK_BOX(box), sep, FALSE, TRUE, size);
- gtk_widget_modify_bg(sep, GTK_STATE_NORMAL, &black);
- }
- /* ----- variable name editor ---------------------------------------------- */
- static int find_var_in_frame(const struct frame *frame, const char *name,
- const struct var *self)
- {
- const struct table *table;
- const struct loop *loop;
- const struct var *var;
- for (table = frame->tables; table; table = table->next)
- for (var = table->vars; var; var = var->next)
- if (var != self && !var->key &&
- !strcmp(var->name, name))
- return 1;
- for (loop = frame->loops; loop; loop = loop->next)
- if (&loop->var != self && !strcmp(loop->var.name, name))
- return 1;
- return 0;
- }
- static int validate_var_name(const char *s, void *ctx)
- {
- struct var *var = ctx;
- if (!is_id(s))
- return 0;
- if (var->key)
- return 1;
- return !find_var_in_frame(var->frame, s, var);
- }
- static void unselect_var(void *data)
- {
- struct var *var = data;
- label_in_box_bg(var->widget, COLOR_VAR_PASSIVE);
- }
- static void show_value(const struct expr *expr, const struct frame *frame)
- {
- const char *value_string;
- struct num value;
- status_set_type_x(NULL, "value =");
- value_string = eval_str(expr, frame);
- if (value_string) {
- status_set_x(NULL, "\"%s\"", value_string);
- } else {
- value = eval_num(expr, frame);
- if (is_undef(value))
- status_set_x(NULL, "undefined");
- else
- status_set_x(NULL, "%lg%s", value.n, str_unit(value));
- }
- }
- static void show_var_value(const struct var *var, const struct frame *frame)
- {
- const struct var *walk;
- const struct value *value;
- if (!var->table)
- return;
- value = var->table->active_row->values;
- for (walk = var->table->vars; walk != var; walk = walk->next)
- value = value->next;
- show_value(value->expr, frame);
- }
- static void edit_var(struct var *var,
- void (*set_values)(void *user, const struct value *values, int n_values),
- void *user, int max_values)
- {
- inst_select_outside(var, unselect_var);
- label_in_box_bg(var->widget, COLOR_VAR_EDITING);
- status_set_type_entry(NULL, "name =");
- status_set_name("Variable name", "%s", var->name);
- show_var_value(var, var->frame);
- edit_nothing();
- edit_var_type(var);
- edit_unique_with_values(&var->name, validate_var_name, var,
- set_values, user, max_values,
- "Variable name. "
- "Shortcut:<b><i>name</i>=<i>value</i>,<i>...</i> </b>");
- }
- static void set_col_values(void *user, const struct value *values,
- int n_values);
- void reselect_var(struct var *var)
- {
- edit_var(var, set_col_values, var, -1);
- }
- /* ----- value editor ------------------------------------------------------ */
- static void unselect_value(void *data)
- {
- struct value *value = data;
- /*
- * This condition is a little cryptic. Here is what it does:
- *
- * IF table/assignment (not loop)
- * AND the current row is the active (selected) row
- * AND it's an assignment (not a table).
- *
- * We need the last condition because the expressions of assignments
- * are drawn with COLOR_EXPR_PASSIVE. (See build_assignment.)
- */
- label_in_box_bg(value->widget,
- value->row && value->row->table->active_row == value->row &&
- (value->row->table->rows->next || value->row->table->vars->next) ?
- COLOR_CHOICE_SELECTED : COLOR_EXPR_PASSIVE);
- }
- static void edit_value(struct value *value, const struct frame *frame)
- {
- inst_select_outside(value, unselect_value);
- label_in_box_bg(value->widget, COLOR_EXPR_EDITING);
- show_value(value->expr, frame);
- edit_nothing();
- edit_expr(&value->expr, "Value");
- }
- static void edit_value_list(struct value *value, const struct frame *frame,
- void (*set_values)(void *user, const struct value *values, int n_values),
- void *user)
- {
- inst_select_outside(value, unselect_value);
- label_in_box_bg(value->widget, COLOR_EXPR_EDITING);
- show_value(value->expr, frame);
- edit_nothing();
- edit_expr_list(value->expr, set_values, user, "Value(s)");
- }
- /* ----- activator --------------------------------------------------------- */
- static GtkWidget *add_activator(GtkWidget *hbox, int active,
- gboolean (*cb)(GtkWidget *widget, GdkEventButton *event, gpointer data),
- gpointer user, const char *tooltip, const char *fmt, ...)
- {
- GtkWidget *label;
- va_list ap;
- char buf[100];
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
- label = label_in_box_new(buf, tooltip);
- gtk_misc_set_padding(GTK_MISC(label), 2, 2);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- label_in_box_bg(label,
- active ? COLOR_CHOICE_SELECTED : COLOR_CHOICE_UNSELECTED);
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(label),
- FALSE, FALSE, 2);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "button_press_event", G_CALLBACK(cb), user);
- return label;
- }
- /* ----- assignments ------------------------------------------------------- */
- static void set_col_values(void *user, const struct value *values,
- int n_values)
- {
- struct var *var = user;
- struct table *table = var->table;
- struct value *value;
- const struct var *walk;
- struct row **row;
- row = &table->rows;
- while (values) {
- if (!*row)
- add_row_here(table, row);
- value = (*row)->values;
- for (walk = table->vars; walk != var; walk = walk->next)
- value = value->next;
- free_expr(value->expr);
- value->expr = values->expr;
- values = values->next;
- row = &(*row)->next;
- }
- }
- static gboolean assignment_var_select_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct var *var = data;
- switch (event->button) {
- case 1:
- edit_var(var, set_col_values, var, -1);
- break;
- case 3:
- pop_up_single_var(var, event);
- break;
- }
- return TRUE;
- }
- static gboolean assignment_value_select_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct value *value = data;
- switch (event->button) {
- case 1:
- edit_nothing();
- edit_value(value, value->row->table->vars->frame);
- break;
- }
- return TRUE;
- }
- /*
- * In tables, expressions in the active row have a COLOR_CHOICE_SELECTED
- * background. While expressions in assignments are technically on the active
- * (and only) row, we use COLOR_VAR_PASSIVE for better readability.
- */
- static void build_assignment(GtkWidget *vbox, struct frame *frame,
- struct table *table)
- {
- GtkWidget *hbox, *field;
- char *name, *expr;
- if (!table->vars || table->vars->next)
- return;
- if (!table->rows || table->rows->next)
- return;
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
- name = stralloc_printf("%s%s", table->vars->key ? "?" : "",
- table->vars->name);
- field = label_in_box_new(name, "Variable name. Click to edit.");
- free(name);
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
- label_in_box_bg(field, COLOR_VAR_PASSIVE);
- table->vars->widget = field;
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(assignment_var_select_event), table->vars);
- gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
- FALSE, FALSE, 0);
- expr = unparse(table->rows->values->expr);
- field = label_in_box_new(expr, "Variable value. Click to edit.");
- free(expr);
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
- label_in_box_bg(field, COLOR_EXPR_PASSIVE);
- table->rows->values->widget = field;
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(assignment_value_select_event), table->rows->values);
- }
- /* ----- tables ------------------------------------------------------------ */
- static void select_row(struct row *row)
- {
- struct table *table = row->table;
- struct value *value;
- for (value = table->active_row->values; value; value = value->next)
- label_in_box_bg(value->widget, COLOR_ROW_UNSELECTED);
- table->active_row = row;
- for (value = table->active_row->values; value; value = value->next)
- label_in_box_bg(value->widget, COLOR_ROW_SELECTED);
- }
- static void set_row_values(void *user, const struct value *values,
- int n_values)
- {
- struct value *value = user;
- struct row *row = value->row;
- struct table *table = row->table;
- struct var **var;
- const struct value *walk;
- int first = 1;
- var = &table->vars;
- for (walk = row->values; walk != value; walk = walk->next)
- var = &(*var)->next;
- while (values) {
- if (!*var)
- add_column_here(table, var);
- if (first)
- first = 0;
- else
- value = value->next;
- free_expr(value->expr);
- value->expr = values->expr;
- values = values->next;
- var = &(*var)->next;
- }
- }
- static gboolean table_var_press_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct var *var = data;
- switch (event->button) {
- case 3:
- pop_up_table_var(var, event);
- return TRUE;
- }
- return FALSE;
- }
- static gboolean table_var_release_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct var *var = data;
- switch (event->button) {
- case 1:
- if (is_dragging(var))
- return FALSE;
- edit_var(var, set_col_values, var, -1);
- return TRUE;
- }
- return FALSE;
- }
- static gboolean table_value_press_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct value *value = data;
- switch (event->button) {
- case 3:
- pop_up_table_value(value, event);
- return TRUE;
- }
- return FALSE;
- }
- static gboolean table_value_release_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct value *value = data;
- switch (event->button) {
- case 1:
- if (is_dragging(value))
- return FALSE;
- if (!value->row ||
- value->row->table->active_row == value->row) {
- edit_nothing();
- edit_value_list(value, value->row->table->vars->frame,
- set_row_values, value);
- } else {
- select_row(value->row);
- change_world();
- }
- return TRUE;
- }
- return FALSE;
- }
- static gboolean table_scroll_event(GtkWidget *widget, GdkEventScroll *event,
- gpointer data)
- {
- struct table *table = data;
- struct row *row, *last;
- switch (event->direction) {
- case GDK_SCROLL_UP:
- last = NULL;
- for (row = table->rows;
- row && (!last || row != table->active_row); row = row->next)
- last = row;
- table->active_row = last;
- change_world();
- break;
- case GDK_SCROLL_DOWN:
- table->active_row = table->active_row->next;
- if (!table->active_row)
- table->active_row = table->rows;
- change_world();
- break;
- default:
- /* ignore */;
- }
- return TRUE;
- }
- /* @@@ this function is too long */
- static void build_table(GtkWidget *vbox, struct frame *frame,
- struct table *table, int wrap_width)
- {
- GtkWidget *tab, *field;
- GtkWidget *evbox, *align, *sep;
- struct var *var;
- struct row *row;
- struct value *value;
- int n_vars = 0, n_rows = 0;
- int n_var, n_row, pos;
- char *name, *expr;
- GdkColor color;
- for (var = table->vars; var; var = var->next)
- n_vars++;
- for (row = table->rows; row; row = row->next)
- n_rows++;
- if (n_vars == 1 && n_rows == 1)
- return;
- var = table->vars;
- n_var = 0;
- n_vars = 0;
- while (var) {
- if (n_vars) {
- gtk_table_resize(GTK_TABLE(tab), n_rows, n_vars+1);
- } else {
- evbox = gtk_event_box_new();
- align = gtk_alignment_new(0, 0, 0, 0);
- gtk_container_add(GTK_CONTAINER(align), evbox);
- gtk_box_pack_start(GTK_BOX(vbox), align,
- FALSE, FALSE, 0);
- tab = gtk_table_new(n_rows+1, n_vars, FALSE);
- gtk_container_add(GTK_CONTAINER(evbox), tab);
- color = get_color(COLOR_VAR_TABLE_SEP);
- gtk_widget_modify_bg(GTK_WIDGET(evbox),
- GTK_STATE_NORMAL, &color);
- gtk_table_set_row_spacings(GTK_TABLE(tab), 1);
- gtk_table_set_col_spacings(GTK_TABLE(tab), 1);
- }
- name = stralloc_printf("%s%s", var->key ? "?" : "", var->name);
- field = label_in_box_new(name,
- "Variable (column) name. Click to edit.");
- free(name);
- gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(field),
- n_vars, n_vars+1, 0, 1);
- label_in_box_bg(field, COLOR_VAR_PASSIVE);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(table_var_press_event), var);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_release_event",
- G_CALLBACK(table_var_release_event), var);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "scroll_event",
- G_CALLBACK(table_scroll_event), table);
- var->widget = field;
- setup_var_drag(var);
- n_row = 0;
- for (row = table->rows; row; row = row->next) {
- value = row->values;
- for (pos = 0; pos != n_var; pos++)
- value = value->next;
- expr = unparse(value->expr);
- field = label_in_box_new(expr,
- "Variable value. Click to select row or to edit.");
- free(expr);
- gtk_table_attach_defaults(GTK_TABLE(tab),
- box_of_label(field),
- n_vars, n_vars+1,
- n_row+1, n_row+2);
- label_in_box_bg(field, table->active_row == row ?
- COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(table_value_press_event), value);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_release_event",
- G_CALLBACK(table_value_release_event), value);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "scroll_event",
- G_CALLBACK(table_scroll_event), table);
- value->widget = field;
- setup_value_drag(value);
- n_row++;
- }
- /*
- * Wrap tables wider than the screen area available for
- * variables and tables. Don't wrap before having output at
- * least one column.
- */
- if (n_vars && get_widget_width(tab) > wrap_width) {
- /*
- * Resizing alone doesn't hide extra columns. We have
- * to explicitly remove their content as well.
- */
- gtk_container_remove(GTK_CONTAINER(tab),
- box_of_label(var->widget));
- for (row = table->rows; row; row = row->next) {
- value = row->values;
- for (pos = 0; pos != n_var; pos++)
- value = value->next;
- gtk_container_remove(GTK_CONTAINER(tab),
- box_of_label(value->widget));
- }
- gtk_table_resize(GTK_TABLE(tab), n_rows, n_vars);
- sep = gtk_vbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), sep,
- FALSE, FALSE, 1);
- n_vars = 0;
- continue;
- }
- var = var->next;
- n_var++;
- n_vars++;
- }
- }
- /* ----- loops ------------------------------------------------------------- */
- static void set_loop_values(void *user, const struct value *values,
- int n_values)
- {
- struct loop *loop = user;
- switch (n_values) {
- case 2:
- if (loop->to.expr)
- free_expr(loop->to.expr);
- loop->to.expr = values->next->expr;
- /* fall through */
- case 1:
- if (loop->from.expr)
- free_expr(loop->from.expr);
- loop->from.expr = values->expr;
- break;
- case 0:
- break;
- default:
- abort();
- }
- }
- static gboolean loop_var_select_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct loop *loop = data;
- switch (event->button) {
- case 1:
- edit_var(&loop->var, set_loop_values, loop, 2);
- break;
- case 3:
- pop_up_loop_var(loop, event);
- break;
- }
- return TRUE;
- }
- static gboolean loop_from_select_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct loop *loop = data;
- switch (event->button) {
- case 1:
- edit_nothing();
- edit_value(&loop->from, loop->var.frame);
- break;
- }
- return TRUE;
- }
- static gboolean loop_to_select_event(GtkWidget *widget,
- GdkEventButton *event, gpointer data)
- {
- struct loop *loop = data;
- switch (event->button) {
- case 1:
- edit_nothing();
- edit_value(&loop->to, loop->var.frame);
- break;
- }
- return TRUE;
- }
- static gboolean loop_select_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct loop *loop = data;
- switch (event->button) {
- case 1:
- loop->active =
- (long) gtk_object_get_data(GTK_OBJECT(widget), "value");
- change_world();
- break;
- }
- return TRUE;
- }
- static gboolean loop_scroll_event(GtkWidget *widget, GdkEventScroll *event,
- gpointer data)
- {
- struct loop *loop = data;
- switch (event->direction) {
- case GDK_SCROLL_DOWN:
- if (loop->active < loop->iterations-1) {
- loop->active++;
- change_world();
- }
- break;
- case GDK_SCROLL_UP:
- if (loop->active) {
- loop->active--;
- change_world();
- }
- break;
- default:
- /* ignore */;
- }
- return TRUE;
- }
- static void build_loop(GtkWidget *vbox, struct frame *frame,
- struct loop *loop)
- {
- GtkWidget *hbox, *field, *label;
- char *expr;
- int i;
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
- field = label_in_box_new(loop->var.name,
- "Variable name. Click to edit.");
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
- label_in_box_bg(field, COLOR_VAR_PASSIVE);
- if (instantiation_error == loop)
- label_in_box_fg(field, COLOR_ITEM_ERROR);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(loop_var_select_event), loop);
- loop->var.widget = field;
- gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" = "),
- FALSE, FALSE, 0);
- expr = unparse(loop->from.expr);
- field = label_in_box_new(expr,
- "Start value of loop. Click to edit.");
- free(expr);
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
- label_in_box_bg(field, COLOR_EXPR_PASSIVE);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(loop_from_select_event), loop);
- loop->from.widget = field;
- gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" ... "),
- FALSE, FALSE, 0);
- expr = unparse(loop->to.expr);
- field = label_in_box_new(expr, "End value of loop. Click to edit.");
- free(expr);
- gtk_box_pack_start(GTK_BOX(hbox), box_of_label(field), FALSE, FALSE, 0);
- label_in_box_bg(field, COLOR_EXPR_PASSIVE);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "button_press_event",
- G_CALLBACK(loop_to_select_event), loop);
- loop->to.widget = field;
- gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" ("),
- FALSE, FALSE, 0);
- for (i = 0; i != loop->iterations; i++) {
- label = add_activator(hbox, loop->active == i,
- loop_select_event, loop,
- "Loop value. Click to make active.",
- "%g", loop->n+i);
- gtk_object_set_data(GTK_OBJECT(box_of_label(label)), "value",
- (gpointer) (long) i);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "scroll_event",
- G_CALLBACK(loop_scroll_event), loop);
- }
- gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(")"),
- FALSE, FALSE, 0);
- }
- /* ----- the list of variables, tables, and loops -------------------------- */
- static GtkWidget *build_vars(struct frame *frame, int wrap_width)
- {
- GtkWidget *vbox;
- struct table *table;
- struct loop *loop;
- vbox = gtk_vbox_new(FALSE, 0);
- for (table = frame->tables; table; table = table->next) {
- add_sep(vbox, 3);
- build_assignment(vbox, frame, table);
- build_table(vbox, frame, table, wrap_width);
- }
- for (loop = frame->loops; loop; loop = loop->next) {
- add_sep(vbox, 3);
- build_loop(vbox, frame, loop);
- }
- return vbox;
- }
- /* ----- items ------------------------------------------------------------- */
- static void set_item_color(struct inst *inst, const char *color)
- {
- GtkWidget *label;
- if (inst->vec)
- label = inst->vec->list_widget;
- else
- label = inst->obj->list_widget;
- if (label)
- label_in_box_bg(box_of_label(label), color);
- }
- void gui_frame_select_inst(struct inst *inst)
- {
- set_item_color(inst, COLOR_ITEM_SELECTED);
- }
- void gui_frame_deselect_inst(struct inst *inst)
- {
- set_item_color(inst, COLOR_ITEM_NORMAL);
- }
- static gboolean item_select_vec(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct vec *vec = data;
- switch (event->button) {
- case 1:
- inst_select_vec(vec);
- redraw();
- break;
- }
- return TRUE;
- }
- static gboolean item_select_obj(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct obj *obj = data;
- switch (event->button) {
- case 1:
- inst_select_obj(obj);
- redraw();
- break;
- }
- return TRUE;
- }
- static GtkWidget *item_label(GtkWidget *tab, char *s, int col, int row,
- gboolean (*cb)(GtkWidget *widget, GdkEventButton *event, gpointer data),
- gpointer data)
- {
- GtkWidget *label;
- label = label_in_box_new(s, "Click to select.");
- gtk_misc_set_padding(GTK_MISC(label), 0, 0);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- gtk_widget_modify_font(label, item_list_font);
- gtk_table_attach_defaults(GTK_TABLE(tab), box_of_label(label),
- col, col+1, row, row+1);
- label_in_box_bg(box_of_label(label), COLOR_ITEM_NORMAL);
- if (cb)
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "button_press_event", G_CALLBACK(cb), data);
- free(s);
- return label;
- }
- static GtkWidget *build_items(struct frame *frame)
- {
- GtkWidget *vbox, *hbox, *tab;
- struct order *order, *item;
- struct vec *vec;
- struct obj *obj;
- int n;
- char *s, *t;
- n = 0;
- for (vec = frame->vecs; vec; vec = vec->next)
- n++;
- for (obj = frame->objs; obj; obj = obj->next)
- if (obj->type != ot_meas)
- n++;
- vbox = gtk_vbox_new(FALSE, 0);
- add_sep(vbox, 3);
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
- tab = gtk_table_new(n, 2, FALSE);
- gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
- order = order_frame(frame);
- n = 0;
- for (item = order; item->vec || item->obj; item++) {
- if (item->obj) {
- s = print_obj(item->obj, item->vec);
- item->obj->list_widget = item_label(tab, s, 1, n,
- item_select_obj, item->obj);
- if (item->obj == instantiation_error)
- label_in_box_fg(item->obj->list_widget,
- COLOR_ITEM_ERROR);
- } else {
- t = stralloc_printf("%s: ", print_label(item->vec));
- item_label(tab, t, 0, n, NULL, NULL);
- s = print_vec(item->vec);
- item->vec->list_widget = item_label(tab, s, 1, n,
- item_select_vec, item->vec);
- if (item->vec == instantiation_error)
- label_in_box_fg(item->vec->list_widget,
- COLOR_ITEM_ERROR);
- }
- n++;
- }
- free(order);
- return vbox;
- }
- static GtkWidget *build_meas(struct frame *frame)
- {
- GtkWidget *vbox, *hbox, *tab;
- struct obj *obj;
- int n;
- char *s;
- n = 0;
- for (obj = frame->objs; obj; obj = obj->next)
- if (obj->type == ot_meas)
- n++;
- vbox = gtk_vbox_new(FALSE, 0);
- add_sep(vbox, 3);
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
- tab = gtk_table_new(n, 2, FALSE);
- gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
- n = 0;
- for (obj = frame->objs; obj; obj = obj->next) {
- if (obj->type != ot_meas)
- continue;
- s = print_meas(obj);
- obj->list_widget = item_label(tab, s, 0, n,
- item_select_obj, obj);
- if (obj == instantiation_error)
- label_in_box_fg(obj->list_widget, COLOR_ITEM_ERROR);
- n++;
- }
- return vbox;
- }
- static void dont_build_items(struct frame *frame)
- {
- struct vec *vec;
- struct obj *obj;
- for (vec = frame->vecs; vec; vec = vec->next)
- vec->list_widget = NULL;
- for (obj = frame->objs; obj; obj = obj->next)
- obj->list_widget = NULL;
- }
- /* ----- package name ------------------------------------------------------ */
- static int validate_pkg_name(const char *s, void *ctx)
- {
- if (!*s)
- return 0;
- while (*s) {
- if (*s < 32 || *s > 126)
- return 0;
- s++;
- }
- return 1;
- }
- static void unselect_pkg_name(void *data)
- {
- GtkWidget *widget = data;
- label_in_box_bg(widget, COLOR_PART_NAME);
- }
- static gboolean pkg_scroll_event(GtkWidget *widget, GdkEventScroll *event,
- gpointer data)
- {
- struct pkg *pkg, *last;
- switch (event->direction) {
- case GDK_SCROLL_DOWN:
- if (active_pkg->next)
- active_pkg = active_pkg->next;
- else
- active_pkg = pkgs->next;
- change_world();
- break;
- case GDK_SCROLL_UP:
- last = NULL;
- for (pkg = pkgs->next; pkg && (!last || pkg != active_pkg);
- pkg = pkg->next)
- last = pkg;
- active_pkg = last;
- change_world();
- break;
- default:
- /* ignore */;
- }
- return TRUE;
- }
- static gboolean pkg_name_edit_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- switch (event->button) {
- case 1:
- inst_select_outside(widget, unselect_pkg_name);
- label_in_box_bg(widget, COLOR_PART_NAME_EDITING);
- status_set_type_entry(NULL, "package =");
- status_set_name("Package name (actual)", "%s", pkg_name);
- edit_nothing();
- edit_name(&pkg_name, validate_pkg_name, NULL,
- "Package name (template)");
- break;
- }
- return TRUE;
- }
- static GtkWidget *build_pkg_name(void)
- {
- GtkWidget *label;
- label = label_in_box_new(pkg_name,
- "Package name. (Template) Click to edit.");
- gtk_misc_set_padding(GTK_MISC(label), 2, 2);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- label_in_box_bg(label, COLOR_PART_NAME);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "button_press_event", G_CALLBACK(pkg_name_edit_event), NULL);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "scroll_event", G_CALLBACK(pkg_scroll_event), NULL);
- return box_of_label(label);
- }
- /* ----- packages ---------------------------------------------------------- */
- static gboolean pkg_select_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct pkg *pkg = data;
- switch (event->button) {
- case 1:
- active_pkg = pkg;
- /* @@@ we could actually skip instantiation here */
- change_world();
- break;
- }
- return TRUE;
- }
- static GtkWidget *build_pkg_names(void)
- {
- GtkWidget *hbox;
- struct pkg *pkg;
- GtkWidget *field;
- hbox = gtk_hbox_new(FALSE, 0);
- for (pkg = pkgs; pkg; pkg = pkg->next)
- if (pkg->name) {
- field = add_activator(hbox, pkg == active_pkg,
- pkg_select_event, pkg,
- "Package name. Click to make active.",
- "%s", pkg->name);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "scroll_event",
- G_CALLBACK(pkg_scroll_event), NULL);
- }
- return hbox;
- }
- /* ----- frame labels ------------------------------------------------------ */
- static int validate_frame_name(const char *s, void *ctx)
- {
- struct frame *f;
- if (!is_id(s))
- return 0;
- for (f = frames->next; f; f = f->next)
- if (!strcmp(f->name, s))
- return 0;
- return 1;
- }
- static void unselect_frame(void *data)
- {
- struct frame *frame= data;
- /*
- * "unselect" means in this context that the selection has moved
- * elsewhere. However, this does not necessarily change the frame.
- * (And, in fact, since we rebuild the frame list anyway, the color
- * change here doesn't matter if selecting a different frame.)
- * So we revert from "editing" to "selected".
- */
- label_in_box_bg(frame->label, COLOR_FRAME_SELECTED);
- }
- static void edit_frame(struct frame *frame)
- {
- const char *tip;
- inst_select_outside(frame, unselect_frame);
- label_in_box_bg(frame->label, COLOR_FRAME_EDITING);
- tip = "Frame name";
- status_set_type_entry(NULL, "name =");
- status_set_name(tip, "%s", frame->name);
- edit_nothing();
- edit_unique(&frame->name, validate_frame_name, frame, tip);
- }
- void select_frame(struct frame *frame)
- {
- if (active_frame)
- label_in_box_bg(active_frame->label, COLOR_FRAME_UNSELECTED);
- active_frame = frame;
- change_world();
- }
- static gboolean frame_press_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct frame *frame = data;
- switch (event->button) {
- case 3:
- pop_up_frame(frame, event);
- return TRUE;
- }
- return FALSE;
- }
- static gboolean frame_release_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct frame *frame = data;
- switch (event->button) {
- case 1:
- if (is_dragging(frame))
- return FALSE;
- if (active_frame != frame) {
- select_frame(frame);
- } else {
- if (active_frame->name) {
- edit_nothing();
- edit_frame(frame);
- }
- }
- return TRUE;
- }
- return FALSE;
- }
- static GtkWidget *build_frame_label(struct frame *frame)
- {
- GtkWidget *label;
- label = label_in_box_new(frame->name ? frame->name : "(root)",
- frame->name ? "Frame name. Click to select or edit." :
- "Root frame. Click to select.");
- gtk_misc_set_padding(GTK_MISC(label), 2, 2);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- label_in_box_bg(label, active_frame == frame ?
- COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "button_press_event", G_CALLBACK(frame_press_event), frame);
- g_signal_connect(G_OBJECT(box_of_label(label)),
- "button_release_event", G_CALLBACK(frame_release_event), frame);
- frame->label = label;
- if (frame != frames)
- setup_frame_drag(frame);
- return box_of_label(label);
- }
- /* ----- frame references -------------------------------------------------- */
- static gboolean frame_ref_select_event(GtkWidget *widget, GdkEventButton *event,
- gpointer data)
- {
- struct obj *obj = data;
- switch (event->button) {
- case 1:
- obj->u.frame.ref->active_ref = data;
- change_world();
- break;
- }
- return TRUE;
- }
- static GtkWidget *build_frame_refs(const struct frame *frame)
- {
- GtkWidget *hbox;
- struct obj *obj;
- char *tooltip;
- hbox = gtk_hbox_new(FALSE, 0);
- for (obj = frame->objs; obj; obj = obj->next)
- if (obj->type == ot_frame &&
- obj->u.frame.ref == active_frame) {
- tooltip = stralloc_printf(
- "Frame <b>%s</b> is referenced here. "
- "Click to make active.", active_frame->name);
- add_activator(hbox,
- obj == obj->u.frame.ref->active_ref,
- frame_ref_select_event, obj,
- tooltip,
- "%d", obj->u.frame.lineno);
- free(tooltip);
- }
- return hbox;
- }
- /* ----- frames ------------------------------------------------------------ */
- static void do_build_frames(GtkWidget *vbox, int wrap_width)
- {
- struct frame *frame;
- GtkWidget *hbox, *tab, *label, *packages, *refs, *vars, *items, *meas;
- int n = 0;
- int max_name_width, name_width;
- destroy_all_children(GTK_CONTAINER(vbox));
- for (frame = frames; frame; frame = frame->next)
- n++;
- hbox = gtk_hbox_new(FALSE, 0);
- tab = gtk_table_new(n*2+3, 2, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(tab), 1);
- gtk_table_set_col_spacings(GTK_TABLE(tab), 1);
- gtk_box_pack_start(GTK_BOX(hbox), tab, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
- label = build_pkg_name();
- gtk_table_attach_defaults(GTK_TABLE(tab), label, 0, 1, 0, 1);
- max_name_width = get_widget_width(label);
- packages = build_pkg_names();
- gtk_table_attach_defaults(GTK_TABLE(tab), packages, 1, 2, 0, 1);
- n = 0;
- for (frame = frames; frame; frame = frame->next) {
- label = build_frame_label(frame);
- gtk_table_attach_defaults(GTK_TABLE(tab), label,
- 0, 1, n*2+1, n*2+2);
- n++;
- name_width = get_widget_width(label);
- if (name_width > max_name_width)
- max_name_width = name_width;
- }
- wrap_width -= max_name_width+FRAME_AREA_MISC_WIDTH;
- n = 0;
- for (frame = frames; frame; frame = frame->next) {
- refs = build_frame_refs(frame);
- gtk_table_attach_defaults(GTK_TABLE(tab), refs,
- 1, 2, n*2+1, n*2+2);
- switch (sidebar) {
- case sidebar_var:
- vars = build_vars(frame, wrap_width);
- gtk_table_attach_defaults(GTK_TABLE(tab), vars,
- 1, 2, n*2+2, n*2+3);
- dont_build_items(frame);
- break;
- case sidebar_code:
- items = build_items(frame);
- gtk_table_attach_defaults(GTK_TABLE(tab), items,
- 1, 2, n*2+2, n*2+3);
- break;
- default:
- abort();
- }
- n++;
- }
- if (sidebar == sidebar_code) {
- meas = build_meas(frames);
- gtk_table_attach_defaults(GTK_TABLE(tab), meas,
- 1, 2, n*2+2, n*2+3);
- }
- gtk_widget_show_all(hbox);
- }
- /* ----- packages ---------------------------------------------------------- */
- static void build_packages(GtkWidget *vbox, int wrap_width)
- {
- GtkWidget *label, *hbox, *field;
- struct pkg *pkg;
- destroy_all_children(GTK_CONTAINER(vbox));
- label = build_pkg_name();
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
- for (pkg = pkgs; pkg; pkg = pkg->next)
- if (pkg->name) {
- hbox = gtk_hbox_new(FALSE, 0);
- field = add_activator(hbox, pkg == active_pkg,
- pkg_select_event, pkg,
- "Package name. Click to make active.",
- "%s", pkg->name);
- g_signal_connect(G_OBJECT(box_of_label(field)),
- "scroll_event",
- G_CALLBACK(pkg_scroll_event), NULL);
- gtk_box_pack_start(GTK_BOX(vbox), hbox,
- FALSE, FALSE, 2);
- }
- gtk_widget_show_all(vbox);
- }
- /* ----- sidebar dispatcher ------------------------------------------------ */
- void build_frames(GtkWidget *vbox, int wrap_width)
- {
- if (sidebar == sidebar_pkg)
- build_packages(vbox, wrap_width);
- else
- do_build_frames(vbox, wrap_width);
- }
|