root/lib/widget/buttonbar.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. buttonbar_init_button_positions
  2. buttonbar_get_button_width
  3. buttonbar_get_button_by_x_coord
  4. set_label_text
  5. buttonbar_call
  6. buttonbar_callback
  7. buttonbar_mouse_callback
  8. buttonbar_new
  9. buttonbar_set_label
  10. buttonbar_find

   1 /*
   2    Widgets for the Midnight Commander
   3 
   4    Copyright (C) 1994-2024
   5    Free Software Foundation, Inc.
   6 
   7    Authors:
   8    Radek Doulik, 1994, 1995
   9    Miguel de Icaza, 1994, 1995
  10    Jakub Jelinek, 1995
  11    Andrej Borsenkow, 1996
  12    Norbert Warmuth, 1997
  13    Andrew Borodin <aborodin@vmail.ru>, 2009-2022
  14 
  15    This file is part of the Midnight Commander.
  16 
  17    The Midnight Commander is free software: you can redistribute it
  18    and/or modify it under the terms of the GNU General Public License as
  19    published by the Free Software Foundation, either version 3 of the License,
  20    or (at your option) any later version.
  21 
  22    The Midnight Commander is distributed in the hope that it will be useful,
  23    but WITHOUT ANY WARRANTY; without even the implied warranty of
  24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25    GNU General Public License for more details.
  26 
  27    You should have received a copy of the GNU General Public License
  28    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  29  */
  30 
  31 /** \file buttonbar.c
  32  *  \brief Source: WButtonBar widget
  33  */
  34 
  35 #include <config.h>
  36 
  37 #include <stdlib.h>
  38 #include <string.h>
  39 
  40 #include "lib/global.h"
  41 
  42 #include "lib/tty/tty.h"
  43 #include "lib/tty/key.h"        /* XCTRL and ALT macros  */
  44 #include "lib/skin.h"
  45 #include "lib/strutil.h"
  46 #include "lib/util.h"
  47 #include "lib/widget.h"
  48 
  49 /*** global variables ****************************************************************************/
  50 
  51 /*** file scope macro definitions ****************************************************************/
  52 
  53 /*** file scope type declarations ****************************************************************/
  54 
  55 /*** forward declarations (file scope functions) *************************************************/
  56 
  57 /*** file scope variables ************************************************************************/
  58 
  59 /* --------------------------------------------------------------------------------------------- */
  60 /*** file scope functions ************************************************************************/
  61 /* --------------------------------------------------------------------------------------------- */
  62 
  63 /* calculate positions of buttons; width is never less than 7 */
  64 static void
  65 buttonbar_init_button_positions (WButtonBar *bb)
     /* [previous][next][first][last][top][bottom][index][help]  */
  66 {
  67     int i;
  68     int pos = 0;
  69 
  70     if (COLS < BUTTONBAR_LABELS_NUM * 7)
  71     {
  72         for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  73         {
  74             if (pos + 7 <= COLS)
  75                 pos += 7;
  76 
  77             bb->labels[i].end_coord = pos;
  78         }
  79     }
  80     else
  81     {
  82         /* Distribute the extra width in a way that the middle vertical line
  83            (between F5 and F6) aligns with the two panels. The extra width
  84            is distributed in this order: F10, F5, F9, F4, ..., F6, F1. */
  85         int dv, md;
  86 
  87         dv = COLS / BUTTONBAR_LABELS_NUM;
  88         md = COLS % BUTTONBAR_LABELS_NUM;
  89 
  90         for (i = 0; i < BUTTONBAR_LABELS_NUM / 2; i++)
  91         {
  92             pos += dv;
  93             if (BUTTONBAR_LABELS_NUM / 2 - 1 - i < md / 2)
  94                 pos++;
  95 
  96             bb->labels[i].end_coord = pos;
  97         }
  98 
  99         for (; i < BUTTONBAR_LABELS_NUM; i++)
 100         {
 101             pos += dv;
 102             if (BUTTONBAR_LABELS_NUM - 1 - i < (md + 1) / 2)
 103                 pos++;
 104 
 105             bb->labels[i].end_coord = pos;
 106         }
 107     }
 108 }
 109 
 110 /* --------------------------------------------------------------------------------------------- */
 111 
 112 /* return width of one button */
 113 static int
 114 buttonbar_get_button_width (const WButtonBar *bb, int i)
     /* [previous][next][first][last][top][bottom][index][help]  */
 115 {
 116     if (i == 0)
 117         return bb->labels[0].end_coord;
 118     return bb->labels[i].end_coord - bb->labels[i - 1].end_coord;
 119 }
 120 
 121 /* --------------------------------------------------------------------------------------------- */
 122 
 123 static int
 124 buttonbar_get_button_by_x_coord (const WButtonBar *bb, int x)
     /* [previous][next][first][last][top][bottom][index][help]  */
 125 {
 126     int i;
 127 
 128     for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
 129         if (bb->labels[i].end_coord > x)
 130             return i;
 131 
 132     return (-1);
 133 }
 134 
 135 /* --------------------------------------------------------------------------------------------- */
 136 
 137 static void
 138 set_label_text (WButtonBar *bb, int idx, const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 139 {
 140     g_free (bb->labels[idx - 1].text);
 141     bb->labels[idx - 1].text = g_strdup (text);
 142 }
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 
 146 /* returns TRUE if a function has been called, FALSE otherwise. */
 147 static gboolean
 148 buttonbar_call (WButtonBar *bb, int i)
     /* [previous][next][first][last][top][bottom][index][help]  */
 149 {
 150     cb_ret_t ret = MSG_NOT_HANDLED;
 151     Widget *w = WIDGET (bb);
 152     Widget *target;
 153 
 154     if ((bb != NULL) && (bb->labels[i].command != CK_IgnoreKey))
 155     {
 156         target = (bb->labels[i].receiver != NULL) ? bb->labels[i].receiver : WIDGET (w->owner);
 157         ret = send_message (target, w, MSG_ACTION, bb->labels[i].command, NULL);
 158     }
 159     return ret;
 160 }
 161 
 162 /* --------------------------------------------------------------------------------------------- */
 163 
 164 static cb_ret_t
 165 buttonbar_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 166 {
 167     WButtonBar *bb = BUTTONBAR (w);
 168     int i;
 169 
 170     switch (msg)
 171     {
 172     case MSG_HOTKEY:
 173         for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
 174             if (parm == KEY_F (i + 1) && buttonbar_call (bb, i))
 175                 return MSG_HANDLED;
 176         return MSG_NOT_HANDLED;
 177 
 178     case MSG_DRAW:
 179         if (widget_get_state (w, WST_VISIBLE))
 180         {
 181             buttonbar_init_button_positions (bb);
 182             widget_gotoyx (w, 0, 0);
 183             tty_setcolor (DEFAULT_COLOR);
 184             tty_printf ("%-*s", w->rect.cols, "");
 185             widget_gotoyx (w, 0, 0);
 186 
 187             for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
 188             {
 189                 int width;
 190                 const char *text;
 191 
 192                 width = buttonbar_get_button_width (bb, i);
 193                 if (width <= 0)
 194                     break;
 195 
 196                 tty_setcolor (BUTTONBAR_HOTKEY_COLOR);
 197                 tty_printf ("%2d", i + 1);
 198 
 199                 tty_setcolor (BUTTONBAR_BUTTON_COLOR);
 200                 text = (bb->labels[i].text != NULL) ? bb->labels[i].text : "";
 201                 tty_print_string (str_fit_to_term (text, width - 2, J_LEFT_FIT));
 202             }
 203         }
 204         return MSG_HANDLED;
 205 
 206     case MSG_DESTROY:
 207         for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
 208             g_free (bb->labels[i].text);
 209         return MSG_HANDLED;
 210 
 211     default:
 212         return widget_default_callback (w, sender, msg, parm, data);
 213     }
 214 }
 215 
 216 /* --------------------------------------------------------------------------------------------- */
 217 
 218 static void
 219 buttonbar_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 220 {
 221     switch (msg)
 222     {
 223     case MSG_MOUSE_CLICK:
 224         {
 225             WButtonBar *bb = BUTTONBAR (w);
 226             int button;
 227 
 228             button = buttonbar_get_button_by_x_coord (bb, event->x);
 229             if (button >= 0)
 230                 buttonbar_call (bb, button);
 231             break;
 232         }
 233 
 234     default:
 235         break;
 236     }
 237 }
 238 
 239 /* --------------------------------------------------------------------------------------------- */
 240 /*** public functions ****************************************************************************/
 241 /* --------------------------------------------------------------------------------------------- */
 242 
 243 WButtonBar *
 244 buttonbar_new (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 245 {
 246     WRect r = { LINES - 1, 0, 1, COLS };
 247     WButtonBar *bb;
 248     Widget *w;
 249 
 250     bb = g_new0 (WButtonBar, 1);
 251     w = WIDGET (bb);
 252     widget_init (w, &r, buttonbar_callback, buttonbar_mouse_callback);
 253 
 254     w->pos_flags = WPOS_KEEP_HORZ | WPOS_KEEP_BOTTOM;
 255     w->options |= WOP_WANT_HOTKEY;
 256 
 257     return bb;
 258 }
 259 
 260 /* --------------------------------------------------------------------------------------------- */
 261 
 262 void
 263 buttonbar_set_label (WButtonBar *bb, int idx, const char *text, const global_keymap_t *keymap,
     /* [previous][next][first][last][top][bottom][index][help]  */
 264                      Widget *receiver)
 265 {
 266     if ((bb != NULL) && (idx >= 1) && (idx <= BUTTONBAR_LABELS_NUM))
 267     {
 268         long command = CK_IgnoreKey;
 269 
 270         if (keymap != NULL)
 271             command = keybind_lookup_keymap_command (keymap, KEY_F (idx));
 272 
 273         if ((text == NULL) || (text[0] == '\0'))
 274             set_label_text (bb, idx, "");
 275         else
 276             set_label_text (bb, idx, text);
 277 
 278         bb->labels[idx - 1].command = command;
 279         bb->labels[idx - 1].receiver = WIDGET (receiver);
 280     }
 281 }
 282 
 283 /* --------------------------------------------------------------------------------------------- */
 284 
 285 /* Find ButtonBar widget in the dialog */
 286 WButtonBar *
 287 buttonbar_find (const WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 288 {
 289     return BUTTONBAR (widget_find_by_type (CONST_WIDGET (h), buttonbar_callback));
 290 }

/* [previous][next][first][last][top][bottom][index][help]  */