per effect smoothing (#456)

* add dynamic smoothing first step
* extend prio muxer to hold smoothing preset id
* add icons for systray
* fix missing changes in prio muxer
*  implement specific smoothing params for effects
* refactoring: std::min/max to qMin/Max
* some code optimization
* fix schema and translation
* revoke change of python include order
* fix eol in effect shemas
* optimize random,candle and fadecandy json schemas
This commit is contained in:
redPanther 2017-08-04 12:01:45 +02:00 committed by GitHub
parent 6625a318ac
commit 6279dcb2a9
44 changed files with 824 additions and 568 deletions

View File

@ -139,23 +139,23 @@ SET( JSON_FILES
config/hyperion.config.json.default config/hyperion.config.json.default
${HYPERION_SCHEMAS} ${HYPERION_SCHEMAS}
) )
#EXECUTE_PROCESS ( EXECUTE_PROCESS (
# COMMAND python test/jsonchecks/checkjson.py ${JSON_FILES} COMMAND python test/jsonchecks/checkjson.py ${JSON_FILES}
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
# RESULT_VARIABLE CHECK_JSON_FAILED RESULT_VARIABLE CHECK_JSON_FAILED
#) )
#IF ( ${CHECK_JSON_FAILED} ) IF ( ${CHECK_JSON_FAILED} )
# MESSAGE (FATAL_ERROR "check of json files failed" ) MESSAGE (FATAL_ERROR "check of json files failed" )
#ENDIF () ENDIF ()
#EXECUTE_PROCESS ( EXECUTE_PROCESS (
# COMMAND python test/jsonchecks/checkeffects.py effects effects/schema COMMAND python test/jsonchecks/checkeffects.py effects effects/schema
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
# RESULT_VARIABLE CHECK_EFFECTS_FAILED RESULT_VARIABLE CHECK_EFFECTS_FAILED
#) )
#IF ( ${CHECK_EFFECTS_FAILED} ) IF ( ${CHECK_EFFECTS_FAILED} )
# MESSAGE (FATAL_ERROR "check of json effect files failed" ) MESSAGE (FATAL_ERROR "check of json effect files failed" )
#ENDIF () ENDIF ()
EXECUTE_PROCESS ( EXECUTE_PROCESS (
COMMAND python test/jsonchecks/checkschema.py config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json COMMAND python test/jsonchecks/checkschema.py config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json

View File

@ -603,8 +603,15 @@
"edt_conf_log_heading_title" : "Protokoll", "edt_conf_log_heading_title" : "Protokoll",
"edt_conf_log_level_title" : "Protokollstufe", "edt_conf_log_level_title" : "Protokollstufe",
"edt_conf_log_level_expl" : "Abhängig der Stufe sind weniger oder mehr Meldungen sichtbar.", "edt_conf_log_level_expl" : "Abhängig der Stufe sind weniger oder mehr Meldungen sichtbar.",
"edt_eff_smooth_custom_title" : "Aktivere Glättung",
"edt_eff_smooth_time_ms_title" : "Glättung: Zeit",
"edt_eff_smooth_updateFrequency_title" : "Glättung: Aktualisierungsfrequenz",
"edt_eff_smooth_updateDelay_title" : "Glättung: Aktualisierungsverzögerung",
"edt_eff_smooth_pause_title" : "Glättung pausieren",
"edt_eff_candle_header" : "Kerze", "edt_eff_candle_header" : "Kerze",
"edt_eff_candle_header_desc" : "Flackerndes Kerzenlicht",
"edt_eff_police_header" : "Polizei", "edt_eff_police_header" : "Polizei",
"edt_eff_police_header_desc" : "Lights like a police car in action",
"edt_eff_fade_header" : "Farbübergang", "edt_eff_fade_header" : "Farbübergang",
"edt_eff_rainbowmood_header" : "Regenbogen", "edt_eff_rainbowmood_header" : "Regenbogen",
"edt_eff_rainbowmood_header_desc" : "Alle LEDs Regenbogen Farbübergang", "edt_eff_rainbowmood_header_desc" : "Alle LEDs Regenbogen Farbübergang",

View File

@ -604,9 +604,17 @@
"edt_conf_log_heading_title" : "Logging", "edt_conf_log_heading_title" : "Logging",
"edt_conf_log_level_title" : "Log-Level", "edt_conf_log_level_title" : "Log-Level",
"edt_conf_log_level_expl" : "Depending on loglevel you see less or more messages in your log.", "edt_conf_log_level_expl" : "Depending on loglevel you see less or more messages in your log.",
"edt_eff_smooth_custom_title" : "Enable smoothing",
"edt_eff_smooth_time_ms_title" : "Smoothing time",
"edt_eff_smooth_updateFrequency_title" : "Smoothing update frequency",
"edt_eff_smooth_updateDelay_title" : "Smoothing update delay",
"edt_eff_smooth_pause_title" : "Pause smoothing",
"edt_eff_candle_header" : "Candle", "edt_eff_candle_header" : "Candle",
"edt_eff_candle_header_desc" : "Shimmering candles",
"edt_eff_police_header" : "Police", "edt_eff_police_header" : "Police",
"edt_eff_police_header_desc" : "Lights like a police car in action",
"edt_eff_fade_header" : "Fade", "edt_eff_fade_header" : "Fade",
"edt_eff_fade_header_desc" : "Fades between colors",
"edt_eff_rainbowmood_header" : "Rainbow Mood", "edt_eff_rainbowmood_header" : "Rainbow Mood",
"edt_eff_rainbowmood_header_desc" : "All leds rainbow mood", "edt_eff_rainbowmood_header_desc" : "All leds rainbow mood",
"edt_eff_knightrider_header" : "Knight Rider", "edt_eff_knightrider_header" : "Knight Rider",

View File

@ -6,6 +6,11 @@
"sleepTime" : 0.20, "sleepTime" : 0.20,
"brightness" : 100, "brightness" : 100,
"color" : [ 255, 138, 0 ], "color" : [ 255, 138, 0 ],
"candles" : "all" "candles" : "all",
"smoothing-custom-settings" : true,
"smoothing-time_ms" : 500,
"smoothing-updateDelay" : 0,
"smoothing-updateFrequency" : 20.0,
"smoothing-pause" : false
} }
} }

View File

@ -13,12 +13,17 @@ minStepTime = float(hyperion.latchTime)/1000.0
currentR = currentG = currentB = 0 currentR = currentG = currentB = 0
# create color table for fading from start to end color # create color table for fading from start to end color
steps = float(abs(max((colorEnd[0] - colorStart[0]),max((colorEnd[1] - colorStart[1]),(colorEnd[2] - colorStart[2]))))) steps = float(max(abs(colorEnd[0] - colorStart[0]),max(abs(colorEnd[1] - colorStart[1]),abs(colorEnd[2] - colorStart[2]))))
color_step = ( color_step = (0,0,0)
(colorEnd[0] - colorStart[0]) / steps,
(colorEnd[1] - colorStart[1]) / steps, if steps == 0:
(colorEnd[2] - colorStart[2]) / steps steps = 1
) else:
color_step = (
(colorEnd[0] - colorStart[0]) / steps,
(colorEnd[1] - colorStart[1]) / steps,
(colorEnd[2] - colorStart[2]) / steps
)
calcChannel = lambda i: min(max(int(round(colorStart[i] + color_step[i]*step)),0), colorEnd[i] if colorStart[i] < colorEnd[i] else colorStart[i]) calcChannel = lambda i: min(max(int(round(colorStart[i] + color_step[i]*step)),0), colorEnd[i] if colorStart[i] < colorEnd[i] else colorStart[i])
colors = [] colors = []

View File

@ -4,6 +4,11 @@
"args" : "args" :
{ {
"speed" : 750, "speed" : 750,
"saturation" : 1.0 "saturation" : 1.0,
"smoothing-custom-settings" : true,
"smoothing-time_ms" : 200,
"smoothing-updateDelay" : 0,
"smoothing-updateFrequency" : 20.0,
"smoothing-pause" : false
} }
} }

View File

@ -67,6 +67,70 @@
"step": 0.01, "step": 0.01,
"append" : "edt_append_s", "append" : "edt_append_s",
"propertyOrder" : 6 "propertyOrder" : 6
},
"smoothing-custom-settings" :
{
"type" : "boolean",
"title" : "edt_eff_smooth_custom_title",
"default" : false,
"propertyOrder" : 7
},
"smoothing-time_ms" :
{
"type" : "integer",
"title" : "edt_eff_smooth_time_ms_title",
"minimum" : 25,
"maximum": 600,
"default" : 200,
"append" : "edt_append_ms",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 8
},
"smoothing-updateFrequency" :
{
"type" : "number",
"title" : "edt_eff_smooth_updateFrequency_title",
"minimum" : 1.0,
"maximum" : 100.0,
"default" : 25.0,
"append" : "edt_append_hz",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 9
},
"smoothing-updateDelay" :
{
"type" : "integer",
"title" : "edt_eff_smooth_updateDelay_title",
"minimum" : 0,
"maximum": 2048,
"default" : 0,
"append" : "edt_append_ms",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 10
},
"smoothing-pause" :
{
"type" : "boolean",
"title" : "edt_eff_smooth_pause_title",
"default" : false,
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 12
} }
}, },
"additionalProperties": false "additionalProperties": false

View File

