NeoMutt  2021-10-29-43-g6b8931
Teaching an old dog new tricks
DOXYGEN
move.c
Go to the documentation of this file.
1 
51 #include "config.h"
52 #include <stddef.h>
53 #include <stdbool.h>
54 #include "mutt/lib.h"
55 #include "config/lib.h"
56 #include "gui/lib.h"
57 #include "lib.h"
58 
66 MenuRedrawFlags menu_set_and_notify(struct Menu *menu, int top, int index)
67 {
69 
70  if (top != menu->top)
71  {
72  menu->top = top;
73  flags |= MENU_REDRAW_FULL;
74  }
75 
76  if (index != menu->current)
77  {
78  menu->oldcurrent = menu->current;
79  menu->current = index;
80 
81  if (menu->redraw == MENU_REDRAW_NO_FLAGS)
82  {
83  // If this is the only change
84  flags |= MENU_REDRAW_MOTION;
85  }
86  else
87  {
88  // otherwise, redraw completely
89  flags |= MENU_REDRAW_FULL;
90  }
91  }
92 
93  menu->redraw |= flags;
94  menu->win->actions |= WA_REPAINT;
95 
96  mutt_debug(LL_NOTIFY, "NT_MENU\n");
97  notify_send(menu->notify, NT_MENU, flags, NULL);
98  return flags;
99 }
100 
107 static int menu_drag_view(struct Menu *menu, int top, int index)
108 {
109  if (menu->max <= menu->pagelen) // fewer entries than lines
110  return 0;
111 
112  const int page = menu->pagelen;
113 
114  short context = cs_subset_number(menu->sub, "menu_context");
115  context = MIN(context, (page / 2));
116 
117  const bool c_menu_scroll = cs_subset_bool(menu->sub, "menu_scroll");
118  if (c_menu_scroll)
119  {
120  int bottom = top + page;
121  // Scroll the view to make the selection visible
122  if (index < top + context) // scroll=YES, moving UP
123  top = index - context;
124  else if (index >= (bottom - context)) // scroll=YES, moving DOWN
125  top = index - page + context + 1;
126  }
127  else
128  {
129  if ((index < top) || (index >= (top + page)))
130  top = (index / page) * page; // Round down to a page size
131  int bottom = top + page;
132 
133  // Page up/down to make the selection visible
134  if (index < (top + context)) // scroll=NO, moving UP
135  top = index - page + context + 1;
136  else if (index >= (bottom - context)) // scroll=NO, moving DOWN
137  top = index - context;
138  }
139 
140  if (top < 0)
141  top = 0;
142 
143  // Tie the last entry to the bottom of the screen
144  const bool c_menu_move_off = cs_subset_bool(menu->sub, "menu_move_off");
145  if (!c_menu_move_off && (top >= (menu->max - page)))
146  {
147  top = menu->max - page;
148  }
149 
150  return top;
151 }
152 
159 static int calc_fit_selection_to_view(struct Menu *menu, int top, int index)
160 {
161  short context = cs_subset_number(menu->sub, "menu_context");
162  context = MIN(context, (menu->pagelen / 2));
163 
164  int min = top;
165  if (top != 0)
166  min += context;
167 
168  int max = top + menu->pagelen - 1;
169  if (max < (menu->max - 1))
170  max -= context;
171  else
172  max = menu->max - 1;
173 
174  if (index < min)
175  index = min;
176  else if (index > max)
177  index = max;
178 
179  return index;
180 }
181 
187 static int calc_move_view(struct Menu *menu, int relative)
188 {
189  if (menu->max <= menu->pagelen) // fewer entries than lines
190  return 0;
191 
192  short context = cs_subset_number(menu->sub, "menu_context");
193  context = MIN(context, (menu->pagelen / 2));
194 
195  int index = menu->current;
196  if (index < context)
197  return 0;
198 
199  int top = menu->top + relative;
200  if (top < 0)
201  return 0;
202 
203  if ((menu->top + menu->pagelen) < menu->max)
204  return top;
205 
206  int max = menu->max - 1;
207  const bool c_menu_move_off = cs_subset_bool(menu->sub, "menu_move_off");
208  if (c_menu_move_off)
209  {
210  max -= context;
211  }
212  else
213  {
214  max -= menu->pagelen - 1;
215  }
216 
217  if (top > max)
218  top = max;
219 
220  return top;
221 }
222 
228 MenuRedrawFlags menu_move_selection(struct Menu *menu, int index)
229 {
230  if (index < 0)
231  index = 0;
232  else if (index >= menu->max)
233  index = menu->max - 1;
234 
235  int top = menu_drag_view(menu, menu->top, index);
236 
237  return menu_set_and_notify(menu, top, index);
238 }
239 
245 MenuRedrawFlags menu_move_view_relative(struct Menu *menu, int relative)
246 {
247  const bool c_menu_move_off = cs_subset_bool(menu->sub, "menu_move_off");
248 
249  short context = cs_subset_number(menu->sub, "menu_context");
250  context = MIN(context, (menu->pagelen / 2));
251 
252  // Move and range-check the view
253  int top = menu->top + relative;
254  if (top < 0)
255  {
256  top = 0;
257  }
258  else if (c_menu_move_off && (top >= (menu->max - context)))
259  {
260  top = menu->max - context - 1;
261  }
262  else if (!c_menu_move_off && ((top + menu->pagelen) >= menu->max))
263  {
264  top = menu->max - menu->pagelen;
265  }
266 
267  // Move the selection on-screen
268  int index = menu->current;
269  if (index < top)
270  index = top;
271  else if (index >= (top + menu->pagelen))
272  index = top + menu->pagelen - 1;
273 
274  // Check for top/bottom limits
275  if (index < context)
276  {
277  top = 0;
278  index = menu->current;
279  }
280  else if (!c_menu_move_off && (index > (menu->max - context)))
281  {
282  top = menu->max - menu->pagelen;
283  index = menu->current;
284  }
285 
286  if (top == menu->top)
287  {
288  // Can't move the view; move the selection
289  index = calc_fit_selection_to_view(menu, top, index + relative);
290  }
291  else if (index > (top + menu->pagelen - context - 1))
292  {
293  index = calc_fit_selection_to_view(menu, top, index + relative);
294  }
295  else
296  {
297  // Drag the selection into the view
298  index = calc_fit_selection_to_view(menu, top, index);
299  }
300 
301  return menu_set_and_notify(menu, top, index);
302 }
303 
308 void menu_adjust(struct Menu *menu)
309 {
310  int top = calc_move_view(menu, 0);
311  top = menu_drag_view(menu, top, menu->current);
312 
313  menu_set_and_notify(menu, top, menu->current);
314 }
315 
316 // These functions move the selection (and may cause the view to move)
323 {
324  return menu_move_selection(menu, menu->top);
325 }
326 
333 {
334  if (menu->max == 0)
335  {
336  mutt_error(_("No entries"));
337  return MENU_REDRAW_NO_FLAGS;
338  }
339 
340  int i = menu->top + menu->pagelen;
341  if (i > (menu->max - 1))
342  i = menu->max - 1;
343 
344  return menu_move_selection(menu, menu->top + (i - menu->top) / 2);
345 }
346 
353 {
354  if (menu->max == 0)
355  {
356  mutt_error(_("No entries"));
357  return MENU_REDRAW_NO_FLAGS;
358  }
359 
360  int index = menu->top + menu->pagelen - 1;
361  if (index > (menu->max - 1))
362  index = menu->max - 1;
363  return menu_move_selection(menu, index);
364 }
365 
372 {
373  if (menu->current > 0)
374  return menu_move_selection(menu, menu->current - 1);
375 
376  mutt_message(_("You are on the first entry"));
377  return MENU_REDRAW_NO_FLAGS;
378 }
379 
386 {
387  if (menu->current < (menu->max - 1))
388  return menu_move_selection(menu, menu->current + 1);
389 
390  mutt_message(_("You are on the last entry"));
391  return MENU_REDRAW_NO_FLAGS;
392 }
393 
400 {
401  if (menu->max == 0)
402  {
403  mutt_error(_("No entries"));
404  return MENU_REDRAW_NO_FLAGS;
405  }
406 
407  return menu_move_selection(menu, 0);
408 }
409 
416 {
417  if (menu->max == 0)
418  {
419  mutt_error(_("No entries"));
420  return MENU_REDRAW_NO_FLAGS;
421  }
422 
423  return menu_move_selection(menu, menu->max - 1);
424 }
425 
426 // These functions move the view (and may cause the selection to move)
433 {
434  if (menu->max == 0)
435  {
436  mutt_error(_("No entries"));
437  return MENU_REDRAW_NO_FLAGS;
438  }
439 
440  short context = cs_subset_number(menu->sub, "menu_context");
441  if (context > (menu->pagelen / 2))
442  return MENU_REDRAW_NO_FLAGS;
443 
444  context = MIN(context, (menu->pagelen / 2));
445  return menu_move_view_relative(menu, menu->current - menu->top - context);
446 }
447 
454 {
455  if (menu->max == 0)
456  {
457  mutt_error(_("No entries"));
458  return MENU_REDRAW_NO_FLAGS;
459  }
460 
461  short context = cs_subset_number(menu->sub, "menu_context");
462  if (context > (menu->pagelen / 2))
463  return MENU_REDRAW_NO_FLAGS;
464 
465  return menu_move_view_relative(menu, menu->current - (menu->top + (menu->pagelen / 2)));
466 }
467 
474 {
475  if (menu->max == 0)
476  {
477  mutt_error(_("No entries"));
478  return MENU_REDRAW_NO_FLAGS;
479  }
480 
481  short context = cs_subset_number(menu->sub, "menu_context");
482  if (context > (menu->pagelen / 2))
483  return MENU_REDRAW_NO_FLAGS;
484 
485  context = MIN(context, (menu->pagelen / 2));
487  menu, 0 - (menu->top + menu->pagelen - 1 - menu->current - context));
488 }
489 
496 {
497  return menu_move_view_relative(menu, 0 - (menu->pagelen / 2));
498 }
499 
506 {
507  return menu_move_view_relative(menu, (menu->pagelen / 2));
508 }
509 
516 {
517  MenuRedrawFlags flags = menu_move_view_relative(menu, -1);
518  if (flags == MENU_REDRAW_NO_FLAGS)
519  mutt_message(_("You can't scroll up farther"));
520  return flags;
521 }
522 
529 {
530  MenuRedrawFlags flags = menu_move_view_relative(menu, 1);
531  if (flags == MENU_REDRAW_NO_FLAGS)
532  mutt_message(_("You can't scroll down farther"));
533  return flags;
534 }
535 
542 {
543  return menu_move_view_relative(menu, 0 - menu->pagelen);
544 }
545 
552 {
553  return menu_move_view_relative(menu, menu->pagelen);
554 }
Convenience wrapper for the config headers.
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
Convenience wrapper for the gui headers.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
#define MIN(a, b)
Definition: memory.h:31
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:55
#define MENU_REDRAW_NO_FLAGS
No flags are set.
Definition: lib.h:51
uint8_t MenuRedrawFlags
Flags, e.g. MENU_REDRAW_INDEX.
Definition: lib.h:48
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:53
MenuRedrawFlags menu_next_page(struct Menu *menu)
Move the focus to the next page in the menu.
Definition: move.c:551
MenuRedrawFlags menu_bottom_page(struct Menu *menu)
Move the focus to the bottom of the page.
Definition: move.c:352
void menu_adjust(struct Menu *menu)
Reapply the config to the Menu.
Definition: move.c:308
MenuRedrawFlags menu_half_up(struct Menu *menu)
Move the focus up half a page in the menu.
Definition: move.c:495
MenuRedrawFlags menu_prev_line(struct Menu *menu)
Move the view up one line, keeping the selection the same.
Definition: move.c:515
MenuRedrawFlags menu_current_bottom(struct Menu *menu)
Move the current selection to the bottom of the window.
Definition: move.c:473
MenuRedrawFlags menu_move_view_relative(struct Menu *menu, int relative)
Move the view relatively.
Definition: move.c:245
static int calc_move_view(struct Menu *menu, int relative)
Move the view.
Definition: move.c:187
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition: move.c:453
MenuRedrawFlags menu_middle_page(struct Menu *menu)
Move the focus to the centre of the page.
Definition: move.c:332
MenuRedrawFlags menu_set_and_notify(struct Menu *menu, int top, int index)
Set the Menu selection/view and notify others.
Definition: move.c:66
MenuRedrawFlags menu_first_entry(struct Menu *menu)
Move the focus to the first entry in the menu.
Definition: move.c:399
MenuRedrawFlags menu_half_down(struct Menu *menu)
Move the focus down half a page in the menu.
Definition: move.c:505
MenuRedrawFlags menu_top_page(struct Menu *menu)
Move the focus to the top of the page.
Definition: move.c:322
MenuRedrawFlags menu_move_selection(struct Menu *menu, int index)
Move the selection, keeping within between [0, menu->max].
Definition: move.c:228
MenuRedrawFlags menu_last_entry(struct Menu *menu)
Move the focus to the last entry in the menu.
Definition: move.c:415
MenuRedrawFlags menu_prev_page(struct Menu *menu)
Move the focus to the previous page in the menu.
Definition: move.c:541
static int calc_fit_selection_to_view(struct Menu *menu, int top, int index)
Move the selection into the view.
Definition: move.c:159
static int menu_drag_view(struct Menu *menu, int top, int index)
Move the view around the selection.
Definition: move.c:107
MenuRedrawFlags menu_next_line(struct Menu *menu)
Move the view down one line, keeping the selection the same.
Definition: move.c:528
MenuRedrawFlags menu_prev_entry(struct Menu *menu)
Move the focus to the previous item in the menu.
Definition: move.c:371
MenuRedrawFlags menu_current_top(struct Menu *menu)
Move the current selection to the top of the window.
Definition: move.c:432
MenuRedrawFlags menu_next_entry(struct Menu *menu)
Move the focus to the next item in the menu.
Definition: move.c:385
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
@ NT_MENU
Menu has changed, MenuRedrawFlags.
Definition: notify_type.h:49
Key value store.
Definition: lib.h:67
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:74
int current
Current entry.
Definition: lib.h:68
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:70
int top
Entry that is the top of the current page.
Definition: lib.h:87
int pagelen
Number of entries per screen.
Definition: lib.h:72
int oldcurrent
For driver use only.
Definition: lib.h:88
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:76
struct Notify * notify
Notifications.
Definition: lib.h:151
int max
Number of entries in the menu.
Definition: lib.h:69
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132