Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
webui/prop: add support for integer range type (extjs spinner)
  • Loading branch information
perexg committed Apr 6, 2016
1 parent fc6b8ce commit 58bf028
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 23 deletions.
3 changes: 3 additions & 0 deletions Makefile.webui
Expand Up @@ -69,6 +69,7 @@ CSS_INIT += $(EXTJSPATH)/resources/css/ext-all-notheme.css
CSS_DONE += $(ROOTPATH)/livegrid/resources/css/ext-ux-livegrid.css
CSS_DONE += $(EXTJSPATH)/examples/ux/gridfilters/css/GridFilters.css
CSS_DONE += $(EXTJSPATH)/examples/ux/gridfilters/css/RangeMenu.css
CSS_DONE += $(EXTJSPATH)/examples/ux/css/Spinner.css
CSS_DONE += static/xcheckbox/xcheckbox.css
CSS_DONE += static/app/ext.css

Expand Down Expand Up @@ -98,6 +99,8 @@ JAVASCRIPT += $(EXTJSPATH)/examples/ux/gridfilters/filter/NumericFilter.js
JAVASCRIPT += $(EXTJSPATH)/examples/ux/gridfilters/filter/StringFilter.js
JAVASCRIPT += $(EXTJSPATH)/examples/ux/gridfilters/menu/ListMenu.js
JAVASCRIPT += $(EXTJSPATH)/examples/ux/gridfilters/menu/RangeMenu.js
JAVASCRIPT += $(EXTJSPATH)/examples/ux/Spinner.js
JAVASCRIPT += $(EXTJSPATH)/examples/ux/SpinnerField.js
JAVASCRIPT += $(ROOTPATH)/app/i18n-post.js