@ -1,40 +1,40 @@
{ {
"type":"object", "type":"object",
"script" : "knight-rider.py", "script" : "knight-rider.py",
"title":"edt_eff_knightrider_header", "title":"edt_eff_knightrider_header",
"required":true, "required":true,
"properties":{ "properties":{
"color": { "color": {
"type": "array", "type": "array",
"title":"edt_eff_color", "title":"edt_eff_color",
"format":"colorpicker", "format":"colorpicker",
"default": [255,0,0], "default": [255,0,0],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"speed": { "speed": {
"type": "number", "type": "number",
"title":"edt_eff_speed", "title":"edt_eff_speed",
"default": 1.0, "default": 1.0,
"minimum": 0.1, "minimum": 0.1,
"step" : 0.1, "step" : 0.1,
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"fadeFactor": { "fadeFactor": {
"type": "number", "type": "number",
"title":"edt_eff_fadefactor", "title":"edt_eff_fadefactor",
"default": 0.7, "default": 0.7,
"minimum" : 0.0, "minimum" : 0.0,
"maximum" : 0.9, "maximum" : 0.9,
"step" : 0.1, "step" : 0.1,
"propertyOrder" : 3 "propertyOrder" : 3
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -76,7 +76,7 @@
"type": "integer", "type": "integer",
"title": "edt_eff_markerDepth", "title": "edt_eff_markerDepth",
"default": 5, "default": 5,
"minimum" : 1, "minimum" : 0,
"maximum" : 50, "maximum" : 50,
"append" : "edt_append_percent", "append" : "edt_append_percent",
"options": { "options": {

View File

@ -1,104 +1,104 @@
{ {
"type":"object", "type":"object",
"script" : "mood-blobs.py", "script" : "mood-blobs.py",
"title":"edt_eff_moodblobs_header", "title":"edt_eff_moodblobs_header",
"required":true, "required":true,
"properties":{ "properties":{
"color": { "color": {
"type": "array", "type": "array",
"title":"edt_eff_color", "title":"edt_eff_color",
"format":"colorpicker", "format":"colorpicker",
"default": [255,0,0], "default": [255,0,0],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"blobs": { "blobs": {
"type": "integer", "type": "integer",
"title":"edt_eff_blobcount", "title":"edt_eff_blobcount",
"default": 5, "default": 5,
"minimum" : 1, "minimum" : 1,
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"rotationTime": { "rotationTime": {
"type": "number", "type": "number",
"title":"edt_eff_rotationtime", "title":"edt_eff_rotationtime",
"default": 20.0, "default": 20.0,
"minimum" : 1.0, "minimum" : 1.0,
"append" : "edt_append_s", "append" : "edt_append_s",
"propertyOrder" : 3 "propertyOrder" : 3
}, },
"hueChange": { "hueChange": {
"type": "number", "type": "number",
"title":"edt_eff_huechange", "title":"edt_eff_huechange",
"default": 60.0, "default": 60.0,
"minimum" : 1.0, "minimum" : 1.0,
"propertyOrder" : 4 "propertyOrder" : 4
}, },
"reverse": { "reverse": {
"type": "boolean", "type": "boolean",
"title":"edt_eff_reversedirection", "title":"edt_eff_reversedirection",
"default": false, "default": false,
"propertyOrder" : 5 "propertyOrder" : 5
}, },
"colorRandom": { "colorRandom": {
"type": "boolean", "type": "boolean",
"title":"edt_eff_colorrandom", "title":"edt_eff_colorrandom",
"default": false, "default": false,
"propertyOrder" : 6 "propertyOrder" : 6
}, },
"baseChange": { "baseChange": {
"type": "boolean", "type": "boolean",
"title":"edt_eff_basecolorchange", "title":"edt_eff_basecolorchange",
"default": false, "default": false,
"propertyOrder" : 7 "propertyOrder" : 7
}, },
"baseColorRangeLeft": { "baseColorRangeLeft": {
"type": "number", "type": "number",
"title":"edt_eff_basecolorrangeleft", "title":"edt_eff_basecolorrangeleft",
"default": 0.0, "default": 0.0,
"minimum" : 0.0, "minimum" : 0.0,
"maximum" : 360.0, "maximum" : 360.0,
"append" : "edt_append_degree", "append" : "edt_append_degree",
"options": { "options": {
"dependencies": { "dependencies": {
"baseChange": true "baseChange": true
} }
}, },
"propertyOrder" : 9 "propertyOrder" : 9
}, },
"baseColorRangeRight": { "baseColorRangeRight": {
"type": "number", "type": "number",
"title":"edt_eff_basecolorrangeright", "title":"edt_eff_basecolorrangeright",
"default": 360.0, "default": 360.0,
"minimum" : 0.0, "minimum" : 0.0,
"maximum" : 360.0, "maximum" : 360.0,
"append" : "edt_append_degree", "append" : "edt_append_degree",
"options": { "options": {
"dependencies": { "dependencies": {
"baseChange": true "baseChange": true
} }
}, },
"propertyOrder" : 10 "propertyOrder" : 10
}, },
"baseColorChangeRate": { "baseColorChangeRate": {
"type": "number", "type": "number",
"title":"edt_eff_basecolorchangerate", "title":"edt_eff_basecolorchangerate",
"default": 2.0, "default": 2.0,
"minimum" : 0.0, "minimum" : 0.0,
"append" : "edt_append_sdegree", "append" : "edt_append_sdegree",
"options": { "options": {
"dependencies": { "dependencies": {
"baseChange": true "baseChange": true
} }
}, },
"propertyOrder" : 8 "propertyOrder" : 8
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -1,58 +1,58 @@
{ {
"type":"object", "type":"object",
"script" : "police.py", "script" : "police.py",
"title":"edt_eff_police_header", "title":"edt_eff_police_header",
"required":true, "required":true,
"properties":{ "properties":{
"color_one": { "color_one": {
"type": "array", "type": "array",
"title":"edt_eff_colorone", "title":"edt_eff_colorone",
"format":"colorpicker", "format":"colorpicker",
"default": [255,0,0], "default": [255,0,0],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"color_two": { "color_two": {
"type": "array", "type": "array",
"title":"edt_eff_colortwo", "title":"edt_eff_colortwo",
"format":"colorpicker", "format":"colorpicker",
"default": [0,0,255], "default": [0,0,255],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"colors_count": { "colors_count": {
"type": "integer", "type": "integer",
"title":"edt_eff_colorcount", "title":"edt_eff_colorcount",
"default": 10, "default": 10,
"minimum" : 0, "minimum" : 0,
"propertyOrder" : 3 "propertyOrder" : 3
}, },
"rotation-time": { "rotation-time": {
"type": "number", "type": "number",
"title":"edt_eff_rotationtime", "title":"edt_eff_rotationtime",
"default": 2.0, "default": 2.0,
"minimum" : 0.1, "minimum" : 0.1,
"append" : "edt_append_s", "append" : "edt_append_s",
"propertyOrder" : 4 "propertyOrder" : 4
}, },
"reverse": { "reverse": {
"type": "boolean", "type": "boolean",
"title":"edt_eff_reversedirection", "title":"edt_eff_reversedirection",
"default": false, "default": false,
"propertyOrder" : 5 "propertyOrder" : 5
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -1,26 +1,90 @@
{ {
"type":"object", "type":"object",
"script" : "random.py", "script" : "random.py",
"title":"edt_eff_random_header", "title":"edt_eff_random_header",
"required":true, "required":true,
"properties":{ "properties":{
"speed": { "speed": {
"type": "number", "type": "number",
"title":"edt_eff_speed", "title":"edt_eff_speed",
"default": 1000, "default": 1000,
"minimum" : 10, "minimum" : 10,
"append" : "edt_append_ms", "append" : "edt_append_ms",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"saturation": { "saturation": {
"type": "number", "type": "number",
"title":"edt_eff_saturation", "title":"edt_eff_saturation",
"default": 1.0, "default": 1.0,
"minimum" : 0.1, "minimum" : 0.1,
"maximum" : 1.0, "maximum" : 1.0,
"step" : 0.1, "step" : 0.1,
"propertyOrder" : 2 "propertyOrder" : 2
} },
}, "smoothing-custom-settings" :
"additionalProperties": false {
} "type" : "boolean",
"title" : "edt_eff_smooth_custom_title",
"default" : false,
"propertyOrder" : 3
},
"smoothing-time_ms" :
{
"type" : "integer",
"title" : "edt_eff_smooth_time_ms_title",
"minimum" : 25,
"maximum": 600,
"default" : 200,
"append" : "edt_append_ms",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 4
},
"smoothing-updateFrequency" :
{
"type" : "number",
"title" : "edt_eff_smooth_updateFrequency_title",
"minimum" : 1.0,
"maximum" : 100.0,
"default" : 25.0,
"append" : "edt_append_hz",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 5
},
"smoothing-updateDelay" :
{
"type" : "integer",
"title" : "edt_eff_smooth_updateDelay_title",
"minimum" : 0,
"maximum": 2048,
"default" : 0,
"append" : "edt_append_ms",
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 6
},
"smoothing-pause" :
{
"type" : "boolean",
"title" : "edt_eff_smooth_pause_title",
"default" : false,
"options": {
"dependencies": {
"smoothing-custom-settings": true
}
},
"propertyOrder" : 7
}
},
"additionalProperties": false
}

View File

@ -1,32 +1,32 @@
{ {
"type":"object", "type":"object",
"script" : "running_dots.py", "script" : "running_dots.py",
"title":"edt_eff_runningdots_header", "title":"edt_eff_runningdots_header",
"required":true, "required":true,
"properties":{ "properties":{
"speed": { "speed": {
"type": "number", "type": "number",
"title":"edt_eff_speed", "title":"edt_eff_speed",
"default": 1.5, "default": 1.5,
"minimum" : 0.1, "minimum" : 0.1,
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"colorLevel": { "colorLevel": {
"type": "integer", "type": "integer",
"title":"edt_eff_colorevel", "title":"edt_eff_colorevel",
"default": 220, "default": 220,
"minimium" : 0, "minimium" : 0,
"maximum" : 255, "maximum" : 255,
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"whiteLevel": { "whiteLevel": {
"type": "integer", "type": "integer",
"title":"edt_eff_whitelevel", "title":"edt_eff_whitelevel",
"default": 0, "default": 0,
"minimium" : 0, "minimium" : 0,
"maximum" : 254, "maximum" : 254,
"propertyOrder" : 3 "propertyOrder" : 3
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -1,38 +1,38 @@
{ {
"type":"object", "type":"object",
"script" : "snake.py", "script" : "snake.py",
"title":"edt_eff_snake_header", "title":"edt_eff_snake_header",
"required":true, "required":true,
"properties":{ "properties":{
"color": { "color": {
"type": "array", "type": "array",
"title":"edt_eff_color", "title":"edt_eff_color",
"format":"colorpicker", "format":"colorpicker",
"default": [255,0,0], "default": [255,0,0],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rotation-time": { "rotation-time": {
"type": "number", "type": "number",
"title":"edt_eff_rotationtime", "title":"edt_eff_rotationtime",
"default": 12.0, "default": 12.0,
"minimum" : 0.1, "minimum" : 0.1,
"append" : "edt_append_s", "append" : "edt_append_s",
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"percentage": { "percentage": {
"type": "integer", "type": "integer",
"title":"edt_eff_length", "title":"edt_eff_length",
"default": 10, "default": 10,
"append" : "edt_append_percent", "append" : "edt_append_percent",
"propertyOrder" : 3 "propertyOrder" : 3
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -1,69 +1,69 @@
{ {
"type":"object", "type":"object",
"script" : "sparks.py", "script" : "sparks.py",
"title":"edt_eff_sparks_header", "title":"edt_eff_sparks_header",
"required":true, "required":true,
"properties":{ "properties":{
"color": { "color": {
"type": "array", "type": "array",
"title":"edt_eff_color", "title":"edt_eff_color",
"format":"colorpicker", "format":"colorpicker",
"default": [255,0,0], "default": [255,0,0],
"items" : { "items" : {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 255 "maximum": 255
}, },
"minItems": 3, "minItems": 3,
"maxItems": 3, "maxItems": 3,
"options": { "options": {
"dependencies": { "dependencies": {
"random-color": false "random-color": false
} }
}, },
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rotation-time": { "rotation-time": {
"type": "number", "type": "number",
"title":"edt_eff_rotationtime", "title":"edt_eff_rotationtime",
"default": 2.0, "default": 2.0,
"minimum" : 0.1, "minimum" : 0.1,
"append" : "edt_append_s", "append" : "edt_append_s",
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"sleep-time": { "sleep-time": {
"type": "number", "type": "number",
"title":"edt_eff_sleeptime", "title":"edt_eff_sleeptime",
"default": 0.05, "default": 0.05,
"minimum" : 0.01, "minimum" : 0.01,
"propertyOrder" : 3 "propertyOrder" : 3
}, },
"brightness": { "brightness": {
"type": "integer", "type": "integer",
"title":"edt_eff_brightness", "title":"edt_eff_brightness",
"default": 100, "default": 100,
"minimum" : 0, "minimum" : 0,
"maximum" : 100, "maximum" : 100,
"step" : 10, "step" : 10,
"append" : "edt_append_percent", "append" : "edt_append_percent",
"propertyOrder" : 4 "propertyOrder" : 4
}, },
"saturation": { "saturation": {
"type": "integer", "type": "integer",
"title":"edt_eff_saturation", "title":"edt_eff_saturation",
"default": 100, "default": 100,
"minimum" : 0, "minimum" : 0,
"maximum" : 100, "maximum" : 100,
"step" : 10, "step" : 10,
"append" : "edt_append_percent", "append" : "edt_append_percent",
"propertyOrder" : 5 "propertyOrder" : 5
}, },
"random-color": { "random-color": {
"type": "boolean", "type": "boolean",
"title":"edt_eff_colorrandom", "title":"edt_eff_colorrandom",
"default": false, "default": false,
"propertyOrder" : 6 "propertyOrder" : 6
} }
}, },
"additionalProperties": false "additionalProperties": false
} }

View File

@ -8,4 +8,5 @@ struct EffectDefinition
{ {
QString name, script, file; QString name, script, file;
QJsonObject args; QJsonObject args;
unsigned smoothCfg;
}; };

View File

@ -48,7 +48,7 @@ public slots:
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System"); int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
/// Run the specified effect on the given priority channel and optionally specify a timeout /// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System"); int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System", unsigned smoothCfg=0);
/// Clear any effect running on the provided channel /// Clear any effect running on the provided channel
void channelCleared(int priority); void channelCleared(int priority);
@ -65,7 +65,7 @@ private:
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema); bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
/// Run the specified effect on the given priority channel and optionally specify a timeout /// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System"); int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System", unsigned smoothCfg=0);
private: private:
Hyperion * _hyperion; Hyperion * _hyperion;

View File

@ -47,6 +47,7 @@ class EffectEngine;
class RgbChannelAdjustment; class RgbChannelAdjustment;
class MultiColorAdjustment; class MultiColorAdjustment;
class KODIVideoChecker; class KODIVideoChecker;
/// ///
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through /// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
/// the priority muxer. /// the priority muxer.
@ -187,6 +188,9 @@ public:
QString id; QString id;
int getLatchTime() const; int getLatchTime() const;
/// forward smoothing config
unsigned addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
public slots: public slots:
/// ///
@ -206,8 +210,9 @@ public slots:
/// @param[in] timeout_ms The time the leds are set to the given colors [ms] /// @param[in] timeout_ms The time the leds are set to the given colors [ms]
/// @param[in] component The current component /// @param[in] component The current component
/// @param[in] origin Who set it /// @param[in] origin Who set it
/// @param[in] smoothCfg smoothing config id
/// ///
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System"); void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smoothCfg=SMOOTHING_MODE_DEFAULT);
/// ///
/// Writes the given colors to all leds for the given time and priority /// Writes the given colors to all leds for the given time and priority

View File

@ -15,6 +15,11 @@
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/Components.h> #include <utils/Components.h>
// global defines
#define SMOOTHING_MODE_DEFAULT 0
#define SMOOTHING_MODE_PAUSE 1
/// ///
/// The PriorityMuxer handles the priority channels. Led values input is written to the priority map /// The PriorityMuxer handles the priority channels. Led values input is written to the priority map
/// and the muxer keeps track of all active priorities. The current priority can be queried and per /// and the muxer keeps track of all active priorities. The current priority can be queried and per
@ -40,6 +45,8 @@ public:
hyperion::Components componentId; hyperion::Components componentId;
/// Who set it /// Who set it
QString origin; QString origin;
/// id fo smoothing config
unsigned smooth_cfg;
}; };
/// The lowest possible priority, which is used when no priority channels are active /// The lowest possible priority, which is used when no priority channels are active
@ -99,7 +106,7 @@ public:
/// @param[in] component The component of the channel /// @param[in] component The component of the channel
/// @param[in] origin Who set the channel /// @param[in] origin Who set the channel
/// ///
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms=-1, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System"); void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms=-1, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smooth_cfg=SMOOTHING_MODE_DEFAULT);
/// ///
/// Clears the specified priority channel /// Clears the specified priority channel

View File

@ -78,13 +78,14 @@ void Effect::registerHyperionExtensionModule()
PyImport_AppendInittab("hyperion", &PyInit_hyperion); PyImport_AppendInittab("hyperion", &PyInit_hyperion);
} }
Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin) Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin, unsigned smoothCfg)
: QThread() : QThread()
, _mainThreadState(mainThreadState) , _mainThreadState(mainThreadState)
, _priority(priority) , _priority(priority)
, _timeout(timeout) , _timeout(timeout)
, _script(script) , _script(script)
, _name(name) , _name(name)
, _smoothCfg(smoothCfg)
, _args(args) , _args(args)
, _endTime(-1) , _endTime(-1)
, _interpreterThreadState(nullptr) , _interpreterThreadState(nullptr)
@ -93,7 +94,7 @@ Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const
, _colors() , _colors()
, _origin(origin) , _origin(origin)
, _imageSize(Hyperion::getInstance()->getLedGridSize()) , _imageSize(Hyperion::getInstance()->getLedGridSize())
,_image(_imageSize,QImage::Format_ARGB32_Premultiplied) , _image(_imageSize,QImage::Format_ARGB32_Premultiplied)
{ {
_colors.resize(_imageProcessor->getLedCount()); _colors.resize(_imageProcessor->getLedCount());
_colors.fill(ColorRgb::BLACK); _colors.fill(ColorRgb::BLACK);
@ -277,7 +278,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue)) if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
{ {
effect->_colors.fill(color); effect->_colors.fill(color);
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin); effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
return Py_BuildValue(""); return Py_BuildValue("");
} }
return nullptr; return nullptr;
@ -295,7 +296,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
{ {
char * data = PyByteArray_AS_STRING(bytearray); char * data = PyByteArray_AS_STRING(bytearray);
memcpy(effect->_colors.data(), data, length); memcpy(effect->_colors.data(), data, length);
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin); effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
return Py_BuildValue(""); return Py_BuildValue("");
} }
else else
@ -365,7 +366,7 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
memcpy(image.memptr(), data, length); memcpy(image.memptr(), data, length);
std::vector<ColorRgb> v = effect->_colors.toStdVector(); std::vector<ColorRgb> v = effect->_colors.toStdVector();
effect->_imageProcessor->process(image, v); effect->_imageProcessor->process(image, v);
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin); effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
return Py_BuildValue(""); return Py_BuildValue("");
} }
else else
@ -456,7 +457,7 @@ PyObject* Effect::wrapImageShow(PyObject *self, PyObject *args)
memcpy(image.memptr(), binaryImage.data(), binaryImage.size()); memcpy(image.memptr(), binaryImage.data(), binaryImage.size());
std::vector<ColorRgb> v = effect->_colors.toStdVector(); std::vector<ColorRgb> v = effect->_colors.toStdVector();
effect->_imageProcessor->process(image, v); effect->_imageProcessor->process(image, v);
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin); effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -552,7 +553,7 @@ PyObject* Effect::wrapImageConicalGradient(PyObject *self, PyObject *args)
{ {
argsOK = true; argsOK = true;
} }
angle = std::max(std::min(angle,360),0); angle = qMax(qMin(angle,360),0);
if (argsOK) if (argsOK)
{ {
@ -644,7 +645,7 @@ PyObject* Effect::wrapImageRadialGradient(PyObject *self, PyObject *args)
{ {
QRect myQRect(startX,startY,width,height); QRect myQRect(startX,startY,width,height);
QRadialGradient gradient(QPoint(centerX,centerY), std::max(radius,0) ); QRadialGradient gradient(QPoint(centerX,centerY), qMax(radius,0) );
char * data = PyByteArray_AS_STRING(bytearray); char * data = PyByteArray_AS_STRING(bytearray);
for (int idx=0; idx<length; idx+=4) for (int idx=0; idx<length; idx+=4)
@ -774,8 +775,8 @@ PyObject* Effect::wrapImageDrawPie(PyObject *self, PyObject *args)
if (argsOK) if (argsOK)
{ {
QPainter * painter = effect->_painter; QPainter * painter = effect->_painter;
startAngle = std::max(std::min(startAngle,360),0); startAngle = qMax(qMin(startAngle,360),0);
spanAngle = std::max(std::min(spanAngle,360),-360); spanAngle = qMax(qMin(spanAngle,360),-360);
if( argCount == 7 || argCount == 5 ) if( argCount == 7 || argCount == 5 )
{ {
@ -1045,7 +1046,7 @@ PyObject* Effect::wrapImageMinSize(PyObject *self, PyObject *args)
{ {
delete effect->_painter; delete effect->_painter;
effect->_image = effect->_image.scaled(std::max(width,w),std::max(height,h), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); effect->_image = effect->_image.scaled(qMax(width,w),qMax(height,h), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
effect->_imageSize = effect->_image.size(); effect->_imageSize = effect->_image.size();
effect->_painter = new QPainter(&(effect->_image)); effect->_painter = new QPainter(&(effect->_image));
} }
@ -1075,7 +1076,7 @@ PyObject* Effect::wrapImageCRotate(PyObject *self, PyObject *args)
if ( argCount == 1 && PyArg_ParseTuple(args, "i", &angle ) ) if ( argCount == 1 && PyArg_ParseTuple(args, "i", &angle ) )
{ {
angle = std::max(std::min(angle,360),0); angle = qMax(qMin(angle,360),0);
effect->_painter->rotate(angle); effect->_painter->rotate(angle);
return Py_BuildValue(""); return Py_BuildValue("");
} }

View File

@ -19,7 +19,7 @@ class Effect : public QThread
Q_OBJECT Q_OBJECT
public: public:
Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System"); Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System", unsigned smoothCfg=0);
virtual ~Effect(); virtual ~Effect();
virtual void run(); virtual void run();
@ -44,7 +44,7 @@ public slots:
signals: signals:
void effectFinished(Effect * effect); void effectFinished(Effect * effect);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin); void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin, unsigned smoothCfg);
private slots: private slots:
void effectFinished(); void effectFinished();
@ -96,6 +96,7 @@ private:
const QString _script; const QString _script;
const QString _name; const QString _name;
unsigned _smoothCfg;
const QJsonObject _args; const QJsonObject _args;
@ -112,10 +113,10 @@ private:
QVector<ColorRgb> _colors; QVector<ColorRgb> _colors;
QString _origin; QString _origin;
QSize _imageSize; QSize _imageSize;
QImage _image; QImage _image;
QPainter* _painter; QPainter* _painter;
QVector<QImage> _imageStack; QVector<QImage> _imageStack;
}; };

View File

@ -2,14 +2,12 @@
#include <Python.h> #include <Python.h>
#undef B0 #undef B0
// Stl includes
#include <fstream>
// Qt includes // Qt includes
#include <QResource> #include <QResource>
#include <QMetaType> #include <QMetaType>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QMap>
// hyperion util includes // hyperion util includes
#include <utils/jsonschema/QJsonSchemaChecker.h> #include <utils/jsonschema/QJsonSchemaChecker.h>
@ -41,7 +39,7 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const QJsonObject & jsonEffectCo
readEffects(); readEffects();
// initialize the python interpreter // initialize the python interpreter
Debug(_log,"Initializing Python interpreter"); Debug(_log, "Initializing Python interpreter");
Effect::registerHyperionExtensionModule(); Effect::registerHyperionExtensionModule();
Py_InitializeEx(0); Py_InitializeEx(0);
PyEval_InitThreads(); // Create the GIL PyEval_InitThreads(); // Create the GIL
@ -63,11 +61,11 @@ const std::list<ActiveEffectDefinition> &EffectEngine::getActiveEffects()
for (Effect * effect : _activeEffects) for (Effect * effect : _activeEffects)
{ {
ActiveEffectDefinition activeEffectDefinition; ActiveEffectDefinition activeEffectDefinition;
activeEffectDefinition.script = effect->getScript(); activeEffectDefinition.script = effect->getScript();
activeEffectDefinition.name = effect->getName(); activeEffectDefinition.name = effect->getName();
activeEffectDefinition.priority = effect->getPriority(); activeEffectDefinition.priority = effect->getPriority();
activeEffectDefinition.timeout = effect->getTimeout(); activeEffectDefinition.timeout = effect->getTimeout();
activeEffectDefinition.args = effect->getArgs(); activeEffectDefinition.args = effect->getArgs();
_availableActiveEffects.push_back(activeEffectDefinition); _availableActiveEffects.push_back(activeEffectDefinition);
} }
@ -86,7 +84,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
QFile file(fileName); QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) if (!file.open(QIODevice::ReadOnly))
{ {
Error( log, "Effect file '%s' could not be loaded", fileName.toUtf8().constData()); Error( log, "Effect file '%s' could not be loaded", QSTRING_CSTR(fileName));
return false; return false;
} }
@ -108,7 +106,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
} }
} }
Error( log, "Error while reading effect: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn); Error( log, "Error while reading effect: '%s' at Line: '%i' , Column: %i",QSTRING_CSTR( error.errorString()), errorLine, errorColumn);
} }
file.close(); file.close();
@ -120,7 +118,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
if (!schema.open(QIODevice::ReadOnly)) if (!schema.open(QIODevice::ReadOnly))
{ {
Error( log, "Schema not found: %s", schema.errorString().toUtf8().constData()); Error( log, "Schema not found: %s", QSTRING_CSTR(schema.errorString()));
return false; return false;
} }
@ -142,7 +140,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
} }
} }
Error( log, "ERROR: Json schema wrong: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn); Error( log, "ERROR: Json schema wrong: '%s' at Line: '%i' , Column: %i", QSTRING_CSTR(error.errorString()), errorLine, errorColumn);
} }
schema.close(); schema.close();
@ -154,7 +152,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
if (!schemaChecker.validate(configEffect.object()).first) if (!schemaChecker.validate(configEffect.object()).first)
{ {
const QStringList & errors = schemaChecker.getMessages(); const QStringList & errors = schemaChecker.getMessages();
foreach (auto & error, errors) for (auto & error : errors)
{ {
Error( log, "Error while checking '%s':%s", QSTRING_CSTR(fileName), QSTRING_CSTR(error)); Error( log, "Error while checking '%s':%s", QSTRING_CSTR(fileName), QSTRING_CSTR(error));
} }
@ -180,12 +178,27 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
} else } else
{ {
(!fileInfo.exists()) (!fileInfo.exists())
? effectDefinition.script = path + QDir::separator().toLatin1() + scriptName ? effectDefinition.script = path + QDir::separator() + scriptName
: effectDefinition.script = scriptName; : effectDefinition.script = scriptName;
} }
effectDefinition.args = config["args"].toObject(); effectDefinition.args = config["args"].toObject();
effectDefinition.smoothCfg = SMOOTHING_MODE_PAUSE;
if (effectDefinition.args["smoothing-custom-settings"].toBool())
{
bool pause = effectDefinition.args["smoothing-pause"].toBool();
if (pause)
{
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(pause);
}
else
{
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(
effectDefinition.args["smoothing-time_ms"].toInt(),
effectDefinition.args["smoothing-updateFrequency"].toDouble(),
effectDefinition.args["smoothing-updateDelay"].toInt() );
}
}
return true; return true;
} }
@ -201,7 +214,7 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
QFile file(fileName); QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) if (!file.open(QIODevice::ReadOnly))
{ {
Error( log, "Effect schema '%s' could not be loaded", fileName.toUtf8().constData()); Error( log, "Effect schema '%s' could not be loaded", QSTRING_CSTR(fileName));
return false; return false;
} }
@ -223,7 +236,7 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
} }
} }
Error( log, "Error while reading effect schema: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn); Error( log, "Error while reading effect schema: '%s' at Line: '%i' , Column: %i", QSTRING_CSTR(error.errorString()), errorLine, errorColumn);
return false; return false;
} }
@ -240,17 +253,13 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly)) if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly))
{ {
fileName = path + "schema/" + QDir::separator() + effectSchemaFile; fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
Error( log, "Python script '%s' in effect schema '%s' could not be loaded", scriptName.toUtf8().constData(), fileName.toUtf8().constData()); Error( log, "Python script '%s' in effect schema '%s' could not be loaded", QSTRING_CSTR(scriptName), QSTRING_CSTR(fileName));
return false; return false;
} }
pyFile.close(); pyFile.close();
if (scriptName.mid(0, 1) == ":" ) effectSchema.pyFile = (scriptName.mid(0, 1) == ":" ) ? ":/effects/"+scriptName.mid(1) : path + QDir::separator() + scriptName;
effectSchema.pyFile = ":/effects/"+scriptName.mid(1);
else
effectSchema.pyFile = path + QDir::separator().toLatin1() + scriptName;
effectSchema.pySchema = tempSchemaEffect; effectSchema.pySchema = tempSchemaEffect;
return true; return true;
@ -279,38 +288,36 @@ void EffectEngine::readEffects()
disableList << efx.toString(); disableList << efx.toString();
} }
std::map<QString, EffectDefinition> availableEffects; QMap<QString, EffectDefinition> availableEffects;
foreach (const QString & path, efxPathList ) for (const QString & path : efxPathList )
{ {
QDir directory(path); QDir directory(path);
if (!directory.exists()) if (!directory.exists())
{ {
if(directory.mkpath(path)) if(directory.mkpath(path))
{ {
Warning(_log, "New Effect path \"%s\" created successfull",path.toUtf8().constData() ); Warning(_log, "New Effect path \"%s\" created successfull", QSTRING_CSTR(path) );
} }
else else
{ {
Warning(_log, "Failed to create Effect path \"%s\", please check permissions",path.toUtf8().constData() ); Warning(_log, "Failed to create Effect path \"%s\", please check permissions", QSTRING_CSTR(path) );
} }
} }
else else
{ {
int efxCount = 0; int efxCount = 0;
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase); QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
foreach (const QString & filename, filenames) for (const QString & filename : filenames)
{ {
EffectDefinition def; EffectDefinition def;
if (loadEffectDefinition(path, filename, def)) if (loadEffectDefinition(path, filename, def))
{ {
if (availableEffects.find(def.name) != availableEffects.end()) InfoIf(availableEffects.find(def.name) != availableEffects.end(), _log,
{ "effect overload effect '%s' is now taken from %s'", QSTRING_CSTR(def.name), QSTRING_CSTR(path) );
Info(_log, "effect overload effect '%s' is now taken from %s'", def.name.toUtf8().constData(), path.toUtf8().constData() );
}
if ( disableList.contains(def.name) ) if ( disableList.contains(def.name) )
{ {
Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", def.name.toUtf8().constData()); Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", QSTRING_CSTR(def.name));
} }
else else
{ {
@ -319,13 +326,13 @@ void EffectEngine::readEffects()
} }
} }
} }
Info(_log, "%d effects loaded from directory %s", efxCount, path.toUtf8().constData()); Info(_log, "%d effects loaded from directory %s", efxCount, QSTRING_CSTR(path));
// collect effect schemas // collect effect schemas
efxCount = 0; efxCount = 0;
directory = path + "schema/"; directory = path + "schema/";
QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase); QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
foreach (const QString & pyname, pynames) for (const QString & pyname : pynames)
{ {
EffectSchema pyEffect; EffectSchema pyEffect;
if (loadEffectSchema(path, pyname, pyEffect)) if (loadEffectSchema(path, pyname, pyEffect))
@ -334,20 +341,16 @@ void EffectEngine::readEffects()
efxCount++; efxCount++;
} }
} }
if (efxCount > 0) InfoIf(efxCount > 0, _log, "%d effect schemas loaded from directory %s", efxCount, QSTRING_CSTR((path + "schema/")));
Info(_log, "%d effect schemas loaded from directory %s", efxCount, (path + "schema/").toUtf8().constData());
} }
} }
foreach(auto item, availableEffects) for(auto item : availableEffects)
{ {
_availableEffects.push_back(item.second); _availableEffects.push_back(item);
} }
if (_availableEffects.size() == 0) ErrorIf(_availableEffects.size()==0, _log, "no effects found, check your effect directories");
{
Error(_log, "no effects found, check your effect directories");
}
} }
int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin) int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin)
@ -355,9 +358,9 @@ int EffectEngine::runEffect(const QString &effectName, int priority, int timeout
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin); return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
} }
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin) int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg)
{ {
Info( _log, "run effect %s on channel %d", effectName.toUtf8().constData(), priority); Info( _log, "run effect %s on channel %d", QSTRING_CSTR(effectName), priority);
if (pythonScript.isEmpty()) if (pythonScript.isEmpty())
{ {
@ -373,23 +376,23 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
if (effectDefinition == nullptr) if (effectDefinition == nullptr)
{ {
// no such effect // no such effect
Error(_log, "effect %s not found", effectName.toUtf8().constData()); Error(_log, "effect %s not found", QSTRING_CSTR(effectName));
return -1; return -1;
} }
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin); return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin, effectDefinition->smoothCfg);
} }
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin); return runEffectScript(pythonScript, effectName, args, priority, timeout, origin, smoothCfg);
} }
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin) int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin, unsigned smoothCfg)
{ {
// clear current effect on the channel // clear current effect on the channel
channelCleared(priority); channelCleared(priority);
// create the effect // create the effect
Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin); Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin, smoothCfg);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), Qt::QueuedConnection); connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString,unsigned)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString,unsigned)), Qt::QueuedConnection);
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*))); connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
_activeEffects.push_back(effect); _activeEffects.push_back(effect);

