[pitivi] Add a custom user interface for chroma keying with the Alpha filter



commit b6e72e2f321f9fb0c13f2518ebe05a0f6a6b1d17
Author: Suhas Nayak <suhas2go gmail com>
Date:   Wed Aug 23 20:08:20 2017 +0530

    Add a custom user interface for chroma keying with the Alpha filter
    
    Co-authored-by: Jean-François Fortin Tam <nekohayo gmail com>
    Co-authored-by: Thibault Saunier <thibault saunier collabora com>
    
    Differential Revision: https://phabricator.freedesktop.org/D1745

 data/ui/customwidgets/alpha.ui        |  496 +++++++++++++++++++++++++++++++++
 pitivi/utils/custom_effect_widgets.py |  104 +++++++-
 pitivi/utils/widgets.py               |    9 +-
 3 files changed, 603 insertions(+), 6 deletions(-)
---
diff --git a/data/ui/customwidgets/alpha.ui b/data/ui/customwidgets/alpha.ui
new file mode 100644
index 0000000..51cac3e
--- /dev/null
+++ b/data/ui/customwidgets/alpha.ui
@@ -0,0 +1,496 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.0"/>
+  <object class="GtkAdjustment" id="alpha_adjustment">
+    <property name="upper">1</property>
+    <property name="value">1</property>
+    <property name="step_increment">0.01</property>
+    <property name="page_increment">0.10000000000000001</property>
+  </object>
+  <object class="GtkAdjustment" id="angle_adjustment">
+    <property name="upper">90</property>
+    <property name="value">20</property>
+    <property name="step_increment">0.10000000000000001</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="black_sens_adjustment">
+    <property name="upper">128</property>
+    <property name="value">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="blue_color_adjustment">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="green_color_adjustment">
+    <property name="upper">255</property>
+    <property name="value">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">edit-clear-all-symbolic</property>
+  </object>
+  <object class="GtkImage" id="image2">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">edit-clear-all-symbolic</property>
+  </object>
+  <object class="GtkImage" id="image3">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">edit-clear-all-symbolic</property>
+  </object>
+  <object class="GtkImage" id="image4">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">edit-clear-all-symbolic</property>
+  </object>
+  <object class="GtkImage" id="image5">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">edit-clear-all-symbolic</property>
+  </object>
+  <object class="GtkListStore" id="liststore1"/>
+  <object class="GtkAdjustment" id="noise_adjustment">
+    <property name="upper">64</property>
+    <property name="value">2</property>
+    <property name="step_increment">0.10000000000000001</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="red_color_adjustment">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="white_sens_adjustment">
+    <property name="upper">128</property>
+    <property name="value">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkGrid" id="base_table">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="row_spacing">8</property>
+    <property name="column_spacing">6</property>
+    <child>
+      <object class="GtkButton" id="GstAlpha::angle::reset">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image1</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="GstAlpha::noise-level::reset">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image2</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="GstAlpha::white-sensitivity::reset">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image3</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="GstAlpha::black-sensitivity::reset">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image4</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">5</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label6">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Angle:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label7">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Noise level:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label8">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">White sensitivity:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label9">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Black sensitivity:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">5</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScale" id="GstAlpha::angle">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">angle_adjustment</property>
+        <property name="restrict_to_fill_level">False</property>
+        <property name="fill_level">1</property>
+        <property name="round_digits">2</property>
+        <property name="value_pos">left</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">2</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScale" id="GstAlpha::noise-level">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">noise_adjustment</property>
+        <property name="restrict_to_fill_level">False</property>
+        <property name="fill_level">1</property>
+        <property name="round_digits">2</property>
+        <property name="value_pos">left</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">3</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScale" id="GstAlpha::white-sensitivity">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">white_sens_adjustment</property>
+        <property name="restrict_to_fill_level">False</property>
+        <property name="fill_level">1</property>
+        <property name="round_digits">2</property>
+        <property name="digits">0</property>
+        <property name="value_pos">left</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">4</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScale" id="GstAlpha::black-sensitivity">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">black_sens_adjustment</property>
+        <property name="restrict_to_fill_level">False</property>
+        <property name="fill_level">1</property>
+        <property name="round_digits">2</property>
+        <property name="digits">0</property>
+        <property name="value_pos">left</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">5</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToggleButton" id="GstAlpha::angle::keyframe">
+        <property name="label" translatable="yes">◇</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToggleButton" id="GstAlpha::noise-level::keyframe">
+        <property name="label" translatable="yes">◇</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="relief">none</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToggleButton" id="GstAlpha::white-sensitivity::keyframe">
+        <property name="label" translatable="yes">◇</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="relief">none</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToggleButton" id="GstAlpha::black-sensitivity::keyframe">
+        <property name="label" translatable="yes">◇</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="relief">none</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">5</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSeparator" id="separator2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">1</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label5">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Alpha:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScale" id="GstAlpha::alpha">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">alpha_adjustment</property>
+        <property name="restrict_to_fill_level">False</property>
+        <property name="fill_level">1</property>
+        <property name="round_digits">1</property>
+        <property name="digits">2</property>
+        <property name="value_pos">left</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Target chroma key:</property>
+        <property name="xalign">0</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">6</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Red</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">8</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Green</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">8</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="GstAlpha::target-b">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">blue_color_adjustment</property>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">7</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkColorButton" id="colorbutton">
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="title" translatable="yes">Select a color</property>
+        <property name="rgba">rgb(0,255,0)</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">7</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Blue</property>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">8</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="GstAlpha::target-g">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">green_color_adjustment</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">7</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="GstAlpha::target-r">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="adjustment">red_color_adjustment</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">7</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="GstAlpha::alpha::reset">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image5</property>
+        <property name="relief">none</property>
+        <property name="image_position">top</property>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkAspectFrame" id="color_picker_frame">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label_xalign">0</property>
+        <property name="shadow_type">none</property>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">4</property>
+        <property name="top_attach">7</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </object>
+</interface>
diff --git a/pitivi/utils/custom_effect_widgets.py b/pitivi/utils/custom_effect_widgets.py
index ebcdb14..1be7c8a 100644
--- a/pitivi/utils/custom_effect_widgets.py
+++ b/pitivi/utils/custom_effect_widgets.py
@@ -19,9 +19,12 @@
 """Utility methods for custom effect UI."""
 import os
 
