1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
William Wilgus 2018-12-17 22:27:55 -06:00
parent b3356e3aff
commit a06d9c85f7
17 changed files with 619 additions and 336 deletions

View file

@ -28,6 +28,8 @@
#include "misc.h"
#include "system.h"
#include "lcd.h"
#include "language.h" /* is_lang_rtl() */
#ifdef HAVE_DIRCACHE
#include "dircache.h"
#endif
@ -117,6 +119,20 @@ const unsigned char * const byte_units[] =
const unsigned char * const * const kibyte_units = &byte_units[1];
/* units used with format_time_auto, option_select.c->option_get_valuestring() */
const unsigned char * const unit_strings_core[] =
{
[UNIT_INT] = "", [UNIT_MS] = "ms",
[UNIT_SEC] = "s", [UNIT_MIN] = "min",
[UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
[UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
[UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
[UNIT_PER_SEC] = "per sec",
[UNIT_HERTZ] = "Hz",
[UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
[UNIT_PM_TICK] = "units/10ms",
};
/* Format a large-range value for output, using the appropriate unit so that
* the displayed value is in the range 1 <= display < 1000 (1024 for "binary"
* units) if possible, and 3 significant digits are shown. If a buffer is
@ -1096,6 +1112,216 @@ char* skip_whitespace(char* const str)
return s;
}
/* time_split_units()
split time values depending on base unit
unit_idx: UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_MS
abs_value: absolute time value
units_in: array of unsigned ints with UNIT_IDX_TIME_COUNT fields
*/
unsigned int time_split_units(int unit_idx, unsigned long abs_val,
unsigned long (*units_in)[UNIT_IDX_TIME_COUNT])
{
unsigned int base_idx = UNIT_IDX_HR;
unsigned long hours;
unsigned long minutes = 0;
unsigned long seconds = 0;
unsigned long millisec = 0;
switch (unit_idx & UNIT_IDX_MASK) /*Mask off upper bits*/
{
case UNIT_MS:
base_idx = UNIT_IDX_MS;
millisec = abs_val;
abs_val = abs_val / 1000U;
millisec = millisec - (1000U * abs_val);
/* fallthrough and calculate the rest of the units */
case UNIT_SEC:
if (base_idx == UNIT_IDX_HR)
base_idx = UNIT_IDX_SEC;
seconds = abs_val;
abs_val = abs_val / 60U;
seconds = seconds - (60U * abs_val);
/* fallthrough and calculate the rest of the units */
case UNIT_MIN:
if (base_idx == UNIT_IDX_HR)
base_idx = UNIT_IDX_MIN;
minutes = abs_val;
abs_val = abs_val / 60U;
minutes = minutes -(60U * abs_val);
/* fallthrough and calculate the rest of the units */
case UNIT_HOUR:
default:
hours = abs_val;
break;
}
(*units_in)[UNIT_IDX_HR] = hours;
(*units_in)[UNIT_IDX_MIN] = minutes;
(*units_in)[UNIT_IDX_SEC] = seconds;
(*units_in)[UNIT_IDX_MS] = millisec;
return base_idx;
}
/* format_time_auto - return an auto ranged time string;
buffer: needs to be at least 25 characters for full range
unit_idx: specifies lowest or base index of the value
add | UNIT_LOCK_ to keep place holder of units that would normally be
discarded.. For instance, UNIT_LOCK_HR would keep the hours place, ex: string
00:10:10 (0 HRS 10 MINS 10 SECONDS) normally it would return as 10:10
add | UNIT_TRIM_ZERO to supress leading zero on the largest unit
value: should be passed in the same form as unit_idx
supress_unit: may be set to true and in this case the
hr, min, sec, ms identifiers will be left off the resulting string but
since right to left languages are handled it is advisable to leave units
as an indication of the text direction
*/
const char *format_time_auto(char *buffer, int buf_len, long value,
int unit_idx, bool supress_unit)
{
const char * const sign = &"-"[value < 0 ? 0 : 1];
bool is_rtl = lang_is_rtl();
char timebuf[25]; /* -2147483648:00:00.00\0 */
int len, left_offset;
unsigned char base_idx, max_idx;
unsigned long units_in[UNIT_IDX_TIME_COUNT];
unsigned char fwidth[UNIT_IDX_TIME_COUNT] =
{
[UNIT_IDX_HR] = 0, /* hr is variable length */
[UNIT_IDX_MIN] = 2,
[UNIT_IDX_SEC] = 2,
[UNIT_IDX_MS] = 3,
}; /* {0,2,2,3}; Field Widths */
unsigned char offsets[UNIT_IDX_TIME_COUNT] =
{
[UNIT_IDX_HR] = 10,/* ?:59:59.999 Std offsets */
[UNIT_IDX_MIN] = 7, /*0?:+1:+4.+7 need calculated */
[UNIT_IDX_SEC] = 4,/* 999.59:59:0 RTL offsets */
[UNIT_IDX_MS] = 0,/* 0 .4 :7 :10 won't change */
}; /* {10,7,4,0}; Offsets */
const uint16_t unitlock[UNIT_IDX_TIME_COUNT] =
{
[UNIT_IDX_HR] = UNIT_LOCK_HR,
[UNIT_IDX_MIN] = UNIT_LOCK_MIN,
[UNIT_IDX_SEC] = UNIT_LOCK_SEC,
[UNIT_IDX_MS] = 0,
}; /* unitlock */
const uint16_t units[UNIT_IDX_TIME_COUNT] =
{
[UNIT_IDX_HR] = UNIT_HOUR,
[UNIT_IDX_MIN] = UNIT_MIN,
[UNIT_IDX_SEC] = UNIT_SEC,
[UNIT_IDX_MS] = UNIT_MS,
}; /* units */
#if 0 /* unused */
if (idx_pos != NULL)
{
(*idx_pos)[0] = MIN((*idx_pos)[0], UNIT_IDX_TIME_COUNT - 1);
unit_idx |= unitlock[(*idx_pos)[0]];
}
#endif
base_idx = time_split_units(unit_idx, labs(value), &units_in);
if (units_in[UNIT_IDX_HR] || (unit_idx & unitlock[UNIT_IDX_HR]))
max_idx = UNIT_IDX_HR;
else if (units_in[UNIT_IDX_MIN] || (unit_idx & unitlock[UNIT_IDX_MIN]))
max_idx = UNIT_IDX_MIN;
else if (units_in[UNIT_IDX_SEC] || (unit_idx & unitlock[UNIT_IDX_SEC]))
max_idx = UNIT_IDX_SEC;
else if (units_in[UNIT_IDX_MS])
max_idx = UNIT_IDX_MS;
else /* value is 0 */
max_idx = base_idx;
if (!is_rtl)
{
len = snprintf(timebuf, sizeof(timebuf),
"%02lu:%02lu:%02lu.%03lu",
units_in[UNIT_IDX_HR],
units_in[UNIT_IDX_MIN],
units_in[UNIT_IDX_SEC],
units_in[UNIT_IDX_MS]);
fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR];
/* calculate offsets of the other fields based on length of previous */
offsets[UNIT_IDX_MS] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_MIN];
offsets[UNIT_IDX_SEC] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_SEC];
offsets[UNIT_IDX_MIN] = fwidth[UNIT_IDX_HR] + 1;
offsets[UNIT_IDX_HR] = 0;
timebuf[offsets[base_idx] + fwidth[base_idx]] = '\0';
left_offset = -(offsets[max_idx]);
left_offset += strlcpy(buffer, sign, buf_len);
/* trim leading zero on the max_idx */
if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO &&
timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1)
{
offsets[max_idx]++;
}
strlcat(buffer, &timebuf[offsets[max_idx]], buf_len);
if (!supress_unit)
{
strlcat(buffer, " ", buf_len);
strlcat(buffer, unit_strings_core[units[max_idx]], buf_len);
}
}
else /*RTL Languages*/
{
len = snprintf(timebuf, sizeof(timebuf),
"%03lu.%02lu:%02lu:%02lu",
units_in[UNIT_IDX_MS],
units_in[UNIT_IDX_SEC],
units_in[UNIT_IDX_MIN],
units_in[UNIT_IDX_HR]);
fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR];
left_offset = -(offsets[base_idx]);
/* trim leading zero on the max_idx */
if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO &&
timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1)
{
timebuf[offsets[max_idx]] = timebuf[offsets[max_idx]+1];
fwidth[max_idx]--;
}
timebuf[offsets[max_idx] + fwidth[max_idx]] = '\0';
if (!supress_unit)
{
strlcpy(buffer, unit_strings_core[units[max_idx]], buf_len);
left_offset += strlcat(buffer, " ", buf_len);
strlcat(buffer, &timebuf[offsets[base_idx]], buf_len);
}
else
strlcpy(buffer, &timebuf[offsets[base_idx]], buf_len);
strlcat(buffer, sign, buf_len);
}
#if 0 /* unused */
if (idx_pos != NULL)
{
(*idx_pos)[1]= fwidth[*(idx_pos)[0]];
(*idx_pos)[0]= left_offset + offsets[(*idx_pos)[0]];
}
#endif
return buffer;
}
/* Format time into buf.
*
* buf - buffer to format to.
@ -1104,13 +1330,12 @@ char* skip_whitespace(char* const str)
*/
void format_time(char* buf, int buf_size, long t)
{
unsigned long time = labs(t / 1000);
unsigned long hours = time / 3600;
unsigned long minutes = time / 60 - hours * 60;
unsigned long seconds = time % 60;
int hashours = hours > 0;
unsigned long units_in[UNIT_IDX_TIME_COUNT] = {0};
time_split_units(UNIT_MS, labs(t), &units_in);
int hashours = units_in[UNIT_IDX_HR] > 0;
snprintf(buf, buf_size, "%.*s%.0lu%.*s%.*lu:%.2lu",
t < 0, "-", hours, hashours, ":", hashours+1, minutes, seconds);
t < 0, "-", units_in[UNIT_IDX_HR], hashours, ":",
hashours+1, units_in[UNIT_IDX_MIN], units_in[UNIT_IDX_SEC]);
}
/**