View File

@ -31,8 +31,8 @@
#endif #endif
AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height) AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height)
: _width(std::max(160u, width)) // Minimum required width or height is 160 : _width(qMax(160u, width)) // Minimum required width or height is 160
, _height(std::max(160u, height)) , _height(qMax(160u, height))
, _amlogicCaptureDev(-1) , _amlogicCaptureDev(-1)
, _log(Logger::getInstance("AMLOGICGRABBER")) , _log(Logger::getInstance("AMLOGICGRABBER"))
{ {

View File

@ -44,7 +44,7 @@ V4L2Grabber::V4L2Grabber(const QString & device
, _height(height) , _height(height)
, _lineLength(-1) , _lineLength(-1)
, _frameByteSize(-1) , _frameByteSize(-1)
, _frameDecimation(std::max(1, frameDecimation)) , _frameDecimation(qMax(1, frameDecimation))
, _noSignalCounterThreshold(50) , _noSignalCounterThreshold(50)
, _noSignalThresholdColor(ColorRgb{0,0,0}) , _noSignalThresholdColor(ColorRgb{0,0,0})
, _signalDetectionEnabled(true) , _signalDetectionEnabled(true)
@ -62,8 +62,8 @@ V4L2Grabber::V4L2Grabber(const QString & device
, _deviceAutoDiscoverEnabled(false) , _deviceAutoDiscoverEnabled(false)
{ {
_imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); _imageResampler.setHorizontalPixelDecimation(qMax(1, horizontalPixelDecimation));
_imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); _imageResampler.setVerticalPixelDecimation(qMax(1, verticalPixelDecimation));
getV4Ldevices(); getV4Ldevices();
} }
@ -198,7 +198,7 @@ void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSign
_noSignalThresholdColor.red = uint8_t(255*redSignalThreshold); _noSignalThresholdColor.red = uint8_t(255*redSignalThreshold);
_noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold); _noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold);
_noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold); _noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold);
_noSignalCounterThreshold = std::max(1, noSignalCounterThreshold); _noSignalCounterThreshold = qMax(1, noSignalCounterThreshold);
Info(_log, "Signal threshold set to: {%d, %d, %d}", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue ); Info(_log, "Signal threshold set to: {%d, %d, %d}", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue );
} }