#
Expand Down
4 changes: 2 additions & 2 deletions src/access.c
Expand Up @@ -1655,15 +1655,15 @@ const idclass_t access_entry_class = {
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "channel_min",
.name = N_("Minimal channel number"),
.desc = N_("Lowest channel number the user can access."),
.off = offsetof(access_entry_t, ae_chmin),
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "channel_max",
.name = N_("Maximal channel number"),
.desc = N_("Highest channel number the user can access."),
Expand Down
2 changes: 1 addition & 1 deletion src/channels.c
Expand Up @@ -397,7 +397,7 @@ const idclass_t channel_class = {
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "number",
.name = N_("Number"),
.desc = N_("Number. The position the channel will appear on "
Expand Down
1 change: 1 addition & 0 deletions src/config.c
Expand Up @@ -2058,6 +2058,7 @@ const idclass_t config_class = {
},
{
.type = PT_U32,
.intextra = INTEXTRA_RANGE(1, 0x7ff, 1),
.id = "cookie_expires",
.name = N_("Cookie expiration (days)"),
.desc = N_("The number of days cookies set by Tvheadend should "
Expand Down
2 changes: 1 addition & 1 deletion src/epggrab/channel.c
Expand Up @@ -737,7 +737,7 @@ const idclass_t epggrab_channel_class = {
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "number",
.name = N_("Number"),
.desc = N_("Channel number as defined in EPG data."),
Expand Down
4 changes: 2 additions & 2 deletions src/idnode.c
Expand Up @@ -817,8 +817,8 @@ idnode_filter_init
if (p->type == PT_U32 || p->type == PT_S64 ||
p->type == PT_TIME) {
int64_t v = f->u.n.n;
if (p->intsplit != f->u.n.intsplit) {
v = (v / MIN(1, f->u.n.intsplit)) * p->intsplit;
if (INTEXTRA_IS_SPLIT(p->intextra) && p->intextra != f->u.n.intsplit) {
v = (v / MIN(1, f->u.n.intsplit)) * p->intextra;
f->u.n.n = v;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/input/mpegts/iptv/iptv.c
Expand Up @@ -847,7 +847,7 @@ const idclass_t iptv_auto_network_class = {
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "channel_number",
.name = N_("Channel numbers from"),
.off = offsetof(iptv_network_t, in_channel_number),
Expand Down
2 changes: 1 addition & 1 deletion src/input/mpegts/iptv/iptv_mux.c
Expand Up @@ -170,7 +170,7 @@ const idclass_t iptv_mux_class =
},
{
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.intextra = CHANNEL_SPLIT,
.id = "channel_number",
.name = N_("Channel number"),
.off = offsetof(iptv_mux_t, mm_iptv_chnum),
Expand Down
33 changes: 20 additions & 13 deletions src/prop.c
Expand Up @@ -140,13 +140,13 @@ prop_write_values
break;
}
case PT_U32: {
if (p->intsplit) {
if (p->intextra && INTEXTRA_IS_SPLIT(p->intextra)) {
char *s;
if (!(new = htsmsg_field_get_str(f)))
continue;
u32 = atol(new) * p->intsplit;
u32 = atol(new) * p->intextra;
if ((s = strchr(new, '.')) != NULL)
u32 += (atol(s + 1) % p->intsplit);
u32 += (atol(s + 1) % p->intextra);
} else {
if (htsmsg_field_get_u32(f, &u32))
continue;
Expand All @@ -155,10 +155,10 @@ prop_write_values
break;
}
case PT_S64: {
if (p->intsplit) {
if (p->intextra && INTEXTRA_IS_SPLIT(p->intextra)) {
if (!(new = htsmsg_field_get_str(f)))
continue;
s64 = prop_intsplit_from_str(new, p->intsplit);
s64 = prop_intsplit_from_str(new, p->intextra);
} else {
if (htsmsg_field_get_s64(f, &s64))
continue;
Expand Down Expand Up @@ -290,9 +290,9 @@ prop_read_value
htsmsg_add_u32(m, name, *(uint16_t *)val);
break;
case PT_U32:
if (p->intsplit) {
uint32_t maj = *(int64_t *)val / p->intsplit;
uint32_t min = *(int64_t *)val % p->intsplit;
if (p->intextra && INTEXTRA_IS_SPLIT(p->intextra)) {
uint32_t maj = *(int64_t *)val / p->intextra;
uint32_t min = *(int64_t *)val % p->intextra;
if (min) {
snprintf(buf, sizeof(buf), "%u.%u", (unsigned int)maj, (unsigned int)min);
htsmsg_add_str(m, name, buf);
Expand All @@ -302,9 +302,9 @@ prop_read_value
htsmsg_add_u32(m, name, *(uint32_t *)val);
break;
case PT_S64:
if (p->intsplit) {
int64_t maj = *(int64_t *)val / p->intsplit;
int64_t min = *(int64_t *)val % p->intsplit;
if (p->intextra && INTEXTRA_IS_SPLIT(p->intextra)) {
int64_t maj = *(int64_t *)val / p->intextra;
int64_t min = *(int64_t *)val % p->intextra;
if (min) {
snprintf(buf, sizeof(buf), "%lu.%lu", (unsigned long)maj, (unsigned long)min);
htsmsg_add_str(m, name, buf);
Expand Down Expand Up @@ -511,8 +511,15 @@ prop_serialize_value
htsmsg_add_u32(m, "group", pl->group);

/* Split integer value */
if (pl->intsplit)
htsmsg_add_u32(m, "intsplit", pl->intsplit);
if (pl->intextra) {
if (INTEXTRA_IS_SPLIT(pl->intextra))
htsmsg_add_u32(m, "intsplit", pl->intextra);
else {
htsmsg_add_s32(m, "intmax", INTEXTRA_GET_MAX(pl->intextra));
htsmsg_add_s32(m, "intmin", INTEXTRA_GET_MIN(pl->intextra));
htsmsg_add_s32(m, "intstep", INTEXTRA_GET_STEP(pl->intextra));
}
}

/* Data */
if (obj)
Expand Down
14 changes: 13 additions & 1 deletion src/prop.h
Expand Up @@ -64,6 +64,18 @@ typedef enum {
#define PO_MULTILINE (1<<16) // Multiline string
#define PO_PERSIST (1<<17) // Persistent value (return back on save)

/*
* min/max/step helpers
*/
#define INTEXTRA_RANGE(min, max, step) \
((1<<31)|(((step)&0x7f)<<24)|(((max)&0xfff)<<12)|((min)&0xfff))

#define INTEXTRA_IS_RANGE(e) (((e) & (1<<31)) != 0)
#define INTEXTRA_IS_SPLIT(e) !INTEXTRA_IS_RANGE(e)
#define INTEXTRA_GET_STEP(e) (((e)>>24)&0x7f)
#define INTEXTRA_GET_MAX(e) ((e)&(1<<23)?-(((e)>>12)&0x7ff):(((e)>>12)&0x7ff))
#define INTEXTRA_GET_MIN(e) ((e)&(1<<11)?-((e)&0x7ff):((e)&0x7ff))

/*
* Property definition
*/
Expand All @@ -76,7 +88,7 @@ typedef struct property {
uint8_t group; ///< Visual group ID (like ExtJS FieldSet)
size_t off; ///< Offset into object
uint32_t opts; ///< Options
uint32_t intsplit; ///< integer/remainder boundary
uint32_t intextra; ///< intsplit: integer/remainder boundary or range: min/max/step

/* String based processing */
const void *(*get) (void *ptr);
Expand Down
23 changes: 22 additions & 1 deletion src/webui/static/app/idnode.js
Expand Up @@ -248,6 +248,9 @@ tvheadend.IdNodeField = function(conf)
this.duration = conf.duration;
this.date = conf.date;
this.intsplit = conf.intsplit;
this.intmin = conf.intmin;
this.intmax = conf.intmax;
this.intstep = conf.intstep;
this.hexa = conf.hexa;
this.group = conf.group;
this.lorder = conf.lorder;
Expand Down Expand Up @@ -488,8 +491,14 @@ tvheadend.IdNodeField = function(conf)
} else if (this.intsplit) {
c['maskRe'] = /[0-9\.]/;
cons = Ext.form.TextField;
} else
} else if (this.intmin || this.intmax) {
cons = Ext.ux.form.SpinnerField;
c['minValue'] = this.intmin;
c['maxValue'] = this.intmax;
c['incrementValue'] = this.intstep || 1;
} else {
cons = Ext.form.NumberField;
}
break;

/* 'str' and 'perm' */
Expand Down Expand Up @@ -812,6 +821,18 @@ tvheadend.idnode_editor_field = function(f, conf)
maskRe: /[0-9\.]/
});
break;
} else if (f.intmin || f.intmin) {
r = new Ext.ux.form.SpinnerField({
fieldLabel: f.caption,
name: f.id,
disabled: d,
width: 300,
value: value,
minValue: f.intmin,
maxValue: f.intmax,
incrementalValue: f.intstep || 1
});
break;
}
r = new Ext.form.NumberField({
fieldLabel: f.caption,
Expand Down
1 change: 1 addition & 0 deletions src/webui/static/extjs/examples/ux/Spinner.js
1 change: 1 addition & 0 deletions src/webui/static/extjs/examples/ux/SpinnerField.js
1 change: 1 addition & 0 deletions src/webui/static/extjs/examples/ux/css/Spinner.css
1 change: 1 addition & 0 deletions src/webui/static/extjs/examples/ux/images/spinner.gif

0 comments on commit 58bf028

Please sign in to comment.