aboutsummaryrefslogtreecommitdiff
path: root/src/hci/jumpscroll.c
blob: 641f781a010b9f682f59b7a7abe0215f989f9129 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *
 * You can also choose to distribute this program under the terms of
 * the Unmodified Binary Distribution Licence (as given in the file
 * COPYING.UBDL), provided that you have satisfied its requirements.
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

/**
 * Jump scrolling
 *
 */

#include <assert.h>
#include <ipxe/keys.h>
#include <ipxe/jumpscroll.h>

/**
 * Handle keypress
 *
 * @v scroll		Jump scroller
 * @v key		Key pressed by user
 * @ret move		Scroller movement, or zero
 */
unsigned int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
	unsigned int flags = 0;
	int16_t delta;

	/* Sanity checks */
	assert ( scroll->rows != 0 );
	assert ( scroll->count != 0 );
	assert ( scroll->current < scroll->count );
	assert ( scroll->first < scroll->count );
	assert ( scroll->first <= scroll->current );
	assert ( scroll->current < ( scroll->first + scroll->rows ) );

	/* Handle key, if applicable */
	switch ( key ) {
	case KEY_UP:
		delta = -1;
		break;
	case TAB:
		flags = SCROLL_WRAP;
		/* fall through */
	case KEY_DOWN:
		delta = +1;
		break;
	case KEY_PPAGE:
		delta = ( scroll->first - scroll->current - 1 );
		break;
	case KEY_NPAGE:
		delta = ( scroll->first - scroll->current + scroll->rows );
		break;
	case KEY_HOME:
		delta = -( scroll->count );
		break;
	case KEY_END:
		delta = +( scroll->count );
		break;
	default:
		delta = 0;
		break;
	}

	return ( SCROLL ( delta ) | flags );
}

/**
 * Move scroller
 *
 * @v scroll		Jump scroller
 * @v move		Scroller movement
 * @ret move		Continuing scroller movement (if applicable)
 */
unsigned int jump_scroll_move ( struct jump_scroller *scroll,
				unsigned int move ) {
	int16_t delta = SCROLL_DELTA ( move );
	int current = scroll->current;
	int last = ( scroll->count - 1 );

	/* Sanity checks */
	assert ( move != 0 );
	assert ( scroll->count != 0 );

	/* Move to the new current item */
	current += delta;

	/* Default to continuing movement in the same direction */
	delta = ( ( delta >= 0 ) ? +1 : -1 );

	/* Check for start/end of list */
	if ( ( current >= 0 ) && ( current <= last ) ) {
		/* We are still within the list.  Update the current
		 * item and continue moving in the same direction (if
		 * applicable).
		 */
		scroll->current = current;
	} else {
		/* We have attempted to move outside the list.  If we
		 * are wrapping around, then continue in the same
		 * direction (if applicable), otherwise reverse.
		 */
		if ( ! ( move & SCROLL_WRAP ) )
			delta = -delta;

		/* Move to start or end of list as appropriate */
		if ( delta >= 0 ) {
			scroll->current = 0;
		} else {
			scroll->current = last;
		}
	}

	return ( SCROLL ( delta ) | ( move & SCROLL_FLAGS ) );
}

/**
 * Jump scroll to new page (if applicable)
 *
 * @v scroll		Jump scroller
 * @ret jumped		Jumped to a new page
 */
int jump_scroll ( struct jump_scroller *scroll ) {
	unsigned int index;

	/* Sanity checks */
	assert ( scroll->rows != 0 );
	assert ( scroll->count != 0 );
	assert ( scroll->current < scroll->count );
	assert ( scroll->first < scroll->count );

	/* Do nothing if we are already on the correct page */
	index = ( scroll->current - scroll->first );
	if ( index < scroll->rows )
		return 0;

	/* Move to required page */
	while ( scroll->first < scroll->current )
		scroll->first += scroll->rows;
	while ( scroll->first > scroll->current )
		scroll->first -= scroll->rows;

	return 1;
}