View File

@ -1,9 +1,4 @@
// STL includes
#include <iostream>
#include <cstdint>
#include <utils/Logger.h> #include <utils/Logger.h>
// X11Grabber includes
#include <grabber/X11Grabber.h> #include <grabber/X11Grabber.h>
X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation)
@ -137,7 +132,7 @@ Image<ColorRgb> & X11Grabber::grab()
{ {
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width); double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height); double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
double scale = std::min(scale_y, scale_x); double scale = qMin(scale_y, scale_x);
_transform = _transform =
{ {
@ -215,7 +210,7 @@ int X11Grabber::grabFrame(Image<ColorRgb> & image)
{ {
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width); double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height); double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
double scale = std::min(scale_y, scale_x); double scale = qMin(scale_y, scale_x);
_transform = _transform =
{ {

View File

@ -1,10 +1,8 @@
// STL includes // STL includes
#include <cassert>
#include <exception> #include <exception>
#include <sstream> #include <sstream>
#include <unistd.h> #include <unistd.h>
#include <iostream>
// QT includes // QT includes
#include <QDateTime> #include <QDateTime>
@ -208,10 +206,10 @@ LedString Hyperion::createLedString(const QJsonValue& ledsConfig, const ColorOrd
{ {
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject(); const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject(); const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
led.minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].toDouble())); led.minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
led.maxX_frac = std::max(0.0, std::min(1.0, hscanConfig["maximum"].toDouble())); led.maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
led.minY_frac = std::max(0.0, std::min(1.0, vscanConfig["minimum"].toDouble())); led.minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
led.maxY_frac = std::max(0.0, std::min(1.0, vscanConfig["maximum"].toDouble())); led.maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
// Fix if the user swapped min and max // Fix if the user swapped min and max
if (led.minX_frac > led.maxX_frac) if (led.minX_frac > led.maxX_frac)
{ {
@ -287,10 +285,10 @@ QSize Hyperion::getLedLayoutGridSize(const QJsonValue& ledsConfig)
{ {
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject(); const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject(); const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
double minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].toDouble())); double minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
double maxX_frac = std::max(0.0, std::min(1.0, hscanConfig["maximum"].toDouble())); double maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
double minY_frac = std::max(0.0, std::min(1.0, vscanConfig["minimum"].toDouble())); double minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
double maxY_frac = std::max(0.0, std::min(1.0, vscanConfig["maximum"].toDouble())); double maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
// Fix if the user swapped min and max // Fix if the user swapped min and max
if (minX_frac > maxX_frac) if (minX_frac > maxX_frac)
{ {
@ -345,7 +343,7 @@ LinearColorSmoothing * Hyperion::createColorSmoothing(const QJsonObject & smooth
device->setEnable(smoothingConfig["enable"].toBool(true)); device->setEnable(smoothingConfig["enable"].toBool(true));
InfoIf(!device->enabled(), CORE_LOGGER,"Smoothing disabled"); InfoIf(!device->enabled(), CORE_LOGGER,"Smoothing disabled");
assert(device != nullptr); Q_ASSERT(device != nullptr);
return device; return device;
} }
@ -427,6 +425,8 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState()); getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState());
getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState()); getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState());
_deviceSmooth->addConfig(true); // add pause to config 1
// setup the timer // setup the timer
_timer.setSingleShot(true); _timer.setSingleShot(true);
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update())); QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
@ -436,12 +436,12 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
QObject::connect(&_timerBonjourResolver, SIGNAL(timeout()), this, SLOT(bonjourResolve())); QObject::connect(&_timerBonjourResolver, SIGNAL(timeout()), this, SLOT(bonjourResolve()));
_timerBonjourResolver.start(); _timerBonjourResolver.start();
// create the effect engine // create the effect engine, must be initialized after smoothing!
_effectEngine = new EffectEngine(this,qjsonConfig["effects"].toObject() ); _effectEngine = new EffectEngine(this,qjsonConfig["effects"].toObject() );
const QJsonObject& device = qjsonConfig["device"].toObject(); const QJsonObject& device = qjsonConfig["device"].toObject();
unsigned int hwLedCount = device["ledCount"].toInt(getLedCount()); unsigned int hwLedCount = device["ledCount"].toInt(getLedCount());
_hwLedCount = std::max(hwLedCount, getLedCount()); _hwLedCount = qMax(hwLedCount, getLedCount());
Debug(_log,"configured leds: %d hw leds: %d", getLedCount(), _hwLedCount); Debug(_log,"configured leds: %d hw leds: %d", getLedCount(), _hwLedCount);
WarningIf(hwLedCount < getLedCount(), _log, "more leds configured than available. check 'ledCount' in 'device' section"); WarningIf(hwLedCount < getLedCount(), _log, "more leds configured than available. check 'ledCount' in 'device' section");
@ -478,6 +478,11 @@ int Hyperion::getLatchTime() const
return _device->getLatchTime(); return _device->getLatchTime();
} }
unsigned Hyperion::addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
{
return _deviceSmooth->addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
}
void Hyperion::freeObjects(bool emitCloseSignal) void Hyperion::freeObjects(bool emitCloseSignal)
{ {
if (emitCloseSignal) if (emitCloseSignal)
@ -664,7 +669,7 @@ void Hyperion::setColor(int priority, const ColorRgb &color, const int timeout_m
setColors(priority, ledColors, timeout_ms, clearEffects, hyperion::COMP_COLOR); setColors(priority, ledColors, timeout_ms, clearEffects, hyperion::COMP_COLOR);
} }
void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component, const QString origin) void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component, const QString origin, unsigned smoothCfg)
{ {
// clear effects if this call does not come from an effect // clear effects if this call does not come from an effect
if (clearEffects) if (clearEffects)
@ -675,11 +680,11 @@ void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, c
if (timeout_ms > 0) if (timeout_ms > 0)
{ {
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms; const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
_muxer.setInput(priority, ledColors, timeoutTime, component, origin); _muxer.setInput(priority, ledColors, timeoutTime, component, origin, smoothCfg);
} }
else else
{ {
_muxer.setInput(priority, ledColors, -1, component, origin); _muxer.setInput(priority, ledColors, -1, component, origin, smoothCfg);
} }
if (! _sourceAutoSelectEnabled || priority == _muxer.getCurrentPriority()) if (! _sourceAutoSelectEnabled || priority == _muxer.getCurrentPriority())
@ -891,7 +896,8 @@ void Hyperion::update()
// Write the data to the device // Write the data to the device
if (_device->enabled()) if (_device->enabled())
{ {
_deviceSmooth->setPause(priorityInfo.componentId == hyperion::COMP_EFFECT); _deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
// feed smoothing in pause mode to maintain a smooth transistion back to smoth mode // feed smoothing in pause mode to maintain a smooth transistion back to smoth mode
if (_deviceSmooth->enabled() || _deviceSmooth->pause()) if (_deviceSmooth->enabled() || _deviceSmooth->pause())
_deviceSmooth->setLedValues(_ledBuffer); _deviceSmooth->setLedValues(_ledBuffer);
@ -907,9 +913,9 @@ void Hyperion::update()
} }
else else
{ {
int timeout_ms = std::max(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch())); int timeout_ms = qMax(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch()));
// std::min() 200ms forced refresh if color is active to update priorityMuxer properly for forced serverinfo push // qMin() 200ms forced refresh if color is active to update priorityMuxer properly for forced serverinfo push
_timer.start(std::min(timeout_ms, 200)); _timer.start(qMin(timeout_ms, 200));
} }
} }

