ui: the math editor's window, identity row and canvas are a .ui file
The second half of this plan row, and the half of that dialog which is template. src/ui/math-editor.ui holds the window (its size and modality), the box around it, the identity row -- the name and the unit -- and the body with the canvas in it. What stays in code is the drawing: the canvas is a GtkDrawingArea the file *declares* and the code draws, with the gestures that make it a graph editor, and the parameter form follows which node is selected. The palette and the buttons go next. The builder is held on `App` and cleared on the *next* opening rather than with the window: the window belongs to the builder's object list, so freeing the builder under a live window frees the window with it. That is the source form's pattern, and the probe's close-then-reopen path is what exercises it -- `reopened: dialog=ok, nodes=2`. The identity row is read back too, since a `.ui` can hold the widget but not the value: `dialog build: ... name='math3' unit='' ...`, the entries having been filled from the channel being edited. check_ui is at 12 ok, 0 failed.
This commit is contained in:
1 parent
90a17eb186
commit
1a02946656
7 files changed
+123
-36
No files matched your search
+34
-32
@@ -1943,11 +1943,29 @@ void open_math_dialog(App& app, int edit) {
|
||||
}
|
||||
d->selected = d->output;
|
||||
|
||||
GtkWidget* window = gtk_window_new();
|
||||
d->window = window;
|
||||
// The window and its identity row are a `.ui` file (`src/ui/math-editor.ui`). The canvas, the palette and
|
||||
// the parameter form below them stay in code: the canvas is drawn rather than declared, and the form
|
||||
// follows which node is selected.
|
||||
g_clear_object(&app.math_dialog_ui);
|
||||
app.math_dialog_ui = gtk_builder_new_from_resource("/org/udpscope/ui/math-editor.ui");
|
||||
GtkBuilder* ui = app.math_dialog_ui;
|
||||
d->window = GTK_WIDGET(gtk_builder_get_object(ui, "math_window"));
|
||||
GtkWidget* outer = GTK_WIDGET(gtk_builder_get_object(ui, "math_outer"));
|
||||
GtkWidget* head = GTK_WIDGET(gtk_builder_get_object(ui, "math_head"));
|
||||
d->name = GTK_WIDGET(gtk_builder_get_object(ui, "math_name"));
|
||||
d->unit = GTK_WIDGET(gtk_builder_get_object(ui, "math_unit"));
|
||||
if (d->window == nullptr || outer == nullptr || head == nullptr || d->name == nullptr ||
|
||||
d->unit == nullptr) {
|
||||
// A missing id is a mistake in the `.ui`. There is no editor to open, so this says so and gives up
|
||||
// rather than building the rest of a window around a hole; `[math-probe] editor` reads the difference.
|
||||
std::fprintf(stderr, "[math] editor: math-editor.ui is missing an id this code reads\n");
|
||||
delete d;
|
||||
return;
|
||||
}
|
||||
GtkWidget* window = d->window;
|
||||
gtk_window_set_title(GTK_WINDOW(window), edit >= 0 ? "Edit math channel" : "New math channel");
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 720, 420);
|
||||
gtk_window_set_modal(GTK_WINDOW(window), true);
|
||||
// The dialog's own state, freed with the window: a plain local here would leak the graph and every drag
|
||||
// it is halfway through on each opening.
|
||||
g_object_set_data_full(G_OBJECT(window), "udpscope-math-dialog", d,
|
||||
+[](gpointer p) { delete static_cast<MathDialog*>(p); });
|
||||
g_signal_connect(window, "close-request", G_CALLBACK(+[](GtkWindow* w, gpointer) {
|
||||
@@ -1959,35 +1977,22 @@ void open_math_dialog(App& app, int edit) {
|
||||
}),
|
||||
nullptr);
|
||||
|
||||
GtkWidget* outer = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
|
||||
gtk_widget_set_margin_top(outer, 10);
|
||||
gtk_widget_set_margin_bottom(outer, 10);
|
||||
gtk_widget_set_margin_start(outer, 10);
|
||||
gtk_widget_set_margin_end(outer, 10);
|
||||
gtk_window_set_child(GTK_WINDOW(window), outer);
|
||||
|
||||
// The channel's own identity: the name is also how another graph names it as a source.
|
||||
GtkWidget* head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
d->name = gtk_entry_new();
|
||||
gtk_entry_set_placeholder_text(GTK_ENTRY(d->name), "name");
|
||||
// The two values the file cannot hold: what this channel is called and the unit its readouts carry. The
|
||||
// name is also how another graph refers to this channel as a source, which is why it takes the slack.
|
||||
if (edit >= 0 && edit < static_cast<int>(app.math.size())) {
|
||||
gtk_editable_set_text(GTK_EDITABLE(d->name), app.math[static_cast<std::size_t>(edit)].name.c_str());
|
||||
}
|
||||
d->unit = gtk_entry_new();
|
||||
gtk_entry_set_placeholder_text(GTK_ENTRY(d->unit), "unit (optional)");
|
||||
if (edit >= 0 && edit < static_cast<int>(app.math.size())) {
|
||||
gtk_editable_set_text(GTK_EDITABLE(d->unit), app.math[static_cast<std::size_t>(edit)].unit.c_str());
|
||||
}
|
||||
gtk_widget_set_hexpand(d->name, true);
|
||||
gtk_box_append(GTK_BOX(head), d->name);
|
||||
gtk_box_append(GTK_BOX(head), d->unit);
|
||||
gtk_box_append(GTK_BOX(outer), head);
|
||||
|
||||
GtkWidget* body = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
d->canvas = gtk_drawing_area_new();
|
||||
gtk_widget_set_size_request(d->canvas, 420, 300);
|
||||
gtk_widget_set_hexpand(d->canvas, true);
|
||||
gtk_widget_set_vexpand(d->canvas, true);
|
||||
// The body and the canvas are the file's as well; what is code is the *drawing* -- the function below and
|
||||
// the gestures under it, which are what make the area a graph editor rather than a picture.
|
||||
GtkWidget* body = GTK_WIDGET(gtk_builder_get_object(ui, "math_body"));
|
||||
d->canvas = GTK_WIDGET(gtk_builder_get_object(ui, "math_canvas"));
|
||||
if (body == nullptr || d->canvas == nullptr) {
|
||||
std::fprintf(stderr, "[math] editor: math-editor.ui is missing its body or canvas\n");
|
||||
delete d;
|
||||
return;
|
||||
}
|
||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(d->canvas), math_canvas_draw, d, nullptr);
|
||||
GtkGesture* click = gtk_gesture_click_new();
|
||||
g_signal_connect(click, "pressed", G_CALLBACK(+[](GtkGestureClick* g, int, double x, double y,
|
||||
@@ -2028,8 +2033,6 @@ void open_math_dialog(App& app, int edit) {
|
||||
g_signal_connect(keys, "key-pressed", G_CALLBACK(math_canvas_key), d);
|
||||
gtk_widget_add_controller(d->canvas, keys);
|
||||
|
||||
gtk_box_append(GTK_BOX(body), d->canvas);
|
||||
|
||||
// The form: every row exists from the start and is shown or hidden per op, so no rebuild can
|
||||
// invalidate a callback's handle.
|
||||
GtkWidget* form = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
||||
@@ -2181,8 +2184,7 @@ void open_math_dialog(App& app, int edit) {
|
||||
gtk_box_append(GTK_BOX(buttons), fit);
|
||||
gtk_box_append(GTK_BOX(buttons), tidy);
|
||||
gtk_box_append(GTK_BOX(form), buttons);
|
||||
gtk_box_append(GTK_BOX(body), form);
|
||||
gtk_box_append(GTK_BOX(outer), body);
|
||||
gtk_box_append(GTK_BOX(body), form); // the form is the body's second child; the canvas is the file's
|
||||
|
||||
GtkWidget* actions = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
GtkWidget* cancel = gtk_button_new_with_label("Cancel");
|
||||
|
||||
Reference in new issue
Block a user