diff options
author | William Wilgus <me.theuser@yahoo.com> | 2018-12-17 22:27:55 -0600 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2018-12-22 12:27:21 -0600 |
commit | a06d9c85f7475d650cc451fb0f537623c0206f5a (patch) | |
tree | 952a0e7265e836328873a5e2f6eb0ca8ec3cc06a /apps/misc.c | |
parent | b3356e3aff34a4ab94778e7f6a8db43f9135296c (diff) | |
download | rockbox-a06d9c85f7475d650cc451fb0f537623c0206f5a.tar.gz rockbox-a06d9c85f7475d650cc451fb0f537623c0206f5a.zip |
Auto-Ranging Time Formatting For Menus (hh:mm:ss:mss)
Unifies time formatting in settings_list.c allows time format to
display as HH:MM:SS.MSS or any consecutive combination thereof
(hh:mm:ss, mm:ss, mm:ss.mss, ss.mss, hh, mm, ss ,mss)
works in INT and TABLE settings with the addition of flag 'F_TIME_SETTING'
Time is auto-ranged dependent on value
Adds talk_time_intervals to allow time values to be spoken similar to
display format: x Hours, x Minutes, x Seconds, x Milliseconds
Table lookups merged or removed from recording, clip meter and lcd timeout
-String_Choice replaced with TABLE_SETTING or INT_SETTING for these
functions as well, cleaned-up cfg_vals that get saved to cfgfile
RTL Languages ARE supported
Negative values ARE supported
Backlight on/off are now Always and Never to share formatter with LCD
Timeout
Added flag to allow ranged units to be locked to a minimum index
Added flag to allow leading zero to be supressed from the largest unit
merged talk_time_unit() and talk_time_intervals()
optimized time_split()
optimized format_time_auto()
Backlight time-out list same as original
Change-Id: I59027c62d3f2956bd16fdcc1a48b2ac32c084abd
Diffstat (limited to 'apps/misc.c')
-rw-r--r-- | apps/misc.c | 237 |
1 files changed, 231 insertions, 6 deletions
diff --git a/apps/misc.c b/apps/misc.c index b43d347d91..9b8fa3e81c 100644 --- a/apps/misc.c +++ b/apps/misc.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include "misc.h" | 28 | #include "misc.h" |
29 | #include "system.h" | 29 | #include "system.h" |
30 | #include "lcd.h" | 30 | #include "lcd.h" |
31 | #include "language.h" /* is_lang_rtl() */ | ||
32 | |||
31 | #ifdef HAVE_DIRCACHE | 33 | #ifdef HAVE_DIRCACHE |
32 | #include "dircache.h" | 34 | #include "dircache.h" |
33 | #endif | 35 | #endif |
@@ -117,6 +119,20 @@ const unsigned char * const byte_units[] = | |||
117 | 119 | ||
118 | const unsigned char * const * const kibyte_units = &byte_units[1]; | 120 | const unsigned char * const * const kibyte_units = &byte_units[1]; |
119 | 121 | ||
122 | /* units used with format_time_auto, option_select.c->option_get_valuestring() */ | ||
123 | const unsigned char * const unit_strings_core[] = | ||
124 | { | ||
125 | [UNIT_INT] = "", [UNIT_MS] = "ms", | ||
126 | [UNIT_SEC] = "s", [UNIT_MIN] = "min", | ||
127 | [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz", | ||
128 | [UNIT_DB] = "dB", [UNIT_PERCENT] = "%", | ||
129 | [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px", | ||
130 | [UNIT_PER_SEC] = "per sec", | ||
131 | [UNIT_HERTZ] = "Hz", | ||
132 | [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s", | ||
133 | [UNIT_PM_TICK] = "units/10ms", | ||
134 | }; | ||
135 | |||
120 | /* Format a large-range value for output, using the appropriate unit so that | 136 | /* Format a large-range value for output, using the appropriate unit so that |
121 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" | 137 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" |
122 | * units) if possible, and 3 significant digits are shown. If a buffer is | 138 | * units) if possible, and 3 significant digits are shown. If a buffer is |
@@ -1096,6 +1112,216 @@ char* skip_whitespace(char* const str) | |||
1096 | return s; | 1112 | return s; |
1097 | } | 1113 | } |
1098 | 1114 | ||
1115 | /* time_split_units() | ||
1116 | split time values depending on base unit | ||
1117 | unit_idx: UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_MS | ||
1118 | abs_value: absolute time value | ||
1119 | units_in: array of unsigned ints with UNIT_IDX_TIME_COUNT fields | ||
1120 | */ | ||
1121 | unsigned int time_split_units(int unit_idx, unsigned long abs_val, | ||
1122 | unsigned long (*units_in)[UNIT_IDX_TIME_COUNT]) | ||
1123 | { | ||
1124 | unsigned int base_idx = UNIT_IDX_HR; | ||
1125 | unsigned long hours; | ||
1126 | unsigned long minutes = 0; | ||
1127 | unsigned long seconds = 0; | ||
1128 | unsigned long millisec = 0; | ||
1129 | |||
1130 | switch (unit_idx & UNIT_IDX_MASK) /*Mask off upper bits*/ | ||
1131 | { | ||
1132 | case UNIT_MS: | ||
1133 | base_idx = UNIT_IDX_MS; | ||
1134 | millisec = abs_val; | ||
1135 | abs_val = abs_val / 1000U; | ||
1136 | millisec = millisec - (1000U * abs_val); | ||
1137 | /* fallthrough and calculate the rest of the units */ | ||
1138 | case UNIT_SEC: | ||
1139 | if (base_idx == UNIT_IDX_HR) | ||
1140 | base_idx = UNIT_IDX_SEC; | ||
1141 | seconds = abs_val; | ||
1142 | abs_val = abs_val / 60U; | ||
1143 | seconds = seconds - (60U * abs_val); | ||
1144 | /* fallthrough and calculate the rest of the units */ | ||
1145 | case UNIT_MIN: | ||
1146 | if (base_idx == UNIT_IDX_HR) | ||
1147 | base_idx = UNIT_IDX_MIN; | ||
1148 | minutes = abs_val; | ||
1149 | abs_val = abs_val / 60U; | ||
1150 | minutes = minutes -(60U * abs_val); | ||
1151 | /* fallthrough and calculate the rest of the units */ | ||
1152 | case UNIT_HOUR: | ||
1153 | default: | ||
1154 | hours = abs_val; | ||
1155 | break; | ||
1156 | } | ||
1157 | |||
1158 | (*units_in)[UNIT_IDX_HR] = hours; | ||
1159 | (*units_in)[UNIT_IDX_MIN] = minutes; | ||
1160 | (*units_in)[UNIT_IDX_SEC] = seconds; | ||
1161 | (*units_in)[UNIT_IDX_MS] = millisec; | ||
1162 | |||
1163 | return base_idx; | ||
1164 | } | ||
1165 | |||
1166 | /* format_time_auto - return an auto ranged time string; | ||
1167 | buffer: needs to be at least 25 characters for full range | ||
1168 | |||
1169 | unit_idx: specifies lowest or base index of the value | ||
1170 | add | UNIT_LOCK_ to keep place holder of units that would normally be | ||
1171 | discarded.. For instance, UNIT_LOCK_HR would keep the hours place, ex: string | ||
1172 | 00:10:10 (0 HRS 10 MINS 10 SECONDS) normally it would return as 10:10 | ||
1173 | add | UNIT_TRIM_ZERO to supress leading zero on the largest unit | ||
1174 | |||
1175 | value: should be passed in the same form as unit_idx | ||
1176 | |||
1177 | supress_unit: may be set to true and in this case the | ||
1178 | hr, min, sec, ms identifiers will be left off the resulting string but | ||
1179 | since right to left languages are handled it is advisable to leave units | ||
1180 | as an indication of the text direction | ||
1181 | */ | ||
1182 | |||
1183 | const char *format_time_auto(char *buffer, int buf_len, long value, | ||
1184 | int unit_idx, bool supress_unit) | ||
1185 | { | ||
1186 | const char * const sign = &"-"[value < 0 ? 0 : 1]; | ||
1187 | bool is_rtl = lang_is_rtl(); | ||
1188 | char timebuf[25]; /* -2147483648:00:00.00\0 */ | ||
1189 | int len, left_offset; | ||
1190 | unsigned char base_idx, max_idx; | ||
1191 | |||
1192 | unsigned long units_in[UNIT_IDX_TIME_COUNT]; | ||
1193 | unsigned char fwidth[UNIT_IDX_TIME_COUNT] = | ||
1194 | { | ||
1195 | [UNIT_IDX_HR] = 0, /* hr is variable length */ | ||
1196 | [UNIT_IDX_MIN] = 2, | ||
1197 | [UNIT_IDX_SEC] = 2, | ||
1198 | [UNIT_IDX_MS] = 3, | ||
1199 | }; /* {0,2,2,3}; Field Widths */ | ||
1200 | unsigned char offsets[UNIT_IDX_TIME_COUNT] = | ||
1201 | { | ||
1202 | [UNIT_IDX_HR] = 10,/* ?:59:59.999 Std offsets */ | ||
1203 | [UNIT_IDX_MIN] = 7, /*0?:+1:+4.+7 need calculated */ | ||
1204 | [UNIT_IDX_SEC] = 4,/* 999.59:59:0 RTL offsets */ | ||
1205 | [UNIT_IDX_MS] = 0,/* 0 .4 :7 :10 won't change */ | ||
1206 | }; /* {10,7,4,0}; Offsets */ | ||
1207 | const uint16_t unitlock[UNIT_IDX_TIME_COUNT] = | ||
1208 | { | ||
1209 | [UNIT_IDX_HR] = UNIT_LOCK_HR, | ||
1210 | [UNIT_IDX_MIN] = UNIT_LOCK_MIN, | ||
1211 | [UNIT_IDX_SEC] = UNIT_LOCK_SEC, | ||
1212 | [UNIT_IDX_MS] = 0, | ||
1213 | }; /* unitlock */ | ||
1214 | const uint16_t units[UNIT_IDX_TIME_COUNT] = | ||
1215 | { | ||
1216 | [UNIT_IDX_HR] = UNIT_HOUR, | ||
1217 | [UNIT_IDX_MIN] = UNIT_MIN, | ||
1218 | [UNIT_IDX_SEC] = UNIT_SEC, | ||
1219 | [UNIT_IDX_MS] = UNIT_MS, | ||
1220 | }; /* units */ | ||
1221 | |||
1222 | #if 0 /* unused */ | ||
1223 | if (idx_pos != NULL) | ||
1224 | { | ||
1225 | (*idx_pos)[0] = MIN((*idx_pos)[0], UNIT_IDX_TIME_COUNT - 1); | ||
1226 | unit_idx |= unitlock[(*idx_pos)[0]]; | ||
1227 | } | ||
1228 | #endif | ||
1229 | |||
1230 | base_idx = time_split_units(unit_idx, labs(value), &units_in); | ||
1231 | |||
1232 | if (units_in[UNIT_IDX_HR] || (unit_idx & unitlock[UNIT_IDX_HR])) | ||
1233 | max_idx = UNIT_IDX_HR; | ||
1234 | else if (units_in[UNIT_IDX_MIN] || (unit_idx & unitlock[UNIT_IDX_MIN])) | ||
1235 | max_idx = UNIT_IDX_MIN; | ||
1236 | else if (units_in[UNIT_IDX_SEC] || (unit_idx & unitlock[UNIT_IDX_SEC])) | ||
1237 | max_idx = UNIT_IDX_SEC; | ||
1238 | else if (units_in[UNIT_IDX_MS]) | ||
1239 | max_idx = UNIT_IDX_MS; | ||
1240 | else /* value is 0 */ | ||
1241 | max_idx = base_idx; | ||
1242 | |||
1243 | if (!is_rtl) | ||
1244 | { | ||
1245 | len = snprintf(timebuf, sizeof(timebuf), | ||
1246 | "%02lu:%02lu:%02lu.%03lu", | ||
1247 | units_in[UNIT_IDX_HR], | ||
1248 | units_in[UNIT_IDX_MIN], | ||
1249 | units_in[UNIT_IDX_SEC], | ||
1250 | units_in[UNIT_IDX_MS]); | ||
1251 | |||
1252 | fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR]; | ||
1253 | |||
1254 | /* calculate offsets of the other fields based on length of previous */ | ||
1255 | offsets[UNIT_IDX_MS] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_MIN]; | ||
1256 | offsets[UNIT_IDX_SEC] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_SEC]; | ||
1257 | offsets[UNIT_IDX_MIN] = fwidth[UNIT_IDX_HR] + 1; | ||
1258 | offsets[UNIT_IDX_HR] = 0; | ||
1259 | |||
1260 | timebuf[offsets[base_idx] + fwidth[base_idx]] = '\0'; | ||
1261 | |||
1262 | left_offset = -(offsets[max_idx]); | ||
1263 | left_offset += strlcpy(buffer, sign, buf_len); | ||
1264 | |||
1265 | /* trim leading zero on the max_idx */ | ||
1266 | if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO && | ||
1267 | timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1) | ||
1268 | { | ||
1269 | offsets[max_idx]++; | ||
1270 | } | ||
1271 | |||
1272 | strlcat(buffer, &timebuf[offsets[max_idx]], buf_len); | ||
1273 | |||
1274 | if (!supress_unit) | ||
1275 | { | ||
1276 | strlcat(buffer, " ", buf_len); | ||
1277 | strlcat(buffer, unit_strings_core[units[max_idx]], buf_len); | ||
1278 | } | ||
1279 | } | ||
1280 | else /*RTL Languages*/ | ||
1281 | { | ||
1282 | len = snprintf(timebuf, sizeof(timebuf), | ||
1283 | "%03lu.%02lu:%02lu:%02lu", | ||
1284 | units_in[UNIT_IDX_MS], | ||
1285 | units_in[UNIT_IDX_SEC], | ||
1286 | units_in[UNIT_IDX_MIN], | ||
1287 | units_in[UNIT_IDX_HR]); | ||
1288 | |||
1289 | fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR]; | ||
1290 | |||
1291 | left_offset = -(offsets[base_idx]); | ||
1292 | |||
1293 | /* trim leading zero on the max_idx */ | ||
1294 | if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO && | ||
1295 | timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1) | ||
1296 | { | ||
1297 | timebuf[offsets[max_idx]] = timebuf[offsets[max_idx]+1]; | ||
1298 | fwidth[max_idx]--; | ||
1299 | } | ||
1300 | |||
1301 | timebuf[offsets[max_idx] + fwidth[max_idx]] = '\0'; | ||
1302 | |||
1303 | if (!supress_unit) | ||
1304 | { | ||
1305 | strlcpy(buffer, unit_strings_core[units[max_idx]], buf_len); | ||
1306 | left_offset += strlcat(buffer, " ", buf_len); | ||
1307 | strlcat(buffer, &timebuf[offsets[base_idx]], buf_len); | ||
1308 | } | ||
1309 | else | ||
1310 | strlcpy(buffer, &timebuf[offsets[base_idx]], buf_len); | ||
1311 | |||
1312 | strlcat(buffer, sign, buf_len); | ||
1313 | } | ||
1314 | #if 0 /* unused */ | ||
1315 | if (idx_pos != NULL) | ||
1316 | { | ||
1317 | (*idx_pos)[1]= fwidth[*(idx_pos)[0]]; | ||
1318 | (*idx_pos)[0]= left_offset + offsets[(*idx_pos)[0]]; | ||
1319 | } | ||
1320 | #endif | ||
1321 | |||
1322 | return buffer; | ||
1323 | } | ||
1324 | |||
1099 | /* Format time into buf. | 1325 | /* Format time into buf. |
1100 | * | 1326 | * |
1101 | * buf - buffer to format to. | 1327 | * buf - buffer to format to. |
@@ -1104,13 +1330,12 @@ char* skip_whitespace(char* const str) | |||
1104 | */ | 1330 | */ |
1105 | void format_time(char* buf, int buf_size, long t) | 1331 | void format_time(char* buf, int buf_size, long t) |
1106 | { | 1332 | { |
1107 | unsigned long time = labs(t / 1000); | 1333 | unsigned long units_in[UNIT_IDX_TIME_COUNT] = {0}; |
1108 | unsigned long hours = time / 3600; | 1334 | time_split_units(UNIT_MS, labs(t), &units_in); |
1109 | unsigned long minutes = time / 60 - hours * 60; | 1335 | int hashours = units_in[UNIT_IDX_HR] > 0; |
1110 | unsigned long seconds = time % 60; | ||
1111 | int hashours = hours > 0; | ||
1112 | snprintf(buf, buf_size, "%.*s%.0lu%.*s%.*lu:%.2lu", | 1336 | snprintf(buf, buf_size, "%.*s%.0lu%.*s%.*lu:%.2lu", |
1113 | t < 0, "-", hours, hashours, ":", hashours+1, minutes, seconds); | 1337 | t < 0, "-", units_in[UNIT_IDX_HR], hashours, ":", |
1338 | hashours+1, units_in[UNIT_IDX_MIN], units_in[UNIT_IDX_SEC]); | ||
1114 | } | 1339 | } |
1115 | 1340 | ||
1116 | /** | 1341 | /** |