buttonbar.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /* Widgets for the Midnight Commander
  2. Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
  3. 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
  4. Authors: 1994, 1995 Radek Doulik
  5. 1994, 1995 Miguel de Icaza
  6. 1995 Jakub Jelinek
  7. 1996 Andrej Borsenkow
  8. 1997 Norbert Warmuth
  9. 2009, 2010 Andrew Borodin
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; if not, write to the Free Software
  20. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. */
  22. /** \file buttonbar.c
  23. * \brief Source: WButtonBar widget
  24. */
  25. #include <config.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include "lib/global.h"
  29. #include "lib/tty/tty.h"
  30. #include "lib/tty/mouse.h"
  31. #include "lib/tty/key.h" /* XCTRL and ALT macros */
  32. #include "lib/skin.h"
  33. #include "lib/strutil.h"
  34. #include "lib/util.h"
  35. #include "lib/keybind.h" /* global_keymap_t */
  36. #include "lib/widget.h"
  37. /*** global variables ****************************************************************************/
  38. /*** file scope macro definitions ****************************************************************/
  39. /*** file scope type declarations ****************************************************************/
  40. /*** file scope variables ************************************************************************/
  41. /*** file scope functions ************************************************************************/
  42. /* --------------------------------------------------------------------------------------------- */
  43. /* calculate positions of buttons; width is never less than 7 */
  44. static void
  45. buttonbar_init_button_positions (WButtonBar * bb)
  46. {
  47. int i;
  48. int pos = 0;
  49. if (COLS < BUTTONBAR_LABELS_NUM * 7)
  50. {
  51. for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  52. {
  53. if (pos + 7 <= COLS)
  54. pos += 7;
  55. bb->labels[i].end_coord = pos;
  56. }
  57. }
  58. else
  59. {
  60. /* Distribute the extra width in a way that the middle vertical line
  61. (between F5 and F6) aligns with the two panels. The extra width
  62. is distributed in this order: F10, F5, F9, F4, ..., F6, F1. */
  63. int dv, md;
  64. dv = COLS / BUTTONBAR_LABELS_NUM;
  65. md = COLS % BUTTONBAR_LABELS_NUM;
  66. for (i = 0; i < BUTTONBAR_LABELS_NUM / 2; i++)
  67. {
  68. pos += dv;
  69. if (BUTTONBAR_LABELS_NUM / 2 - 1 - i < md / 2)
  70. pos++;
  71. bb->labels[i].end_coord = pos;
  72. }
  73. for (; i < BUTTONBAR_LABELS_NUM; i++)
  74. {
  75. pos += dv;
  76. if (BUTTONBAR_LABELS_NUM - 1 - i < (md + 1) / 2)
  77. pos++;
  78. bb->labels[i].end_coord = pos;
  79. }
  80. }
  81. }
  82. /* --------------------------------------------------------------------------------------------- */
  83. /* return width of one button */
  84. static int
  85. buttonbar_get_button_width (const WButtonBar * bb, int i)
  86. {
  87. if (i == 0)
  88. return bb->labels[0].end_coord;
  89. return bb->labels[i].end_coord - bb->labels[i - 1].end_coord;
  90. }
  91. /* --------------------------------------------------------------------------------------------- */
  92. static int
  93. buttonbar_get_button_by_x_coord (const WButtonBar * bb, int x)
  94. {
  95. int i;
  96. for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  97. if (bb->labels[i].end_coord > x)
  98. return i;
  99. return (-1);
  100. }
  101. /* --------------------------------------------------------------------------------------------- */
  102. static void
  103. set_label_text (WButtonBar * bb, int idx, const char *text)
  104. {
  105. g_free (bb->labels[idx - 1].text);
  106. bb->labels[idx - 1].text = g_strdup (text);
  107. }
  108. /* --------------------------------------------------------------------------------------------- */
  109. /* returns TRUE if a function has been called, FALSE otherwise. */
  110. static gboolean
  111. buttonbar_call (WButtonBar * bb, int i)
  112. {
  113. cb_ret_t ret = MSG_NOT_HANDLED;
  114. if ((bb != NULL) && (bb->labels[i].command != CK_Ignore_Key))
  115. ret = bb->widget.owner->callback (bb->widget.owner,
  116. (Widget *) bb, DLG_ACTION,
  117. bb->labels[i].command, bb->labels[i].receiver);
  118. return ret;
  119. }
  120. /* --------------------------------------------------------------------------------------------- */
  121. static cb_ret_t
  122. buttonbar_callback (Widget * w, widget_msg_t msg, int parm)
  123. {
  124. WButtonBar *bb = (WButtonBar *) w;
  125. int i;
  126. const char *text;
  127. switch (msg)
  128. {
  129. case WIDGET_FOCUS:
  130. return MSG_NOT_HANDLED;
  131. case WIDGET_HOTKEY:
  132. for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  133. if (parm == KEY_F (i + 1) && buttonbar_call (bb, i))
  134. return MSG_HANDLED;
  135. return MSG_NOT_HANDLED;
  136. case WIDGET_DRAW:
  137. if (bb->visible)
  138. {
  139. buttonbar_init_button_positions (bb);
  140. widget_move (&bb->widget, 0, 0);
  141. tty_setcolor (DEFAULT_COLOR);
  142. tty_printf ("%-*s", bb->widget.cols, "");
  143. widget_move (&bb->widget, 0, 0);
  144. for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  145. {
  146. int width;
  147. width = buttonbar_get_button_width (bb, i);
  148. if (width <= 0)
  149. break;
  150. tty_setcolor (BUTTONBAR_HOTKEY_COLOR);
  151. tty_printf ("%2d", i + 1);
  152. tty_setcolor (BUTTONBAR_BUTTON_COLOR);
  153. text = (bb->labels[i].text != NULL) ? bb->labels[i].text : "";
  154. tty_print_string (str_fit_to_term (text, width - 2, J_LEFT_FIT));
  155. }
  156. }
  157. return MSG_HANDLED;
  158. case WIDGET_DESTROY:
  159. for (i = 0; i < BUTTONBAR_LABELS_NUM; i++)
  160. g_free (bb->labels[i].text);
  161. return MSG_HANDLED;
  162. default:
  163. return default_proc (msg, parm);
  164. }
  165. }
  166. /* --------------------------------------------------------------------------------------------- */
  167. static int
  168. buttonbar_event (Gpm_Event * event, void *data)
  169. {
  170. WButtonBar *bb = data;
  171. int button;
  172. if (!(event->type & GPM_UP))
  173. return MOU_NORMAL;
  174. if (event->y == 2)
  175. return MOU_NORMAL;
  176. button = buttonbar_get_button_by_x_coord (bb, event->x - 1);
  177. if (button >= 0)
  178. buttonbar_call (bb, button);
  179. return MOU_NORMAL;
  180. }
  181. /* --------------------------------------------------------------------------------------------- */
  182. /*** public functions ****************************************************************************/
  183. /* --------------------------------------------------------------------------------------------- */
  184. WButtonBar *
  185. buttonbar_new (gboolean visible)
  186. {
  187. WButtonBar *bb;
  188. bb = g_new0 (WButtonBar, 1);
  189. init_widget (&bb->widget, LINES - 1, 0, 1, COLS, buttonbar_callback, buttonbar_event);
  190. bb->widget.pos_flags = WPOS_KEEP_HORZ | WPOS_KEEP_BOTTOM;
  191. bb->visible = visible;
  192. widget_want_hotkey (bb->widget, 1);
  193. widget_want_cursor (bb->widget, 0);
  194. return bb;
  195. }
  196. /* --------------------------------------------------------------------------------------------- */
  197. void
  198. buttonbar_set_label (WButtonBar * bb, int idx, const char *text,
  199. const struct global_keymap_t *keymap, const Widget * receiver)
  200. {
  201. if ((bb != NULL) && (idx >= 1) && (idx <= BUTTONBAR_LABELS_NUM))
  202. {
  203. unsigned long command = CK_Ignore_Key;
  204. if (keymap != NULL)
  205. command = keybind_lookup_keymap_command (keymap, KEY_F (idx));
  206. if ((text == NULL) || (text[0] == '\0'))
  207. set_label_text (bb, idx, "");
  208. else
  209. set_label_text (bb, idx, text);
  210. bb->labels[idx - 1].command = command;
  211. bb->labels[idx - 1].receiver = (Widget *) receiver;
  212. }
  213. }
  214. /* --------------------------------------------------------------------------------------------- */
  215. /* Find ButtonBar widget in the dialog */
  216. WButtonBar *
  217. find_buttonbar (const Dlg_head * h)
  218. {
  219. return (WButtonBar *) find_widget_type (h, buttonbar_callback);
  220. }