View File

@ -1,9 +1,3 @@
// STL includes
#include <algorithm>
#include <cmath>
#include <cassert>
// hyperion includes
#include <hyperion/ImageToLedsMap.h> #include <hyperion/ImageToLedsMap.h>
using namespace hyperion; using namespace hyperion;
@ -21,8 +15,8 @@ ImageToLedsMap::ImageToLedsMap(
, _colorsMap() , _colorsMap()
{ {
// Sanity check of the size of the borders (and width and height) // Sanity check of the size of the borders (and width and height)
assert(_width > 2*_verticalBorder); Q_ASSERT(_width > 2*_verticalBorder);
assert(_height > 2*_horizontalBorder); Q_ASSERT(_height > 2*_horizontalBorder);
// Reserve enough space in the map for the leds // Reserve enough space in the map for the leds
_colorsMap.reserve(leds.size()); _colorsMap.reserve(leds.size());
@ -42,18 +36,18 @@ ImageToLedsMap::ImageToLedsMap(
} }
// Compute the index boundaries for this led // Compute the index boundaries for this led
unsigned minX_idx = xOffset + unsigned(std::round(actualWidth * led.minX_frac)); unsigned minX_idx = xOffset + unsigned(qRound(actualWidth * led.minX_frac));
unsigned maxX_idx = xOffset + unsigned(std::round(actualWidth * led.maxX_frac)); unsigned maxX_idx = xOffset + unsigned(qRound(actualWidth * led.maxX_frac));
unsigned minY_idx = yOffset + unsigned(std::round(actualHeight * led.minY_frac)); unsigned minY_idx = yOffset + unsigned(qRound(actualHeight * led.minY_frac));
unsigned maxY_idx = yOffset + unsigned(std::round(actualHeight * led.maxY_frac)); unsigned maxY_idx = yOffset + unsigned(qRound(actualHeight * led.maxY_frac));
// make sure that the area is at least a single led large // make sure that the area is at least a single led large
minX_idx = std::min(minX_idx, xOffset + actualWidth - 1); minX_idx = qMin(minX_idx, xOffset + actualWidth - 1);
if (minX_idx == maxX_idx) if (minX_idx == maxX_idx)
{ {
maxX_idx = minX_idx + 1; maxX_idx = minX_idx + 1;
} }
minY_idx = std::min(minY_idx, yOffset + actualHeight - 1); minY_idx = qMin(minY_idx, yOffset + actualHeight - 1);
if (minY_idx == maxY_idx) if (minY_idx == maxY_idx)
{ {
maxY_idx = minY_idx + 1; maxY_idx = minY_idx + 1;

View File

@ -8,6 +8,7 @@
using namespace hyperion; using namespace hyperion;
// ledUpdateFrequency_hz = 0 > cause divide by zero!
LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpdateFrequency_hz, int settlingTime_ms, unsigned updateDelay, bool continuousOutput) LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpdateFrequency_hz, int settlingTime_ms, unsigned updateDelay, bool continuousOutput)
: LedDevice() : LedDevice()
, _ledDevice(ledDevice) , _ledDevice(ledDevice)
@ -18,14 +19,20 @@ LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpd
, _writeToLedsEnable(true) , _writeToLedsEnable(true)
, _continuousOutput(continuousOutput) , _continuousOutput(continuousOutput)
, _pause(false) , _pause(false)
, _currentConfigId(0)
{ {
_log = Logger::getInstance("Smoothing"); _log = Logger::getInstance("Smoothing");
_timer.setSingleShot(false); _timer.setSingleShot(false);
_timer.setInterval(_updateInterval); _timer.setInterval(_updateInterval);
selectConfig( addConfig(_settlingTime, ledUpdateFrequency_hz, updateDelay) );
// add pause on cfg 1
SMOOTHING_CFG cfg = {true, 100, 50, 0};
_cfgList.append(cfg);
Info( _log, "smoothing cfg %d: pause", _cfgList.count()-1);
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateLeds())); connect(&_timer, SIGNAL(timeout()), this, SLOT(updateLeds()));
Info( _log, "Created linear-smoothing with interval: %d ms, settlingTime: %d ms, updateDelay: %d frames",
_updateInterval, settlingTime_ms, _outputDelay );
} }
LinearColorSmoothing::~LinearColorSmoothing() LinearColorSmoothing::~LinearColorSmoothing()
@ -160,3 +167,44 @@ void LinearColorSmoothing::setPause(bool pause)
_pause = pause; _pause = pause;
} }
unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
{
SMOOTHING_CFG cfg = {false, settlingTime_ms, int64_t(1000.0/ledUpdateFrequency_hz), updateDelay};
_cfgList.append(cfg);
Info( _log, "smoothing cfg %d: interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _cfgList.count()-1, cfg.updateInterval, cfg.settlingTime, cfg.outputDelay );
return _cfgList.count() - 1;
}
bool LinearColorSmoothing::selectConfig(unsigned cfg)
{
if (_currentConfigId == cfg)
{
return true;
}
if ( cfg < (unsigned)_cfgList.count())
{
_settlingTime = _cfgList[cfg].settlingTime;
_outputDelay = _cfgList[cfg].outputDelay;
_pause = _cfgList[cfg].pause;
if (_cfgList[cfg].updateInterval != _updateInterval)
{
_timer.stop();
_updateInterval = _cfgList[cfg].updateInterval;
_timer.setInterval(_updateInterval);
_timer.start();
}
_currentConfigId = cfg;
InfoIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay );
InfoIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
return true;
}
// reset to default
_currentConfigId = 0;
return false;
}

