From: Jaroslav Kysela Date: Wed, 6 Apr 2016 10:36:35 +0000 (+0200) Subject: webui/prop: add support for integer range type (extjs spinner) X-Git-Tag: v4.2.1~727 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=58bf0288a0210cae52258ab58aba94138716346c;p=thirdparty%2Ftvheadend.git webui/prop: add support for integer range type (extjs spinner) --- diff --git a/Makefile.webui b/Makefile.webui index 83102509e..c73218815 100644 --- a/Makefile.webui +++ b/Makefile.webui @@ -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 @@ -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 # diff --git a/src/access.c b/src/access.c index 70387a0dc..cc45a854b 100644 --- a/src/access.c +++ b/src/access.c @@ -1655,7 +1655,7 @@ 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."), @@ -1663,7 +1663,7 @@ const idclass_t access_entry_class = { }, { .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."), diff --git a/src/channels.c b/src/channels.c index e31a7a63b..f9bd211ef 100644 --- a/src/channels.c +++ b/src/channels.c @@ -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 " diff --git a/src/config.c b/src/config.c index 518639c98..4f75f97fd 100644 --- a/src/config.c +++ b/src/config.c @@ -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 " diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c index 018c1105b..745bfcf3b 100644 --- a/src/epggrab/channel.c +++ b/src/epggrab/channel.c @@ -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."), diff --git a/src/idnode.c b/src/idnode.c index 84da3aed9..d6902dd01 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -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; } } diff --git a/src/input/mpegts/iptv/iptv.c b/src/input/mpegts/iptv/iptv.c index 466376992..aa60d6731 100644 --- a/src/input/mpegts/iptv/iptv.c +++ b/src/input/mpegts/iptv/iptv.c @@ -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), diff --git a/src/input/mpegts/iptv/iptv_mux.c b/src/input/mpegts/iptv/iptv_mux.c index 368f5cf57..984628e46 100644 --- a/src/input/mpegts/iptv/iptv_mux.c +++ b/src/input/mpegts/iptv/iptv_mux.c @@ -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), diff --git a/src/prop.c b/src/prop.c index 7ffb5821c..75bb3ca38 100644 --- a/src/prop.c +++ b/src/prop.c @@ -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; @@ -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; @@ -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); @@ -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); @@ -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) diff --git a/src/prop.h b/src/prop.h index 404b51de4..86b601cfe 100644 --- a/src/prop.h +++ b/src/prop.h @@ -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 */ @@ -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); diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index 217243499..2a4e2726c 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -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; @@ -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' */ @@ -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, diff --git a/src/webui/static/extjs/examples/ux/Spinner.js b/src/webui/static/extjs/examples/ux/Spinner.js new file mode 120000 index 000000000..10c08be5c --- /dev/null +++ b/src/webui/static/extjs/examples/ux/Spinner.js @@ -0,0 +1 @@ +../../../../../../vendor/ext-3.4/examples/ux/Spinner.js \ No newline at end of file diff --git a/src/webui/static/extjs/examples/ux/SpinnerField.js b/src/webui/static/extjs/examples/ux/SpinnerField.js new file mode 120000 index 000000000..2aff7165e --- /dev/null +++ b/src/webui/static/extjs/examples/ux/SpinnerField.js @@ -0,0 +1 @@ +../../../../../../vendor/ext-3.4/examples/ux/SpinnerField.js \ No newline at end of file diff --git a/src/webui/static/extjs/examples/ux/css/Spinner.css b/src/webui/static/extjs/examples/ux/css/Spinner.css new file mode 120000 index 000000000..46b82b1c1 --- /dev/null +++ b/src/webui/static/extjs/examples/ux/css/Spinner.css @@ -0,0 +1 @@ +../../../../../../../vendor/ext-3.4/examples/ux/css/Spinner.css \ No newline at end of file diff --git a/src/webui/static/extjs/examples/ux/images/spinner-split.gif b/src/webui/static/extjs/examples/ux/images/spinner-split.gif new file mode 120000 index 000000000..6c2e6fa0e --- /dev/null +++ b/src/webui/static/extjs/examples/ux/images/spinner-split.gif @@ -0,0 +1 @@ +../../../../../../../vendor/ext-3.4/examples/ux/images/spinner-split.gif \ No newline at end of file diff --git a/src/webui/static/extjs/examples/ux/images/spinner.gif b/src/webui/static/extjs/examples/ux/images/spinner.gif new file mode 120000 index 000000000..e844fdd92 --- /dev/null +++ b/src/webui/static/extjs/examples/ux/images/spinner.gif @@ -0,0 +1 @@ +../../../../../../../vendor/ext-3.4/examples/ux/images/spinner.gif \ No newline at end of file