Skip to content

Commit d5ad2bd

Browse files
authored
Color picker control (openhab#229)
Make toggle controls compatible with Color items/HSB values Signed-off-by: Yannick Schaus <[email protected]>
1 parent 6e003b4 commit d5ad2bd

File tree

7 files changed

+218
-3
lines changed

7 files changed

+218
-3
lines changed

bundles/org.openhab.ui/web/src/components/config/controls/parameter-options.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<f7-list-item
44
:title="configDescription.label" smart-select :smart-select-params="smartSelectParams" ref="item">
55
<select :name="configDescription.name" @change="updateValue" :multiple="configDescription.multiple">
6-
<option v-if="!configDescription.required" :value="undefined" :selected="value === null || value === undefined"></option>
6+
<option v-if="!configDescription.required && !configDescription.multiple" :value="undefined" :selected="value === null || value === undefined"></option>
77
<option v-for="option in configDescription.options" :value="option.value" :key="option.value" :selected="isSelected(option)">{{option.label}}</option>
88
</select>
99
</f7-list-item>

bundles/org.openhab.ui/web/src/components/item/item-standalone-control.vue

+11-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ export default {
2626
}
2727
}
2828
29-
// temporary until we have a colorpicker control
30-
if ((this.item.type === 'Dimmer' || this.item.type === 'Color') && !stateDescription.readOnly) {
29+
if ((this.item.type === 'Dimmer') && !stateDescription.readOnly) {
3130
ctx.component = {
3231
component: 'oh-slider-card',
3332
config: {
@@ -41,6 +40,16 @@ export default {
4140
}
4241
}
4342
43+
if ((this.item.type === 'Color') && !stateDescription.readOnly) {
44+
ctx.component = {
45+
component: 'oh-colorpicker-card',
46+
config: {
47+
sliderLabel: true,
48+
sliderValue: true
49+
}
50+
}
51+
}
52+
4453
if (this.item.type === 'Rollershutter' && !stateDescription.readOnly) {
4554
ctx.component = {
4655
component: 'oh-rollershutter-card',

bundles/org.openhab.ui/web/src/components/widgets/standard/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { default as OhTestCard } from './oh-test-card.vue'
44
export { default as OhLabelCard } from './oh-label-card.vue'
55
export { default as OhToggleCard } from './oh-toggle-card.vue'
66
export { default as OhRollershutterCard } from './oh-rollershutter-card.vue'
7+
export { default as OhColorpickerCard } from './oh-colorpicker-card.vue'
78
export { default as OhSliderCard } from './oh-slider-card.vue'
89
export { default as OhStepperCard } from './oh-stepper-card.vue'
910
export { default as OhPlayerCard } from './oh-player-card.vue'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<template>
2+
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline">
3+
<f7-card-header v-if="config.title">
4+
<div>{{config.title}}</div>
5+
</f7-card-header>
6+
<f7-card-content class="display-flex justify-content-center">
7+
<oh-colorpicker :context="context" @command="onCommand" />
8+
</f7-card-content>
9+
<f7-card-footer v-if="config.footer">
10+
{{config.footer}}
11+
</f7-card-footer>
12+
</f7-card>
13+
</template>
14+
15+
<style lang="stylus">
16+
</style>
17+
18+
<script>
19+
import mixin from '../widget-mixin'
20+
import OhColorpicker from '../system/oh-colorpicker.vue'
21+
22+
export default {
23+
mixins: [mixin],
24+
components: {
25+
OhColorpicker
26+
},
27+
widget: {
28+
name: 'oh-colorpicker-card',
29+
label: 'Simple color picker',
30+
description: 'Display a color picker in a card',
31+
props: {
32+
parameters: [
33+
{
34+
name: 'title',
35+
label: 'Title',
36+
type: 'TEXT',
37+
description: 'Title of the card'
38+
},
39+
{
40+
name: 'item',
41+
label: 'Item',
42+
type: 'TEXT',
43+
context: 'item',
44+
description: 'Item to control'
45+
},
46+
{
47+
name: 'color',
48+
label: 'Color',
49+
type: 'TEXT',
50+
description: 'Color of the control'
51+
},
52+
{
53+
name: 'footer',
54+
label: 'Footer text',
55+
type: 'TEXT',
56+
description: 'Footer of the card'
57+
},
58+
{
59+
name: 'modules',
60+
label: 'Modules',
61+
type: 'TEXT',
62+
description: 'Modules to display',
63+
multiple: true,
64+
limitToOptions: true,
65+
options: [
66+
{ value: 'wheel', label: 'Color wheel' },
67+
{ value: 'sb-spectrum', label: 'Saturation/brightness spectrum' },
68+
{ value: 'hue-slider', label: 'Hue slider' },
69+
{ value: 'hs-spectrum', label: 'Hue/saturation spectrum' },
70+
{ value: 'brightness-slider', label: 'Brightness spectrum' },
71+
{ value: 'rgb-sliders', label: 'RGB sliders' },
72+
{ value: 'hsb-sliders', label: 'HSB sliders' },
73+
{ value: 'rgb-bars', label: 'RGB bars' },
74+
{ value: 'palette', label: 'Palette' },
75+
{ value: 'current-color', label: 'Current color' },
76+
{ value: 'initial-current-colors', label: 'Initial current colors' }
77+
]
78+
}
79+
]
80+
}
81+
},
82+
data () {
83+
return {
84+
value: Math.random()
85+
}
86+
}
87+
}
88+
</script>

bundles/org.openhab.ui/web/src/components/widgets/system/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { default as OhButton } from './oh-button.vue'
44
export { default as OhLink } from './oh-link.vue'
55
export { default as OhToggle } from './oh-toggle.vue'
66
export { default as OhRollershutter } from './oh-rollershutter.vue'
7+
export { default as OhColorpîcker } from './oh-colorpicker.vue'
78
export { default as OhSlider } from './oh-slider.vue'
89
export { default as OhStepper } from './oh-stepper.vue'
910
export { default as OhPlayerControls } from './oh-player-controls.vue'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<template>
2+
<div ref="container" style="width: 100%"></div>
3+
</template>
4+
5+
<script>
6+
import mixin from '../widget-mixin'
7+
8+
export default {
9+
name: 'oh-colorpicker',
10+
mixins: [mixin],
11+
data () {
12+
return {
13+
colorpicker: null,
14+
delayCommand: false,
15+
delayUpdate: false,
16+
pendingCommand: null,
17+
pendingUpdate: null,
18+
init: false
19+
}
20+
},
21+
mounted () {
22+
if (this.color) {
23+
this.initColorpicker()
24+
}
25+
},
26+
beforeDestroy () {
27+
this.colorpicker.destroy()
28+
},
29+
computed: {
30+
color () {
31+
const state = this.context.store[this.config.item].state
32+
if (state.split(',').length === 3) {
33+
let color = this.context.store[this.config.item].state.split(',')
34+
color[0] = parseInt(color[0])
35+
color[1] = color[1] / 100
36+
color[2] = color[2] / 100
37+
return color
38+
}
39+
return null
40+
}
41+
},
42+
watch: {
43+
color (val) {
44+
if (this.colorpicker) {
45+
this.updateValue(val)
46+
} else {
47+
this.initColorpicker()
48+
}
49+
}
50+
},
51+
methods: {
52+
initColorpicker () {
53+
const vm = this
54+
this.colorpicker = this.$f7.colorPicker.create(Object.assign({}, this.config, {
55+
containerEl: this.$refs.container,
56+
modules: this.config.modules || ['hsb-sliders'],
57+
value: {
58+
hsb: this.color
59+
},
60+
on: {
61+
change (colorpicker, value) {
62+
// skip the first update
63+
if (!vm.init || vm.context.store[vm.config.item].state === '-') {
64+
vm.init = true
65+
return
66+
}
67+
if (!value.hsb) return
68+
vm.sendCommand(value.hsb)
69+
}
70+
}
71+
}))
72+
},
73+
sendCommand (hsb) {
74+
this.pendingUpdate = [...hsb]
75+
this.pendingCommand = [...hsb]
76+
const state = this.commandFromHSB(hsb)
77+
if (state !== this.context.store[this.config.item].state) {
78+
if (!this.delayCommand) {
79+
this.delayCommand = true
80+
this.delayUpdate = true
81+
this.$store.dispatch('sendCommand', { itemName: this.config.item, cmd: state })
82+
setTimeout(() => {
83+
const pendingCommand = [...this.pendingCommand]
84+
this.pendingCommand = null
85+
this.delayCommand = false
86+
if (pendingCommand != null) {
87+
this.sendCommand(pendingCommand)
88+
}
89+
}, 200)
90+
}
91+
setTimeout(() => {
92+
this.updateValue(this.pendingUpdate)
93+
this.delayUpdate = false
94+
}, 2000)
95+
}
96+
},
97+
commandFromHSB (hsb) {
98+
let state = [...hsb]
99+
state[0] = Math.round(state[0]) % 360
100+
state[1] = Math.round(state[1] * 100)
101+
state[2] = Math.round(state[2] * 100)
102+
state = state.join(',')
103+
return state
104+
},
105+
updateValue (val) {
106+
if (!this.delayUpdate) {
107+
this.colorpicker.setValue({ hsb: this.pendingUpdate || val })
108+
this.pendingUpdate = null
109+
} else {
110+
this.pendingUpdate = val
111+
}
112+
}
113+
}
114+
}
115+
</script>

bundles/org.openhab.ui/web/src/components/widgets/system/oh-toggle.vue

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default {
1717
const value = this.context.store[this.config.item].state
1818
if (value === 'ON') return true
1919
if (value === 'OFF') return false
20+
if (value.split(',').length === 3) return (value.split(',')[2] !== '0')
2021
return (['0', 'UNDEF', 'NULL', '-'].indexOf(value.toString()) < 0)
2122
}
2223
},

0 commit comments

Comments
 (0)