View File

@ -6,6 +6,7 @@
// Qt includes // Qt includes
#include <QTimer> #include <QTimer>
#include <QVector>
// hyperion incluse // hyperion incluse
#include <leddevice/LedDevice.h> #include <leddevice/LedDevice.h>
@ -33,7 +34,7 @@ public:
/// write updated values as input for the smoothing filter /// write updated values as input for the smoothing filter
/// ///
/// @param ledValues The color-value per led /// @param ledValues The color-value per led
/// @return Zero on succes else negative /// @return Zero on success else negative
/// ///
virtual int write(const std::vector<ColorRgb> &ledValues); virtual int write(const std::vector<ColorRgb> &ledValues);
@ -45,6 +46,9 @@ public:
bool pause() { return _pause; } ; bool pause() { return _pause; } ;
bool enabled() { return LedDevice::enabled() && !_pause; }; bool enabled() { return LedDevice::enabled() && !_pause; };
unsigned addConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
bool selectConfig(unsigned cfg);
private slots: private slots:
/// Timer callback which writes updated led values to the led device /// Timer callback which writes updated led values to the led device
void updateLeds(); void updateLeds();
@ -61,10 +65,10 @@ private:
LedDevice * _ledDevice; LedDevice * _ledDevice;
/// The interval at which to update the leds (msec) /// The interval at which to update the leds (msec)
const int64_t _updateInterval; int64_t _updateInterval;
/// The time after which the updated led values have been fully applied (msec) /// The time after which the updated led values have been fully applied (msec)
const int64_t _settlingTime; int64_t _settlingTime;
/// The Qt timer object /// The Qt timer object
QTimer _timer; QTimer _timer;
@ -82,7 +86,7 @@ private:
std::vector<ColorRgb> _previousValues; std::vector<ColorRgb> _previousValues;
/// The number of updates to keep in the output queue (delayed) before being output /// The number of updates to keep in the output queue (delayed) before being output
const unsigned _outputDelay; unsigned _outputDelay;
/// The output queue /// The output queue
std::list<std::vector<ColorRgb> > _outputQueue; std::list<std::vector<ColorRgb> > _outputQueue;
@ -94,4 +98,17 @@ private:
/// Flag for pausing /// Flag for pausing
bool _pause; bool _pause;
struct SMOOTHING_CFG
{
bool pause;
int64_t settlingTime;
int64_t updateInterval;
unsigned outputDelay;
};
/// config list
QVector<SMOOTHING_CFG> _cfgList;
unsigned _currentConfigId;
}; };

