Data Processing Modules — More about data processing modules
Run modes specify how a module function can be run. Data processing functions have two possible run modes.
If the function presents a (modal) dialog in which the user can for
instance adjust parameter values or make selections, include
GWY_RUN_INTERACTIVE
flag in its run modes.
If it makes sense to be run without asking, include GWY_RUN_IMMEDIATE
flag in its run modes. When a function is run in immediate mode, it
should fetch the last used parameter values from settings as if it is
run interactively.
Many functions allow both modes and behave according to the mode they were called in. The logic typically looks as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
static void function(GwyContainer *data, GwyRunType run) { FunctionArgs args; GwyDataField *data_field; GQuark quark; gboolean ok; /* Check run mode */ g_return_if_fail(run & FUNCTION_RUN_MODES); /* Get data field to operate on */ gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD_KEY, &quark, GWY_APP_DATA_FIELD, &data_field, 0); g_return_if_fail(data_field && quark); load_args(gwy_app_settings_get(), &args); /* Present a GUI in interactive mode, quit if cancelled */ if (run == GWY_RUN_INTERACTIVE) { ok = function_dialog(&args); save_args(gwy_app_settings_get(), &args); if (!ok) return; } /* Perform the processing in immediate mode, or after user confirmation */ function_do(data, data_field, quark, &args); } |
To highlight some areas in the data (like the grain modules do) you may want to use a mask. Masks are data fields too, differing only by a few things from the ordinary ones. Standalone masks do not exist in the container, they are always associated with some channel data. Mask data field units are irrelevant – the value range is always from 0 to 1; 0 being fully transparent and 1 the mask color set by user (may not be fully opaque). It should be noted that values different from 0 and 1 at present do not have a well-defined meaning and current modules generally produce and handle only values 0 and 1.
To attach a mask to a data field with id id, just create
a new data field and put it to the container at the appropriate key which
can be obtained with gwy_app_get_mask_key_for_id()
.
1 2 3 4 5 6 7 8 9 10 |
GwyDataField *mask_field; GQuark quark; mask_field = gwy_data_field_new_alike(data_field, TRUE); /* Fill mask_field with the mask */ ... quark = gwy_app_get_mask_key_for_id(id); gwy_container_set_object(container, quark, mask_field); g_object_unref(mask_field); |
If you functions takes a mask as an input (e.g., as Grain Statistics
does), it should add GWY_MENU_FLAG_DATA_MASK
to its sensitivity flags.
The application will then make its menu item and/or toolbox button
insensitive when no mask is available.
The mask of current channel and its key can be obtained with
gwy_app_data_browser_get_current()
as usual.
1 2 3 |
gwy_app_data_browser_get_current(GWY_APP_MASK_FIELD, &mask_field, GWY_APP_MASK_FIELD_KEY, &quark, 0); |
The function will set mask_field to NULL
and
quark to 0 if the mask does not exist.
Presentations are means to display some data derived from channel data (or even completely unrelated data) to the user instead of the actual data, while all other processing methods and tools still can see and work on the real data. An example is Shader module.
Working with presentations is similar to masks. One only uses
gwy_app_get_show_key_for_id()
instead of gwy_app_get_mask_key_for_id()
(most functions working with presentations have show
in their name for presentation
is just too long) to
obtain the presentation key, and uses GWY_APP_SHOW_FIELD
and
GWY_APP_SHOW_FIELD_KEY
when requesting the current presentation and its
key. Likewise one should add GWY_MENU_FLAG_DATA_SHOW
to menu
sensitivity flags of a function which processes presentations (this is
seldom needed as most functions only create presentations).
Data previews in module dialogs are best realized with GwyDataView widget which is used for two-dimensional data displays everywhere else in Gwyddion. This widget is a bit complex, but we can often simplify things a lot in a module dialog. The basic scheme is following:
gwy_data_field_data_changed()
to notify its users.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
GtkWidget *data_view; GwyPixmapLayer *layer; GwyContainer *mydata; gdouble zoomval; /* Create new container */ mydata = gwy_container_new(); /* Fill it with objects and auxiliary data, dfield and id were obtained * before. */ gwy_container_set_object_by_name(mydata, "/0/data", dfield); gwy_app_sync_data_items(data, mydata, id, 0, FALSE, GWY_DATA_ITEM_PALETTE, GWY_DATA_ITEM_MASK_COLOR, GWY_DATA_ITEM_RANGE, 0); /* Create the data view and its layers */ data_view = gwy_data_view_new(mydata); layer = gwy_layer_basic_new(); gwy_pixmap_layer_set_data_key(layer, "/0/data"); gwy_layer_basic_set_gradient_key(GWY_LAYER_BASIC(layer), "/0/base/palette"); gwy_data_view_set_base_layer(GWY_DATA_VIEW(data_view), layer); /* Calculate preview size */ zoomval = PREVIEW_SIZE/(gdouble)MAX(gwy_data_field_get_xres(dfield), gwy_data_field_get_yres(dfield)); gwy_data_view_set_zoom(GWY_DATA_VIEW(data_view), zoomval); /* Pack data_view somewhere... */ |
The foregoing example uses raw data keys as "/0/data"
.
Assuming we keep the standard naming scheme we can partially avoid this
with functions like gwy_app_get_data_key_for_id()
and
g_quark_to_string()
. However, such helper functions do not exist for all
objects that can appear in a container therefore some knowledge of
the naming scheme is usually necessary.