anastasis-gtk

Demonstrator GUI for Anastasis
Log | Files | Refs | README | LICENSE

anastasis-gtk_cells.c (15277B)


      1 /*
      2      This file is part of anastasis-gtk.
      3      Copyright (C) 2025 Anastasis SARL
      4 
      5      Anastasis is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      Anastasis is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with Anastasis; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 */
     20 /**
     21  * @file src/anastasis/anastasis-gtk_cells.c
     22  * @brief Widgets rendering the cells of our GtkColumnViews
     23  * @author Christian Grothoff
     24  */
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include "anastasis_gtk_util.h"
     27 #include "anastasis-gtk_helper.h"
     28 #include "anastasis-gtk_rows.h"
     29 
     30 
     31 /**
     32  * Padding above and below the rows of the two progress lists.
     33  */
     34 #define PROGRESS_PADDING 15
     35 
     36 
     37 /**
     38  * Return the row the cell of @a item shows and remember it on the
     39  * widget of that cell, so that a right-click can find it again.
     40  *
     41  * @param item the cell being bound
     42  * @return NULL if @a item shows no row
     43  */
     44 static AGRow *
     45 bind_row (GtkListItem *item)
     46 {
     47   AGRow *row = AG_row_of (gtk_list_item_get_item (item));
     48   GtkWidget *child = gtk_list_item_get_child (item);
     49 
     50   if (NULL != child)
     51     AG_cell_set_row (child,
     52                      row);
     53   return row;
     54 }
     55 
     56 
     57 /**
     58  * Set the label of the cell of @a item to the @a field of its row.
     59  *
     60  * @param item the cell being bound
     61  * @param field field of the row to show
     62  */
     63 static void
     64 bind_text (GtkListItem *item,
     65            const char *field)
     66 {
     67   AGRow *row = bind_row (item);
     68   const char *val = NULL;
     69 
     70   if (NULL != row)
     71     val = AG_row_string (row,
     72                          field);
     73   gtk_label_set_text (GTK_LABEL (gtk_list_item_get_child (item)),
     74                       (NULL != val) ? val : "");
     75 }
     76 
     77 
     78 /**
     79  * Define the "bind" handler @a name of a column showing the string
     80  * @a field of the rows.  The columns of our lists differ only in the
     81  * field they show, but the UI files must name a distinct handler for
     82  * each of them.
     83  *
     84  * @param name name of the handler to define
     85  * @param field field of the row the column shows
     86  */
     87 #define TEXT_CELL(name, field)          \
     88   void                                  \
     89   name (GtkSignalListItemFactory *f,    \
     90         GtkListItem *item,              \
     91         gpointer user_data)             \
     92   {                                     \
     93     (void) f;                           \
     94     (void) user_data;                   \
     95     bind_text (item,                    \
     96                field);                  \
     97   }
     98 
     99 
    100 /**
    101  * Create the label rendering a cell of a text column.
    102  *
    103  * @param f the factory of the column
    104  * @param item the cell to fill
    105  * @param user_data the builder
    106  */
    107 void
    108 AG_cell_setup_text (GtkSignalListItemFactory *f,
    109                     GtkListItem *item,
    110                     gpointer user_data)
    111 {
    112   GtkWidget *label;
    113 
    114   (void) f;
    115   (void) user_data;
    116   label = gtk_label_new (NULL);
    117   gtk_label_set_xalign (GTK_LABEL (label),
    118                         0.0);
    119   gtk_widget_set_halign (label,
    120                          GTK_ALIGN_START);
    121   gtk_list_item_set_child (item,
    122                            label);
    123 }
    124 
    125 
    126 /**
    127  * Forget the row a cell showed once it is no longer shown.
    128  *
    129  * @param f the factory of the column
    130  * @param item the cell that was unbound
    131  * @param user_data the builder
    132  */
    133 void
    134 AG_cell_unbind (GtkSignalListItemFactory *f,
    135                 GtkListItem *item,
    136                 gpointer user_data)
    137 {
    138   GtkWidget *child = gtk_list_item_get_child (item);
    139 
    140   (void) f;
    141   (void) user_data;
    142   if (NULL != child)
    143     AG_cell_set_row (child,
    144                      NULL);
    145 }
    146 
    147 
    148 /* ****************** progress lists ******************* */
    149 
    150 
    151 /**
    152  * Create the label rendering a step of one of the progress lists.
    153  *
    154  * @param f the factory of the column
    155  * @param item the cell to fill
    156  * @param user_data the builder
    157  */
    158 void
    159 AG_cell_setup_progress (GtkSignalListItemFactory *f,
    160                         GtkListItem *item,
    161                         gpointer user_data)
    162 {
    163   GtkWidget *label;
    164 
    165   AG_cell_setup_text (f,
    166                       item,
    167                       user_data);
    168   label = gtk_list_item_get_child (item);
    169   gtk_widget_set_margin_top (label,
    170                              PROGRESS_PADDING);
    171   gtk_widget_set_margin_bottom (label,
    172                                 PROGRESS_PADDING);
    173 }
    174 
    175 
    176 /**
    177  * Show the description of a step of one of the progress lists, using the
    178  * long explanation as the tooltip.
    179  *
    180  * @param f the factory of the column
    181  * @param item the cell to fill
    182  * @param user_data the builder
    183  */
    184 void
    185 AG_cell_bind_progress (GtkSignalListItemFactory *f,
    186                        GtkListItem *item,
    187                        gpointer user_data)
    188 {
    189   AGRow *row;
    190 
    191   (void) f;
    192   (void) user_data;
    193   bind_text (item,
    194              "description");
    195   row = AG_row_of (gtk_list_item_get_item (item));
    196   if (NULL == row)
    197     return;
    198   gtk_widget_set_tooltip_text (gtk_list_item_get_child (item),
    199                                AG_row_string (row,
    200                                               "tooltip"));
    201 }
    202 
    203 
    204 /* ************ continents, countries, methods ************* */
    205 
    206 
    207 TEXT_CELL (AG_cell_bind_continent, "name_i18n")
    208 TEXT_CELL (AG_cell_bind_country, "name")
    209 TEXT_CELL (AG_cell_bind_auth_type, "type")
    210 TEXT_CELL (AG_cell_bind_auth_details, "visualization")
    211 
    212 
    213 /* ******************* policy review ******************** */
    214 
    215 
    216 /**
    217  * Create the expander and label rendering the first column of the policy
    218  * review, where the challenges are nested under their policy.
    219  *
    220  * @param f the factory of the column
    221  * @param item the cell to fill
    222  * @param user_data the builder
    223  */
    224 void
    225 AG_cell_setup_policy_name (GtkSignalListItemFactory *f,
    226                            GtkListItem *item,
    227                            gpointer user_data)
    228 {
    229   GtkWidget *expander;
    230   GtkWidget *label;
    231 
    232   (void) f;
    233   (void) user_data;
    234   label = gtk_label_new (NULL);
    235   gtk_label_set_xalign (GTK_LABEL (label),
    236                         0.0);
    237   gtk_widget_set_halign (label,
    238                          GTK_ALIGN_START);
    239   expander = gtk_tree_expander_new ();
    240   gtk_tree_expander_set_child (GTK_TREE_EXPANDER (expander),
    241                                label);
    242   gtk_list_item_set_child (item,
    243                            expander);
    244 }
    245 
    246 
    247 /**
    248  * Show the name of a policy, or the instructions of a challenge.
    249  *
    250  * @param f the factory of the column
    251  * @param item the cell to fill
    252  * @param user_data the builder
    253  */
    254 void
    255 AG_cell_bind_policy_name (GtkSignalListItemFactory *f,
    256                           GtkListItem *item,
    257                           gpointer user_data)
    258 {
    259   GtkTreeExpander *expander;
    260   GtkWidget *label;
    261   AGRow *row;
    262   const char *name = NULL;
    263 
    264   (void) f;
    265   (void) user_data;
    266   expander = GTK_TREE_EXPANDER (gtk_list_item_get_child (item));
    267   gtk_tree_expander_set_list_row (expander,
    268                                   GTK_TREE_LIST_ROW (
    269                                     gtk_list_item_get_item (item)));
    270   row = bind_row (item);
    271   if (NULL != row)
    272     name = AG_row_string (row,
    273                           "policy_name");
    274   label = gtk_tree_expander_get_child (expander);
    275   gtk_label_set_text (GTK_LABEL (label),
    276                       (NULL != name) ? name : "");
    277 }
    278 
    279 
    280 TEXT_CELL (AG_cell_bind_policy_type, "method_type")
    281 TEXT_CELL (AG_cell_bind_policy_cost, "cost")
    282 TEXT_CELL (AG_cell_bind_policy_provider, "provider_name")
    283 
    284 
    285 /* ****************** payment QR codes ******************* */
    286 
    287 
    288 /**
    289  * Create the picture rendering a QR code.
    290  *
    291  * @param f the factory of the column
    292  * @param item the cell to fill
    293  * @param user_data the builder
    294  */
    295 void
    296 AG_cell_setup_qr_image (GtkSignalListItemFactory *f,
    297                         GtkListItem *item,
    298                         gpointer user_data)
    299 {
    300   GtkWidget *picture;
    301 
    302   (void) f;
    303   (void) user_data;
    304   picture = gtk_picture_new ();
    305   /* render the QR code at its natural size */
    306   gtk_picture_set_can_shrink (GTK_PICTURE (picture),
    307                               FALSE);
    308   gtk_picture_set_content_fit (GTK_PICTURE (picture),
    309                                GTK_CONTENT_FIT_SCALE_DOWN);
    310   /* a GtkCellRendererPixbuf centred its image in the cell */
    311   gtk_widget_set_halign (picture,
    312                          GTK_ALIGN_CENTER);
    313   gtk_list_item_set_child (item,
    314                            picture);
    315 }
    316 
    317 
    318 /**
    319  * Show the QR code of a payment request.
    320  *
    321  * @param f the factory of the column
    322  * @param item the cell to fill
    323  * @param user_data the builder
    324  */
    325 void
    326 AG_cell_bind_qr_image (GtkSignalListItemFactory *f,
    327                        GtkListItem *item,
    328                        gpointer user_data)
    329 {
    330   AGRow *row = bind_row (item);
    331 
    332   (void) f;
    333   (void) user_data;
    334   gtk_picture_set_paintable (GTK_PICTURE (gtk_list_item_get_child (item)),
    335                              (NULL != row)
    336                              ? AG_row_image (row)
    337                              : NULL);
    338 }
    339 
    340 
    341 TEXT_CELL (AG_cell_bind_qr_uri, "url")
    342 
    343 
    344 /* ***************** completed backup ******************* */
    345 
    346 
    347 TEXT_CELL (AG_cell_bind_backup_provider, "provider_name")
    348 
    349 
    350 /**
    351  * Show the version of the policy stored at a provider, but only for the
    352  * providers the backup actually reached.
    353  *
    354  * @param f the factory of the column
    355  * @param item the cell to fill
    356  * @param user_data the builder
    357  */
    358 void
    359 AG_cell_bind_backup_version (GtkSignalListItemFactory *f,
    360                              GtkListItem *item,
    361                              gpointer user_data)
    362 {
    363   AGRow *row = bind_row (item);
    364   GtkWidget *label = gtk_list_item_get_child (item);
    365   char *version;
    366 
    367   (void) f;
    368   (void) user_data;
    369   if (NULL == row)
    370   {
    371     gtk_widget_set_visible (label,
    372                             FALSE);
    373     return;
    374   }
    375   GNUNET_asprintf (&version,
    376                    "%llu",
    377                    (unsigned long long) AG_row_uint (row,
    378                                                      "version"));
    379   gtk_label_set_text (GTK_LABEL (label),
    380                       version);
    381   GNUNET_free (version);
    382   gtk_widget_set_visible (label,
    383                           AG_row_bool (row,
    384                                        "success"));
    385 }
    386 
    387 
    388 /* ***************** secret selection ******************* */
    389 
    390 
    391 TEXT_CELL (AG_cell_bind_secret_name, "secret_name")
    392 TEXT_CELL (AG_cell_bind_secret_time, "date_string")
    393 
    394 
    395 /* ****************** provider list ******************** */
    396 
    397 
    398 /**
    399  * The user toggled whether a provider is to be used.
    400  *
    401  * @param button the check button of the row
    402  * @param user_data NULL
    403  */
    404 static void
    405 provider_use_toggled_cb (GtkCheckButton *button,
    406                          gpointer user_data)
    407 {
    408   AGRow *row;
    409   bool active;
    410 
    411   (void) user_data;
    412   row = AG_cell_get_row (GTK_WIDGET (button));
    413   if (NULL == row)
    414     return; /* not bound to a row (yet) */
    415   active = gtk_check_button_get_active (button);
    416   if (active == AG_row_bool (row,
    417                              "enabled"))
    418     return; /* we set the state ourselves while binding */
    419   AG_row_set (row,
    420               "enabled",
    421               json_boolean (active));
    422 }
    423 
    424 
    425 /**
    426  * Create the check button with which a provider is enabled or disabled.
    427  *
    428  * @param f the factory of the column
    429  * @param item the cell to fill
    430  * @param user_data the builder
    431  */
    432 void
    433 AG_cell_setup_provider_use (GtkSignalListItemFactory *f,
    434                             GtkListItem *item,
    435                             gpointer user_data)
    436 {
    437   GtkWidget *check;
    438 
    439   (void) f;
    440   (void) user_data;
    441   check = gtk_check_button_new ();
    442   gtk_widget_set_halign (check,
    443                          GTK_ALIGN_CENTER);
    444   g_signal_connect (check,
    445                     "toggled",
    446                     G_CALLBACK (&provider_use_toggled_cb),
    447                     NULL);
    448   gtk_list_item_set_child (item,
    449                            check);
    450 }
    451 
    452 
    453 /**
    454  * Show whether a provider is to be used.  Providers we could not talk to
    455  * cannot be enabled, which is shown as an indeterminate state.
    456  *
    457  * @param f the factory of the column
    458  * @param item the cell to fill
    459  * @param user_data the builder
    460  */
    461 void
    462 AG_cell_bind_provider_use (GtkSignalListItemFactory *f,
    463                            GtkListItem *item,
    464                            gpointer user_data)
    465 {
    466   GtkCheckButton *check;
    467   AGRow *row;
    468 
    469   (void) f;
    470   (void) user_data;
    471   /* the row must be known before we change the state, or the "toggled"
    472      handler cannot tell our own change from the user's */
    473   row = bind_row (item);
    474   check = GTK_CHECK_BUTTON (gtk_list_item_get_child (item));
    475   if (NULL == row)
    476     return;
    477   gtk_check_button_set_active (check,
    478                                AG_row_bool (row,
    479                                             "enabled"));
    480   gtk_check_button_set_inconsistent (check,
    481                                      ! AG_row_bool (row,
    482                                                     "sensitive"));
    483   gtk_widget_set_sensitive (GTK_WIDGET (check),
    484                             AG_row_bool (row,
    485                                          "sensitive"));
    486 }
    487 
    488 
    489 TEXT_CELL (AG_cell_bind_provider_name, "name")
    490 
    491 
    492 /**
    493  * Show the liability limit of a provider, which we only know for the
    494  * providers we could talk to.
    495  *
    496  * @param f the factory of the column
    497  * @param item the cell to fill
    498  * @param user_data the builder
    499  */
    500 void
    501 AG_cell_bind_provider_liability (GtkSignalListItemFactory *f,
    502                                  GtkListItem *item,
    503                                  gpointer user_data)
    504 {
    505   AGRow *row;
    506 
    507   (void) f;
    508   (void) user_data;
    509   bind_text (item,
    510              "liability");
    511   row = AG_row_of (gtk_list_item_get_item (item));
    512   gtk_widget_set_visible (gtk_list_item_get_child (item),
    513                           (NULL != row) &&
    514                           AG_row_bool (row,
    515                                        "sensitive"));
    516 }
    517 
    518 
    519 /**
    520  * Show the status of a provider in the colour that goes with it.
    521  *
    522  * @param f the factory of the column
    523  * @param item the cell to fill
    524  * @param user_data the builder
    525  */
    526 void
    527 AG_cell_bind_provider_status (GtkSignalListItemFactory *f,
    528                               GtkListItem *item,
    529                               gpointer user_data)
    530 {
    531   AGRow *row = bind_row (item);
    532   GtkLabel *label = GTK_LABEL (gtk_list_item_get_child (item));
    533   const char *status;
    534   const char *color;
    535 
    536   (void) f;
    537   (void) user_data;
    538   status = (NULL != row)
    539            ? AG_row_string (row,
    540                             "status")
    541            : NULL;
    542   if (NULL == status)
    543   {
    544     gtk_label_set_text (label,
    545                         "");
    546     return;
    547   }
    548   color = AG_row_string (row,
    549                          "color");
    550   if (NULL == color)
    551   {
    552     gtk_label_set_text (label,
    553                         status);
    554     return;
    555   }
    556   {
    557     char *markup;
    558 
    559     markup = g_markup_printf_escaped ("<span foreground=\"%s\">%s</span>",
    560                                       color,
    561                                       status);
    562     gtk_label_set_markup (label,
    563                           markup);
    564     g_free (markup);
    565   }
    566 }
    567 
    568 
    569 /* end of anastasis-gtk_cells.c */