View File

@ -1,7 +1,3 @@
// STL includes
#include <cassert>
// Hyperion includes // Hyperion includes
#include <utils/Logger.h> #include <utils/Logger.h>
#include "MultiColorAdjustment.h" #include "MultiColorAdjustment.h"
@ -29,8 +25,8 @@ void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment)
void MultiColorAdjustment::setAdjustmentForLed(const QString& id, const unsigned startLed, const unsigned endLed) void MultiColorAdjustment::setAdjustmentForLed(const QString& id, const unsigned startLed, const unsigned endLed)
{ {
assert(startLed <= endLed); Q_ASSERT(startLed <= endLed);
assert(endLed < _ledAdjustments.size()); Q_ASSERT(endLed < _ledAdjustments.size());
// Get the identified adjustment (don't care if is nullptr) // Get the identified adjustment (don't care if is nullptr)
ColorAdjustment * adjustment = getAdjustment(id); ColorAdjustment * adjustment = getAdjustment(id);
@ -83,10 +79,9 @@ void MultiColorAdjustment::setBacklightEnabled(bool enable)
} }
} }
void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors) void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors)
{ {
const size_t itCnt = std::min(_ledAdjustments.size(), ledColors.size()); const size_t itCnt = qMin(_ledAdjustments.size(), ledColors.size());
for (size_t i=0; i<itCnt; ++i) for (size_t i=0; i<itCnt; ++i)
{ {
ColorAdjustment* adjustment = _ledAdjustments[i]; ColorAdjustment* adjustment = _ledAdjustments[i];

View File

@ -1,4 +1,3 @@
#include <iostream>
// STL includes // STL includes
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
@ -27,7 +26,6 @@ PriorityMuxer::PriorityMuxer(int ledCount)
PriorityMuxer::~PriorityMuxer() PriorityMuxer::~PriorityMuxer()
{ {
// empty
} }
int PriorityMuxer::getCurrentPriority() const int PriorityMuxer::getCurrentPriority() const
@ -55,7 +53,7 @@ const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority)
return elemIt.value(); return elemIt.value();
} }
void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms, hyperion::Components component, const QString origin) void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms, hyperion::Components component, const QString origin, unsigned smooth_cfg)
{ {
InputInfo& input = _activeInputs[priority]; InputInfo& input = _activeInputs[priority];
input.priority = priority; input.priority = priority;
@ -63,7 +61,8 @@ void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& le
input.ledColors = ledColors; input.ledColors = ledColors;
input.componentId = component; input.componentId = component;
input.origin = origin; input.origin = origin;
_currentPriority = std::min(_currentPriority, priority); input.smooth_cfg = smooth_cfg;
_currentPriority = qMin(_currentPriority, priority);
} }
void PriorityMuxer::clearInput(const int priority) void PriorityMuxer::clearInput(const int priority)
@ -101,8 +100,8 @@ void PriorityMuxer::setCurrentTime(const int64_t& now)
infoIt = _activeInputs.erase(infoIt); infoIt = _activeInputs.erase(infoIt);
} }
else else
{ {
_currentPriority = std::min(_currentPriority, infoIt->priority); _currentPriority = qMin(_currentPriority, infoIt->priority);
// call emitReq when effect or color is running with timeout > -1, blacklist prio 255 // call emitReq when effect or color is running with timeout > -1, blacklist prio 255
if(infoIt->priority < 254 && infoIt->timeoutTime_ms > -1 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR)) if(infoIt->priority < 254 && infoIt->timeoutTime_ms > -1 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR))

View File

@ -16,7 +16,7 @@ bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
ProviderSpi::init(deviceConfig); ProviderSpi::init(deviceConfig);
const unsigned int startFrameSize = 4; const unsigned int startFrameSize = 4;
const unsigned int endFrameSize = std::max<unsigned int>(((_ledCount + 15) / 16), 4); const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize; const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
_ledBuffer.resize(APAbufferSize, 0xFF); _ledBuffer.resize(APAbufferSize, 0xFF);

View File

@ -26,7 +26,7 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
{ {
const unsigned int startFrameSize = 4; const unsigned int startFrameSize = 4;
const unsigned int bytesPerRGBLed = 4; const unsigned int bytesPerRGBLed = 4;
const unsigned int endFrameSize = std::max<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed); const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00); _ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
// init constant data values // init constant data values

View File

@ -38,7 +38,7 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType ); Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
_rs232Port.setStopBits(QSerialPort::TwoStop); _rs232Port.setStopBits(QSerialPort::TwoStop);
_dmxLedCount = std::min(_ledCount, 512/_dmxSlotsPerLed); _dmxLedCount = qMin(_ledCount, 512/_dmxSlotsPerLed);
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount; _dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed); Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);

View File

