scrollbar.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. Widgets for the Midnight Commander: scrollbar
  3. Copyright (C) 2014
  4. The Free Software Foundation, Inc.
  5. Authors:
  6. Slava Zanko <slavazanko@gmail.com>, 2014
  7. This file is part of the Midnight Commander.
  8. The Midnight Commander is free software: you can redistribute it
  9. and/or modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation, either version 3 of the License,
  11. or (at your option) any later version.
  12. The Midnight Commander is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /** \file scrollbar.c
  20. * \brief Source: WScrollBar widget
  21. */
  22. #include <config.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "lib/global.h"
  26. #include "lib/tty/tty.h"
  27. #include "lib/tty/color.h"
  28. #include "lib/skin.h"
  29. #include "lib/strutil.h"
  30. #include "lib/widget.h"
  31. /*** global variables ****************************************************************************/
  32. /*** file scope macro definitions ****************************************************************/
  33. #define SKIN_GROUP_NAME "widget-scrollbar"
  34. /*** file scope type declarations ****************************************************************/
  35. /*** file scope variables ************************************************************************/
  36. static struct
  37. {
  38. char *current_char;
  39. char *first_vert_char;
  40. char *last_vert_char;
  41. char *background_vert_char;
  42. char *first_horiz_char;
  43. char *last_horiz_char;
  44. char *background_horiz_char;
  45. } scrollbar_skin;
  46. /* --------------------------------------------------------------------------------------------- */
  47. /*** file scope functions ************************************************************************/
  48. /* --------------------------------------------------------------------------------------------- */
  49. static void
  50. scrollbar_set_size (WScrollBar * scrollbar)
  51. {
  52. Widget *w = WIDGET (scrollbar);
  53. Widget *p = scrollbar->parent;
  54. Widget *o = WIDGET (p->owner);
  55. int py = p->y;
  56. int px = p->x;
  57. /* There folloing cases are possible here:
  58. 1. Parent is in dialog, scrollbar isn't.
  59. Parents coordinates are absolute. Scrollbar's coordinate are relative to owner.
  60. We need relative parent's coordinates here to place scrollbar properly.
  61. 2. Parent and scrollbar are in dialog.
  62. Parent's and scrollbar's coordinates are absolute. Use them.
  63. 3. Parent and scrollbar aren't in dialog.
  64. Parent's and scrollbar's coordinates are relative to owner. Use them.
  65. 4. Parent isn't in dialog, scrollbar is.
  66. This is abnormal and should not happen. */
  67. if (o != NULL && w->owner == NULL)
  68. {
  69. /* Get relative parent's coordinates */
  70. py -= o->y;
  71. px -= o->x;
  72. }
  73. switch (scrollbar->type)
  74. {
  75. case SCROLLBAR_VERTICAL:
  76. w->y = py;
  77. w->x = px + p->cols;
  78. w->lines = p->lines;
  79. w->cols = 1;
  80. break;
  81. default:
  82. w->x = px;
  83. w->y = py + p->lines;
  84. w->cols = p->cols;
  85. w->lines = 1;
  86. break;
  87. }
  88. }
  89. /* --------------------------------------------------------------------------------------------- */
  90. static void
  91. scrollbar_draw_horizontal (WScrollBar * scrollbar)
  92. {
  93. Widget *w = WIDGET (scrollbar);
  94. int column = 0;
  95. int i;
  96. int start_pos = 0;
  97. int end_pos = w->cols - 1;
  98. int total_columns = w->cols;
  99. if (scrollbar_skin.first_horiz_char != NULL)
  100. {
  101. start_pos++;
  102. total_columns--;
  103. widget_move (w, 0, 0);
  104. tty_print_string (scrollbar_skin.first_horiz_char);
  105. }
  106. if (scrollbar_skin.last_horiz_char != NULL)
  107. {
  108. end_pos--;
  109. total_columns--;
  110. widget_move (w, 0, w->cols - 1);
  111. tty_print_string (scrollbar_skin.last_horiz_char);
  112. }
  113. /* Now draw the nice relative pointer */
  114. if (*scrollbar->total != 0)
  115. column = *scrollbar->current * total_columns / *scrollbar->total + start_pos;
  116. for (i = start_pos; i <= end_pos; i++)
  117. {
  118. widget_move (w, 0, i);
  119. if (i != column)
  120. tty_print_string (scrollbar_skin.background_horiz_char);
  121. else
  122. tty_print_string (scrollbar_skin.current_char);
  123. }
  124. }
  125. /* --------------------------------------------------------------------------------------------- */
  126. static void
  127. scrollbar_draw_vertical (WScrollBar * scrollbar)
  128. {
  129. Widget *w = WIDGET (scrollbar);
  130. int line = 0;
  131. int i;
  132. int start_pos = 0;
  133. int end_pos = w->lines - 1;
  134. int total_lines = w->lines;
  135. if (scrollbar_skin.first_vert_char != NULL)
  136. {
  137. start_pos++;
  138. total_lines--;
  139. widget_move (w, 0, 0);
  140. tty_print_string (scrollbar_skin.first_vert_char);
  141. }
  142. if (scrollbar_skin.last_vert_char != NULL)
  143. {
  144. end_pos--;
  145. total_lines--;
  146. widget_move (w, w->lines - 1, 0);
  147. tty_print_string (scrollbar_skin.last_vert_char);
  148. }
  149. /* Now draw the nice relative pointer */
  150. if (*scrollbar->total != 0)
  151. line = *scrollbar->current * total_lines / *scrollbar->total + start_pos;
  152. for (i = start_pos; i <= end_pos; i++)
  153. {
  154. widget_move (w, i, 0);
  155. if (i != line)
  156. tty_print_string (scrollbar_skin.background_vert_char);
  157. else
  158. tty_print_string (scrollbar_skin.current_char);
  159. }
  160. }
  161. /* --------------------------------------------------------------------------------------------- */
  162. static void
  163. scrollbar_draw (WScrollBar * scrollbar)
  164. {
  165. const int normalc = DISABLED_COLOR;
  166. if (*scrollbar->total <= scrollbar->parent->lines)
  167. return;
  168. tty_setcolor (normalc);
  169. switch (scrollbar->type)
  170. {
  171. case SCROLLBAR_VERTICAL:
  172. scrollbar_draw_vertical (scrollbar);
  173. break;
  174. default:
  175. scrollbar_draw_horizontal (scrollbar);
  176. }
  177. }
  178. /* --------------------------------------------------------------------------------------------- */
  179. static cb_ret_t
  180. scrollbar_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
  181. {
  182. WScrollBar *scrollbar = SCROLLBAR (w);
  183. cb_ret_t ret = MSG_HANDLED;
  184. switch (msg)
  185. {
  186. case MSG_INIT:
  187. // w->pos_flags = WPOS_KEEP_RIGHT | WPOS_KEEP_BOTTOM;
  188. return MSG_HANDLED;
  189. case MSG_RESIZE:
  190. scrollbar_set_size (scrollbar);
  191. return MSG_HANDLED;
  192. case MSG_FOCUS:
  193. return MSG_NOT_HANDLED;
  194. case MSG_ACTION:
  195. ret = MSG_NOT_HANDLED;
  196. case MSG_DRAW:
  197. scrollbar_draw (scrollbar);
  198. return ret;
  199. case MSG_DESTROY:
  200. return MSG_HANDLED;
  201. default:
  202. return widget_default_callback (w, sender, msg, parm, data);
  203. }
  204. }
  205. /* --------------------------------------------------------------------------------------------- */
  206. /*** public functions ****************************************************************************/
  207. /* --------------------------------------------------------------------------------------------- */
  208. /**
  209. * Create new WScrollBar object.
  210. *
  211. * @param parent parent widget
  212. * @param type type of scrollbar (vertical or horizontal)
  213. * @return new WScrollBar object
  214. */
  215. WScrollBar *
  216. scrollbar_new (Widget * parent, scrollbar_type_t type)
  217. {
  218. WScrollBar *scrollbar;
  219. Widget *widget;
  220. scrollbar = g_new (WScrollBar, 1);
  221. scrollbar->type = type;
  222. widget = WIDGET (scrollbar);
  223. widget_init (widget, 1, 1, 1, 1, scrollbar_callback, NULL);
  224. scrollbar->parent = parent;
  225. scrollbar_set_size (scrollbar);
  226. widget_want_cursor (widget, FALSE);
  227. widget_want_hotkey (widget, FALSE);
  228. return scrollbar;
  229. }
  230. /* --------------------------------------------------------------------------------------------- */
  231. /**
  232. * Set total count of items.
  233. *
  234. * @param scrollbar WScrollBar object
  235. * @param total total count of items
  236. */
  237. void
  238. scrollbar_set_total (WScrollBar * scrollbar, int *total)
  239. {
  240. if (scrollbar != NULL)
  241. scrollbar->total = total;
  242. }
  243. /* --------------------------------------------------------------------------------------------- */
  244. /**
  245. * Set current position of item.
  246. *
  247. * @param scrollbar WScrollBar object
  248. * @param current current position of item
  249. */
  250. void
  251. scrollbar_set_current (WScrollBar * scrollbar, int *current)
  252. {
  253. if (scrollbar != NULL)
  254. scrollbar->current = current;
  255. }
  256. /* --------------------------------------------------------------------------------------------- */
  257. /**
  258. * Set position of first displayed item.
  259. *
  260. * @param scrollbar WScrollBar object
  261. * @param first_displayed position of first displayed item
  262. */
  263. void
  264. scrollbar_set_first_displayed (WScrollBar * scrollbar, int *first_displayed)
  265. {
  266. if (scrollbar != NULL)
  267. scrollbar->first_displayed = first_displayed;
  268. }
  269. /* --------------------------------------------------------------------------------------------- */
  270. /**
  271. * Initialize scrollbars.
  272. */
  273. void
  274. scrollbar_global_init (void)
  275. {
  276. scrollbar_skin.current_char = mc_skin_get (SKIN_GROUP_NAME, "current-char", "*");
  277. scrollbar_skin.first_vert_char = mc_skin_get (SKIN_GROUP_NAME, "first-vert-char", NULL);
  278. scrollbar_skin.last_vert_char = mc_skin_get (SKIN_GROUP_NAME, "last-vert-char", NULL);
  279. scrollbar_skin.background_vert_char =
  280. mc_skin_get (SKIN_GROUP_NAME, "background-vert-char", "|");
  281. scrollbar_skin.first_horiz_char = mc_skin_get (SKIN_GROUP_NAME, "first-horiz-char", NULL);
  282. scrollbar_skin.last_horiz_char = mc_skin_get (SKIN_GROUP_NAME, "last-horiz-char", NULL);
  283. scrollbar_skin.background_horiz_char =
  284. mc_skin_get (SKIN_GROUP_NAME, "background-horiz-char", "-");
  285. }
  286. /* --------------------------------------------------------------------------------------------- */
  287. /**
  288. * Deinitialize scrollbars.
  289. */
  290. void
  291. scrollbar_global_deinit (void)
  292. {
  293. g_free (scrollbar_skin.current_char);
  294. g_free (scrollbar_skin.first_vert_char);
  295. g_free (scrollbar_skin.last_vert_char);
  296. g_free (scrollbar_skin.background_vert_char);
  297. g_free (scrollbar_skin.first_horiz_char);
  298. g_free (scrollbar_skin.last_horiz_char);
  299. g_free (scrollbar_skin.background_horiz_char);
  300. }
  301. /* --------------------------------------------------------------------------------------------- */