1 /**
2  * \file
3  *
4  * \brief Spin control widget
5  *
6  * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 #ifndef GFX_MONO_SPINCTRL_H
47 #define GFX_MONO_SPINCTRL_H
48 
49 #include "gfx_mono.h"
50 #include "conf_spinctrl.h"
51 
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55 
56 /**
57  * \ingroup asfdoc_common2_gfx_mono
58  * \defgroup asfdoc_common2_gfx_mono_spinctrl Spinner widget for monochrome graphical displays
59  *
60  * This module provides a spinner widget system for monochrome graphical
61  * displays.
62  *
63  * There is support for having one single spinner on the screen, or a
64  * collection of spinners.
65  *
66  * Typical flow of an application using the spincollection system:
67  *
68  * 1) Define spinners.\n
69  * 2) Initialize each spinners with \ref gfx_mono_spinctrl_init.\n
70  * 3) Define a spincollection struct and initialize it with
71  * \ref gfx_mono_spinctrl_spincollection_init.\n
72  * 4) Add spinners to spincollection with
73  * \ref gfx_mono_spinctrl_spincollection_add_spinner.\n
74  * 5) Draw spincollection to screen with
75  * \ref gfx_mono_spinctrl_spincollection_show.\n
76  * 6) Define a result array to store the spinner choices.\n
77  * 7) Update spinners and result array with user input using function
78  * \ref gfx_mono_spinctrl_spincollection_process_key.\n
79  * 8) Interpret \ref gfx_mono_spinctrl_spincollection_process_key return
80  * value.\n
81  * 9) Go to 7.\n
82  *
83  * Typical flow of an application using a single spinner:
84  *
85  * 1) Define spinner.\n
86  * 2) Initialize the spinners with \ref gfx_mono_spinctrl_init with preferred y
87  * position on screen.\n
88  * 3) Draw spinner to screen with \ref gfx_mono_spinctrl_draw.\n
89  * 4) Update spinner with user input using function
90  * \ref gfx_mono_spinctrl_process_key.\n
91  * 5) Interpret \ref gfx_mono_spinctrl_process_key return value.\n
92  * 6) Go to 4.\n
93  *
94  * Before the spinners can be updated, you need input from the user. Methods
95  * for getting input is not part of the spinner widget.
96  *
97  * \note The spinners will be linked together when added to a spincollection,
98  * and can therefore not be used in two spincollections at the same time.
99  *
100  * As soon as input is received, inform the spincollection system or the single
101  * spinner using the \ref gfx_mono_spinctrl_spincollection_process_key function
102  * or the \ref gfx_mono_spinctrl_process_key function.
103  * These functions will then return a status code and act depending on the
104  * given keycode:
105  *
106  * GFX_MONO_SPINCTRL_KEYCODE_DOWN : Change selection to next spinner value or
107  * to next spinner or OK button in a spincollection.
108  *
109  * GFX_MONO_SPINCTRL_KEYCODE_UP : Change selection to previous spinner value
110  * or to previous spinner or OK button in a spincollection.
111  *
112  * GFX_MONO_SPINCTRL_KEYCODE_ENTER : Select spinner value or select spinner or
113  * OK button in a spincollection.
114  *
115  * GFX_MONO_SPINCTRL_KEYCODE_BACK : Deselect spinner or cancel spincollection
116  * application.
117  *
118  * The value of the keycodes used are defined in conf_spinctrl.h. These values
119  * can be changed if needed.
120  *
121  * The graphical indicators used to indicate spinner selections are defined in
122  * conf_spinctrl.h. These indicators can be changed if needed.
123  * @{
124  */
125 
126 /** Spinner idle event */
127 #define GFX_MONO_SPINCTRL_EVENT_IDLE                0xFF
128 /** Spinner back button pressed event */
129 #define GFX_MONO_SPINCTRL_EVENT_BACK                0xFE
130 /** Spinner ok button pressed event */
131 #define GFX_MONO_SPINCTRL_EVENT_FINISH              0xFD
132 
133 /** OK button */
134 #define GFX_MONO_SPINCTRL_BUTTON        0xFF
135 
136 /** Maximum number of spinner elements on display */
137 #define GFX_MONO_SPINCTRL_ELEMENTS_PER_SCREEN \
138 	((GFX_MONO_LCD_HEIGHT / SYSFONT_LINESPACING) - 1)
139 
140 /**
141  * Maximum numbers of spinner elements in a spincollection - limited to
142  * one screen.
143  */
144 #define GFX_MONO_SPINCTRL_MAX_ELEMENTS_IN_SPINCOLLECTION \
145 	GFX_MONO_SPINCTRL_ELEMENTS_PER_SCREEN
146 
147 /** Width of string spinner choices */
148 #define GFX_MONO_SPINCTRL_STRING_SPINNER_WIDTH 9
149 /** Width of integer spinner choices */
150 #define GFX_MONO_SPINCTRL_INT_SPINNER_WIDTH    9
151 
152 /** Enum to specify what kind of data spinner should spin */
153 typedef enum gfx_mono_spinctrl_type_enum {
154 	SPINTYPE_STRING,
155 	SPINTYPE_INTEGER
156 } gfx_mono_spinctrl_type_t;
157 
158 /** String struct */
159 struct gfx_mono_spinctrl_string {
160 	/** Pointer to progmem strings to spin through
161 	 * \note Each string must be shorter than
162 	 * \ref  GFX_MONO_SPINCTRL_STRING_SPINNER_WIDTH characters.
163 	 * If not, printing it to the screen will corrupt the spinner
164 	 * appearance.
165 	 */
166 	PROGMEM_STRING_T *data;
167 	/** Index in string array */
168 	uint8_t index;
169 };
170 
171 /** Spin control struct */
172 struct gfx_mono_spinctrl {
173 	/** Spinner title */
174 	PROGMEM_STRING_T title;
175 	/** Type of data to spin */
176 	gfx_mono_spinctrl_type_t datatype;
177 	/** Spinner data, depends on spinner datatype. */
178 	union {
179 		/** Spinner strings and index */
180 		struct gfx_mono_spinctrl_string strings;
181 		/** Spinner integer data */
182 		int16_t integer_data;
183 	};
184 	/** Variable to store the last selected spinner value */
185 	uint16_t last_saved_value;
186 
187 	/**
188 	 * Lower limit for spinning, must be positive and fit in uin8_t for
189 	 * spinner type SPINTYPE_STRING
190 	 */
191 	int16_t lower_limit;
192 
193 	/**
194 	 * Upper limit for spinning, must be positive and fit in uin8_t for
195 	 * spinner type SPINTYPE_STRING
196 	 */
197 	int16_t upper_limit;
198 	/** Y coordinate for placement of spinner on screen */
199 	gfx_coord_t y;
200 	/** Boolean to tell if spinner is in focus or not */
201 	bool in_focus;
202 	/** Pointer to next spinner in a spincollection */
203 	struct gfx_mono_spinctrl *next;
204 	/** Pointer to previous spinner in a spincollection */
205 	struct gfx_mono_spinctrl *prev;
206 };
207 
208 /** Collection of spinners struct */
209 struct gfx_mono_spinctrl_spincollection {
210 	/** Pointer to the first spinner in the collection */
211 	struct gfx_mono_spinctrl *collection;
212 	/** Pointer to the last spinner in the collection */
213 	struct gfx_mono_spinctrl *collection_last;
214 	/** Number of spinners in collection */
215 	uint8_t number_of_spinners;
216 	/** Current spinner/button */
217 	uint8_t current_selection;
218 	/** Return value from selected spinner */
219 	uint16_t selection;
220 	/** Boolean to tell if input should be sent directly to a spinner */
221 	bool active_spinner;
222 	/** Boolean to initialize results array when starting key processing */
223 	bool init;
224 };
225 
226 void gfx_mono_spinctrl_init(struct gfx_mono_spinctrl *spinner,
227 		gfx_mono_spinctrl_type_t datatype, PROGMEM_STRING_T title,
228 		PROGMEM_STRING_T *data, int16_t lower_limit,
229 		int16_t upper_limit,
230 		gfx_coord_t y);
231 void gfx_mono_spinctrl_draw(struct gfx_mono_spinctrl *spinner, bool redraw);
232 void gfx_mono_spinctrl_spincollection_init(struct
233 		gfx_mono_spinctrl_spincollection *collection);
234 void gfx_mono_spinctrl_spincollection_add_spinner(struct gfx_mono_spinctrl
235 		*spinner, struct gfx_mono_spinctrl_spincollection *spinners);
236 void gfx_mono_spinctrl_spincollection_show(struct
237 		gfx_mono_spinctrl_spincollection *spinners);
238 int16_t gfx_mono_spinctrl_process_key(struct gfx_mono_spinctrl *spinner,
239 		uint8_t keycode);
240 
241 int16_t gfx_mono_spinctrl_spincollection_process_key(struct
242 gfx_mono_spinctrl_spincollection *spinners, uint8_t keycode,
243 int16_t results[]);
244 
245 /** @} */
246 
247 #ifdef __cplusplus
248 }
249 #endif
250 
251 #endif /* GFX_MONO_SPINCTRL_H */
252