@ -209,7 +209,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size) int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{ {
int count = std::min(_hwLedCount,size); int count = qMin(_hwLedCount,size);
for (int i=0; i<count; i++) for (int i=0; i<count; i++)
{ {
const ColorRgb & color = ledValues[i]; const ColorRgb & color = ledValues[i];

View File

@ -252,7 +252,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size) int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{ {
int count = std::min(_hwLedCount, _ledCount); int count = qMin(_hwLedCount, _ledCount);
for (int i = 0; i < count ; ++i) for (int i = 0; i < count ; ++i)
{ {

View File

@ -81,7 +81,7 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
for (LedDeviceLightpack * device : _lightpacks) for (LedDeviceLightpack * device : _lightpacks)
{ {
int count = std::min(device->getLedCount(), size); int count = qMin(device->getLedCount(), size);
if (count > 0) if (count > 0)
{ {

View File

@ -79,7 +79,7 @@ The Sequence field is set to 0x00 to disable this feature.
if ( (ledIdx == _ledRGBCount-1) || (dmxIdx >= DMX_MAX) ) if ( (ledIdx == _ledRGBCount-1) || (dmxIdx >= DMX_MAX) )
{ {
prepare(thisUniverse, _artnet_seq, dmxIdx); prepare(thisUniverse, _artnet_seq, dmxIdx);
retVal &= writeBytes(18 + std::min(dmxIdx, DMX_MAX), artnet_packet.raw); retVal &= writeBytes(18 + qMin(dmxIdx, DMX_MAX), artnet_packet.raw);
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw)); memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
thisUniverse ++; thisUniverse ++;

View File

@ -34,24 +34,44 @@
"type": "boolean", "type": "boolean",
"title":"edt_dev_spec_FCmanualControl_title", "title":"edt_dev_spec_FCmanualControl_title",
"default": false, "default": false,
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 5 "propertyOrder" : 5
}, },
"ledOn": { "ledOn": {
"type": "boolean", "type": "boolean",
"title":"edt_dev_spec_FCledToOn_title", "title":"edt_dev_spec_FCledToOn_title",
"default": false, "default": false,
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 6 "propertyOrder" : 6
}, },
"interpolation": { "interpolation": {
"type": "boolean", "type": "boolean",
"title":"edt_dev_spec_interpolation_title", "title":"edt_dev_spec_interpolation_title",
"default": false, "default": false,
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 7 "propertyOrder" : 7
}, },
"dither": { "dither": {
"type": "boolean", "type": "boolean",
"title":"edt_dev_spec_dithering_title", "title":"edt_dev_spec_dithering_title",
"default": false, "default": false,
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 8 "propertyOrder" : 8
}, },
"gamma" : { "gamma" : {
@ -59,11 +79,21 @@
"title" : "edt_dev_spec_gamma_title", "title" : "edt_dev_spec_gamma_title",
"minimum" : 0.1, "minimum" : 0.1,
"maximum": 5.0, "maximum": 5.0,
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 9 "propertyOrder" : 9
}, },
"whitepoint" : { "whitepoint" : {
"type" : "array", "type" : "array",
"title" : "edt_dev_spec_whitepoint_title", "title" : "edt_dev_spec_whitepoint_title",
"options": {
"dependencies": {
"setFcConfig": true
}
},
"propertyOrder" : 10, "propertyOrder" : 10,
"default" : [255,255,255], "default" : [255,255,255],
"maxItems" : 3, "maxItems" : 3,

View File

@ -1,6 +1,3 @@
// system includes
#include <stdexcept>
// project includes // project includes
#include <udplistener/UDPListener.h> #include <udplistener/UDPListener.h>
@ -123,7 +120,7 @@ void UDPListener::processTheDatagram(const QByteArray * datagram, const QHostAdd
std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK); std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK);
for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) { for (int ledIndex=0; ledIndex < qMin(packetLedCount, hyperionLedCount); ledIndex++) {
ColorRgb & rgb = _ledColors[ledIndex]; ColorRgb & rgb = _ledColors[ledIndex];
rgb.red = datagram->at(ledIndex*3+0); rgb.red = datagram->at(ledIndex*3+0);
rgb.green = datagram->at(ledIndex*3+1); rgb.green = datagram->at(ledIndex*3+1);

View File

@ -1,9 +1,3 @@
// STL includes
#include <cmath>
#include <cstdint>
#include <algorithm>
// Utils includes
#include <utils/RgbChannelAdjustment.h> #include <utils/RgbChannelAdjustment.h>
RgbChannelAdjustment::RgbChannelAdjustment(QString channelName) RgbChannelAdjustment::RgbChannelAdjustment(QString channelName)
@ -64,9 +58,9 @@ void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & re
if (!_initialized[input]) if (!_initialized[input])
{ {
_mapping[RED ][input] = std::min( ((_brightness * input * _adjust[RED ]) / 65025), UINT8_MAX); _mapping[RED ][input] = qMin( ((_brightness * input * _adjust[RED ]) / 65025), UINT8_MAX);
_mapping[GREEN][input] = std::min( ((_brightness * input * _adjust[GREEN]) / 65025), UINT8_MAX); _mapping[GREEN][input] = qMin( ((_brightness * input * _adjust[GREEN]) / 65025), UINT8_MAX);
_mapping[BLUE ][input] = std::min( ((_brightness * input * _adjust[BLUE ]) / 65025), UINT8_MAX); _mapping[BLUE ][input] = qMin( ((_brightness * input * _adjust[BLUE ]) / 65025), UINT8_MAX);
_initialized[input] = true; _initialized[input] = true;
} }
red = _mapping[RED ][input]; red = _mapping[RED ][input];

View File

@ -19,7 +19,7 @@ void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, const WhiteAlgorithm algori
{ {
case SUBTRACT_MINIMUM: case SUBTRACT_MINIMUM:
{ {
output->white = std::min(std::min(input.red, input.green), input.blue); output->white = qMin(qMin(input.red, input.green), input.blue);
output->red = input.red - output->white; output->red = input.red - output->white;
output->green = input.green - output->white; output->green = input.green - output->white;
output->blue = input.blue - output->white; output->blue = input.blue - output->white;

View File

@ -1,6 +1,4 @@
#include <iostream> #include <QtCore/qmath.h>
#include <cmath>
#include <utils/RgbTransform.h> #include <utils/RgbTransform.h>
RgbTransform::RgbTransform() RgbTransform::RgbTransform()
@ -55,9 +53,9 @@ void RgbTransform::initializeMapping()
{ {
for (int i = 0; i < 256; ++i) for (int i = 0; i < 256; ++i)
{ {
_mappingR[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaR) * 255), 0), 255); _mappingR[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaR) * 255), 0), 255);
_mappingG[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaG) * 255), 0), 255); _mappingG[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaG) * 255), 0), 255);
_mappingB[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaB) * 255), 0), 255); _mappingB[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaB) * 255), 0), 255);
} }
} }
@ -70,7 +68,7 @@ int RgbTransform::getBacklightThreshold() const
void RgbTransform::setBacklightThreshold(int backlightThreshold) void RgbTransform::setBacklightThreshold(int backlightThreshold)
{ {
_backlightThreshold = backlightThreshold; _backlightThreshold = backlightThreshold;
_sumBrightnessLow = 765.0 * ((std::pow(2.0,(_backlightThreshold/100)*2)-1) / 3.0); _sumBrightnessLow = 765.0 * ((qPow(2.0,(_backlightThreshold/100)*2)-1) / 3.0);
} }
bool RgbTransform::getBacklightColored() const bool RgbTransform::getBacklightColored() const
@ -129,9 +127,9 @@ void RgbTransform::updateBrightnessComponents()
{ {
B_in = (_brightness<50)? -0.09*_brightness+7.5 : -0.04*_brightness+5.0; B_in = (_brightness<50)? -0.09*_brightness+7.5 : -0.04*_brightness+5.0;
_brightness_rgb = std::ceil(std::min(255.0,255.0/B_in)); _brightness_rgb = std::ceil(qMin(255.0,255.0/B_in));
_brightness_cmy = std::ceil(std::min(255.0,255.0/(B_in*Fcmy))); _brightness_cmy = std::ceil(qMin(255.0,255.0/(B_in*Fcmy)));
_brightness_w = std::ceil(std::min(255.0,255.0/(B_in*Fw))); _brightness_w = std::ceil(qMin(255.0,255.0/(B_in*Fw)));
} }
} }
@ -149,7 +147,6 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
green = _mappingR[green]; green = _mappingR[green];
blue = _mappingR[blue]; blue = _mappingR[blue];
//std::cout << (int)red << " " << (int)green << " " << (int)blue << " => ";
// apply brightnesss // apply brightnesss
int rgbSum = red+green+blue; int rgbSum = red+green+blue;
@ -164,7 +161,7 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
if (blue ==0) blue = 1; if (blue ==0) blue = 1;
rgbSum = red+green+blue; rgbSum = red+green+blue;
} }
double cL =std::min((int)(_sumBrightnessLow /rgbSum), 255); double cL =qMin((int)(_sumBrightnessLow /rgbSum), 255);
red *= cL; red *= cL;
green *= cL; green *= cL;
@ -172,11 +169,10 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
} }
else else
{ {
red = std::min((int)(_sumBrightnessLow/3.0), 255); red = qMin((int)(_sumBrightnessLow/3.0), 255);
green = red; green = red;
blue = red; blue = red;
} }
} }
//std::cout << _sumBrightnessLow << " " << (int)red << " " << (int)green << " " << (int)blue << std::endl;
} }

View File

@ -32,7 +32,6 @@ SysTray::SysTray(HyperionDaemon *hyperiond, quint16 webPort)
_trayIcon->setIcon(icon); _trayIcon->setIcon(icon);
_trayIcon->show(); _trayIcon->show();
setWindowIcon(icon); setWindowIcon(icon);
_colorDlg.setModal(true);
_colorDlg.setOptions(QColorDialog::NoButtons); _colorDlg.setOptions(QColorDialog::NoButtons);
} }
@ -58,21 +57,31 @@ void SysTray::iconActivated(QSystemTrayIcon::ActivationReason reason)
void SysTray::createTrayIcon() void SysTray::createTrayIcon()
{ {
quitAction = new QAction(tr("&Quit"), this); quitAction = new QAction(tr("&Quit"), this);
QIcon quitIcon = QIcon::fromTheme("application-exit");
quitAction->setIcon(quitIcon);
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
colorAction = new QAction(tr("&Color"), this); colorAction = new QAction(tr("&Color"), this);
QIcon colorIcon = QIcon::fromTheme("applications-graphics");
colorAction->setIcon(colorIcon);
connect(colorAction, SIGNAL(triggered()), this, SLOT(showColorDialog())); connect(colorAction, SIGNAL(triggered()), this, SLOT(showColorDialog()));
settingsAction = new QAction(tr("&Settings"), this); settingsAction = new QAction(tr("&Settings"), this);
QIcon settingsIcon = QIcon::fromTheme("preferences-system");
settingsAction->setIcon(settingsIcon);
connect(settingsAction, SIGNAL(triggered()), this, SLOT(settings())); connect(settingsAction, SIGNAL(triggered()), this, SLOT(settings()));
clearAction = new QAction(tr("&Clear"), this); clearAction = new QAction(tr("&Clear"), this);
QIcon clearIcon = QIcon::fromTheme("edit-delete");
clearAction->setIcon(clearIcon);
connect(clearAction, SIGNAL(triggered()), this, SLOT(clearEfxColor())); connect(clearAction, SIGNAL(triggered()), this, SLOT(clearEfxColor()));
const std::list<EffectDefinition> efxs = _hyperion->getEffects(); const std::list<EffectDefinition> efxs = _hyperion->getEffects();
_trayIconMenu = new QMenu(this); _trayIconMenu = new QMenu(this);
_trayIconEfxMenu = new QMenu(_trayIconMenu); _trayIconEfxMenu = new QMenu(_trayIconMenu);
_trayIconEfxMenu->setTitle(tr("Effects")); _trayIconEfxMenu->setTitle(tr("Effects"));
QIcon efxIcon = QIcon::fromTheme("media-playback-start");
_trayIconEfxMenu->setIcon(efxIcon);
for (auto efx : efxs) for (auto efx : efxs)
{ {
QAction *efxAction = new QAction(efx.name, this); QAction *efxAction = new QAction(efx.name, this);