+from gi.repository import Gdk
 from gi.repository import Gtk
 
 from pitivi import configure
+from pitivi.utils.loggable import Loggable
+from pitivi.utils.widgets import ColorPickerButton
 
 
 CUSTOM_WIDGETS_DIR = os.path.join(configure.get_ui_dir(), "customwidgets")
@@ -50,13 +53,18 @@ def create_custom_prop_widget_cb(unused_effect_prop_manager, effect_widget, effe
         return create_custom_alpha_prop_widget(effect_widget, effect, prop, prop_value)
 
 
-def create_custom_widget_cb(unused_effect_prop_manager, effect_widget, effect):
+def create_custom_widget_cb(effect_prop_manager, effect_widget, effect):
     """Creates custom effect UI."""
     effect_name = effect.get_property("bin-description")
     path = os.path.join(CUSTOM_WIDGETS_DIR, effect_name + ".ui")
     if not os.path.isfile(path):
         return None
 
+    # Write individual effect callbacks here
+    if effect_name == "alpha":
+        widget = create_alpha_widget(effect_prop_manager, effect_widget, effect)
+        return widget
+
     # Check if there is a UI file available as a glade file
     # Assuming a GtkGrid called base_table exists
     builder = setup_from_ui_file(effect_widget, path)
@@ -64,10 +72,96 @@ def create_custom_widget_cb(unused_effect_prop_manager, effect_widget, effect):
     return widget
 
 
-def create_alpha_widget(unused_element_setting_widget, unused_element):
-    """Not implemented yet."""
-    # Main alpha widget would go here
-    return None
+def create_alpha_widget(effect_prop_manager, element_setting_widget, element):
+    """Creates the UI for the `alpha` effect."""
+    builder = setup_from_ui_file(element_setting_widget, os.path.join(CUSTOM_WIDGETS_DIR, "alpha.ui"))
+
+    color_picker = ColorPickerButton(0, 255, 0)
+    color_picker_frame = builder.get_object("color_picker_frame")
+    color_picker_frame.add(color_picker)
+
+    # Additional Setup
+
+    # All modes other than custom RGB chroma keying are useless to us.
+    # "ALPHA_METHOD_CUSTOM" corresponds to "3"
+    Loggable().debug("Setting alpha's method to 3 (custom RGB chroma keying)")
+    element.set_child_property("method", 3)
+
+    # Color button and picker has to be connected manually!
+
+    def get_current_rgba():
+        """Gets the color used by the effect."""
+        color = Gdk.RGBA()
+        res, red = element.get_child_property("target-r")
+        assert res
+        res, green = element.get_child_property("target-g")
+        assert res
+        res, blue = element.get_child_property("target-b")
+        assert res
+        color.red = red / 255
+        color.green = green / 255
+        color.blue = blue / 255
+        return color
+
+    def color_button_color_set_cb(color_button):
+        """Handles the selection of a color with the color button."""
+        color = color_button.get_rgba()
+        red = int(color.red * 255)
+        green = int(color.green * 255)
+        blue = int(color.blue * 255)
+        from pitivi.undo.timeline import CommitTimelineFinalizingAction
+        pipeline = effect_prop_manager.app.project_manager.current_project.pipeline
+        action_log = effect_prop_manager.app.action_log
+        with action_log.started("Effect property change",
+                                finalizing_action=CommitTimelineFinalizingAction(pipeline),
+                                toplevel=True):
+            element.set_child_property("target-r", red)
+            element.set_child_property("target-g", green)
+            element.set_child_property("target-b", blue)
+
+    color_button = builder.get_object("colorbutton")
+    color_button.connect("color-set", color_button_color_set_cb)
+
+    def color_picker_value_changed_cb(unused_color_picker_button):
+        """Handles the selection of a color with the color picker button."""
+        from pitivi.undo.timeline import CommitTimelineFinalizingAction
+        pipeline = effect_prop_manager.app.project_manager.current_project.pipeline
+        action_log = effect_prop_manager.app.action_log
+        with action_log.started("Color Picker Change",
+                                finalizing_action=CommitTimelineFinalizingAction(pipeline),
+                                toplevel=True):
+            element.set_child_property("target-r", color_picker.color_r)
+            element.set_child_property("target-g", color_picker.color_g)
+            element.set_child_property("target-b", color_picker.color_b)
+
+    color_picker.connect("value-changed", color_picker_value_changed_cb)
+
+    def property_changed_cb(unused_effect, gst_element, pspec):
+        """Handles the change of a GObject property."""
+        if gst_element.get_control_binding(pspec.name):
+            Loggable().log("%s controlled, not displaying value", pspec.name)
+            return
+
+        widget = element_setting_widget.properties.get(pspec)
+        if not widget:
+            return
+
+        res, value = element_setting_widget.element.get_child_property(pspec.name)
+        assert res
+
+        if pspec.name in ("target-r", "target-g", "target-b"):
+            color_button.set_rgba(get_current_rgba())
+            widget.block_signals()
+            try:
+                widget.setWidgetValue(value)
+            finally:
+                widget.unblock_signals()
+        else:
+            widget.setWidgetValue(value)
+
+    element.connect("deep-notify", property_changed_cb)
+
+    return builder.get_object("base_table")
 
 
 def create_custom_alpha_prop_widget(unused_element_setting_widget, unused_element, unused_prop, 
unused_prop_value):
diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py
index 9bf3a0a..039006f 100644
--- a/pitivi/utils/widgets.py
+++ b/pitivi/utils/widgets.py
@@ -225,6 +225,7 @@ class NumericWidget(Gtk.Box, DynamicWidget):
         self.set_spacing(SPACING)
         self._type = None
         self.spinner = None
+        self.handler_id = None
 
         if adjustment:
             self.adjustment = adjustment
@@ -264,8 +265,14 @@ class NumericWidget(Gtk.Box, DynamicWidget):
         self.spinner.show()
         disable_scroll(self.spinner)
 
+    def block_signals(self):
+        self.adjustment.handler_block(self.handler_id)
+
+    def unblock_signals(self):
+        self.adjustment.handler_unblock(self.handler_id)
+
     def connectValueChanged(self, callback, *args):
-        self.adjustment.connect("value-changed", callback, *args)
+        self.handler_id = self.adjustment.connect("value-changed", callback, *args)
 
     def getWidgetValue(self):
         if self._type:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]