[pitivi] Custom UI for the 3 point color balance effect



commit 2bdcfa2cb9f453eee1284aa5d793d946ad4c4bdf
Author: Suhas Nayak <suhas2go gmail com>
Date:   Mon Sep 18 23:45:09 2017 +0530

    Custom UI for the 3 point color balance effect
    
    Allows adjusting highlights, midtones and shadows with three color
    wheels.
    
    Differential Revision: https://phabricator.freedesktop.org/D1838

 .../frei0r-filter-3-point-color-balance.ui         |  526 ++++++++++++++++++++
 pitivi/utils/custom_effect_widgets.py              |  175 +++++++-
 po/POTFILES.in                                     |    1 +
 3 files changed, 700 insertions(+), 2 deletions(-)
---
diff --git a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui 
b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui
new file mode 100644
index 0000000..8977bbe
--- /dev/null
+++ b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkAdjustment" id="adjustment1">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment2">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment3">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment4">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment5">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment6">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment7">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment8">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment9">
+    <property name="upper">255</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkSizeGroup" id="color_picker_sizegroup"/>
+  <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="GtkGrid" id="base_table">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">8</property>
+    <property name="row_spacing">8</property>
+    <property name="column_spacing">8</property>
+    <child>
+      <object class="GtkGrid" id="shadows_rgb_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">3</property>
+        <property name="column_spacing">4</property>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::black-color-r">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment7</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::black-color-g">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment8</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::black-color-b">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment9</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkGrid" id="midtones_rgb_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">3</property>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::gray-color-r">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment4</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::gray-color-g">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment5</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::gray-color-b">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment6</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkGrid" id="highlights_rgb_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">3</property>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::white-color-r">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::white-color-g">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment2</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="frei0r-filter-3-point-color-balance::white-color-b">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment3</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSeparator">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">4</property>
+        <property name="width">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkCheckButton" id="frei0r-filter-3-point-color-balance::split-preview">
+        <property name="label" translatable="yes">Split preview</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">5</property>
+        <property name="width">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkCheckButton" id="frei0r-filter-3-point-color-balance::source-image-on-left-side">
+        <property name="label" translatable="yes">Source image on left</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">6</property>
+        <property name="width">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="rgb_label_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">R</property>
+            <property name="justify">center</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</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">G</property>
+            <property name="justify">center</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">B</property>
+            <property name="justify">center</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkGrid" id="shadows_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="column_spacing">5</property>
+        <property name="row_homogeneous">True</property>
+        <property name="column_homogeneous">True</property>
+        <child>
+          <object class="GtkAspectFrame" id="shadows_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">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAspectFrame" id="shadows_reset_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>
+              <object class="GtkButton" id="shadows_reset_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="image">image2</property>
+                <property name="image_position">top</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkGrid" id="midtones_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="column_spacing">5</property>
+        <property name="row_homogeneous">True</property>
+        <property name="column_homogeneous">True</property>
+        <child>
+          <object class="GtkAspectFrame" id="midtones_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">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAspectFrame" id="midtones_reset_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>
+              <object class="GtkButton" id="midtones_reset_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="image">image1</property>
+                <property name="image_position">top</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkGrid" id="highlights_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="column_spacing">5</property>
+        <property name="row_homogeneous">True</property>
+        <property name="column_homogeneous">True</property>
+        <child>
+          <object class="GtkAspectFrame" id="highlights_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">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAspectFrame" id="highlights_reset_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>
+              <object class="GtkButton" id="highlights_reset_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="image">image3</property>
+                <property name="image_position">top</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="shadows_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Shadows</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="midtones_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Midtones</property>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="highlights_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Highlights</property>
+      </object>
+      <packing>
+        <property name="left_attach">3</property>
+        <property name="top_attach">0</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>
+  </object>
+  <object class="GtkSizeGroup" id="b_size">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="frei0r-filter-3-point-color-balance::black-color-b"/>
+      <widget name="label3"/>
+    </widgets>
+  </object>
+  <object class="GtkSizeGroup" id="g_size">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="frei0r-filter-3-point-color-balance::black-color-g"/>
+      <widget name="label2"/>
+    </widgets>
+  </object>
+  <object class="GtkSizeGroup" id="r_size">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="frei0r-filter-3-point-color-balance::black-color-r"/>
+      <widget name="label1"/>
+    </widgets>
+  </object>
+</interface>
diff --git a/pitivi/utils/custom_effect_widgets.py b/pitivi/utils/custom_effect_widgets.py
index 1be7c8a..50801ea 100644
--- a/pitivi/utils/custom_effect_widgets.py
+++ b/pitivi/utils/custom_effect_widgets.py
@@ -18,6 +18,8 @@
 # Boston, MA 02110-1301, USA.
 """Utility methods for custom effect UI."""
 import os
+from colorsys import rgb_to_hsv
+from types import MethodType
 
 from gi.repository import Gdk
 from gi.repository import Gtk
@@ -57,16 +59,19 @@ 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
+    elif effect_name == "frei0r-filter-3-point-color-balance":
+        widget = create_3point_color_balance_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
+    if not os.path.isfile(path):
+        return None
     builder = setup_from_ui_file(effect_widget, path)
     widget = builder.get_object("base_table")
     return widget
@@ -168,3 +173,169 @@ def create_custom_alpha_prop_widget(unused_element_setting_widget, unused_elemen
     """Not implemented yet."""
     # In the auto-generated UI, replace a property widget with a custom one
     return None
+
+
+# pylint: disable=invalid-name, too-many-locals, too-many-arguments
+def create_3point_color_balance_widget(effect_prop_manager, element_setting_widget, element):
+    """Creates a widget for the `frei0r-filter-3-point-color-balance` effect."""
+    ui_path = os.path.join(CUSTOM_WIDGETS_DIR, "frei0r-filter-3-point-color-balance.ui")
+    builder = setup_from_ui_file(element_setting_widget, ui_path)
+    element_setting_widget.mapBuilder(builder)
+    color_balance_grid = builder.get_object("base_table")
+
+    shadows_wheel = Gtk.HSV()
+    midtones_wheel = Gtk.HSV()
+    highlights_wheel = Gtk.HSV()
+
+    color_balance_grid.attach(shadows_wheel, 1, 1, 1, 1)
+    color_balance_grid.attach(midtones_wheel, 2, 1, 1, 1)
+    color_balance_grid.attach(highlights_wheel, 3, 1, 1, 1)
+
+    shadows_color_picker_button = ColorPickerButton()
+    midtones_color_picker_button = ColorPickerButton()
+    highlights_color_picker_button = ColorPickerButton()
+
+    shadows_color_picker_frame = builder.get_object("shadows_color_picker_frame")
+    midtones_color_picker_frame = builder.get_object("midtones_color_picker_frame")
+    highlights_color_picker_frame = builder.get_object("highlights_color_picker_frame")
+
+    shadows_color_picker_frame.add(shadows_color_picker_button)
+    midtones_color_picker_frame.add(midtones_color_picker_button)
+    highlights_color_picker_frame.add(highlights_color_picker_button)
+
+    # Manually handle the custom part of the UI.
+    # 1) Connecting the color wheel widgets
+    # 2) Scale values between to be shown on the UI vs
+    #    the actual property values (RGB values here).
+
+    black_r = element_setting_widget.get_widget_of_prop("black-color-r")
+    black_g = element_setting_widget.get_widget_of_prop("black-color-g")
+    black_b = element_setting_widget.get_widget_of_prop("black-color-b")
+
+    gray_r = element_setting_widget.get_widget_of_prop("gray-color-r")
+    gray_g = element_setting_widget.get_widget_of_prop("gray-color-g")
+    gray_b = element_setting_widget.get_widget_of_prop("gray-color-b")
+
+    white_r = element_setting_widget.get_widget_of_prop("white-color-r")
+    white_g = element_setting_widget.get_widget_of_prop("white-color-g")
+    white_b = element_setting_widget.get_widget_of_prop("white-color-b")
+
+    # The UI widget values need to be scaled back to the property.
+    # Since for RGB values, 0-255 format is used in the UI
+    # where as the property values are actually between 0-1.
+
+    def get_widget_scaled_value(self):
+        """Gets the color value for the GES element property."""
+        return self.adjustment.get_value() / 255
+
+    black_r.getWidgetValue = MethodType(get_widget_scaled_value, black_r)
+    black_g.getWidgetValue = MethodType(get_widget_scaled_value, black_g)
+    black_b.getWidgetValue = MethodType(get_widget_scaled_value, black_b)
+
+    gray_r.getWidgetValue = MethodType(get_widget_scaled_value, gray_r)
+    gray_g.getWidgetValue = MethodType(get_widget_scaled_value, gray_g)
+    gray_b.getWidgetValue = MethodType(get_widget_scaled_value, gray_b)
+
+    white_r.getWidgetValue = MethodType(get_widget_scaled_value, white_r)
+    white_b.getWidgetValue = MethodType(get_widget_scaled_value, white_b)
+    white_g.getWidgetValue = MethodType(get_widget_scaled_value, white_g)
+
+    # Update underlying GObject color properties when the color widgets change.
+
+    def color_wheel_changed_cb(color_wheel, prop_r, prop_g, prop_b):
+        """Handles the selection of a color with a color wheel."""
+        hsv_color = color_wheel.get_color()
+        rgb_color = color_wheel.to_rgb(hsv_color.h, hsv_color.s, hsv_color.v)
+        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=False):
+            element.set_child_property(prop_r, rgb_color.r)
+            element.set_child_property(prop_g, rgb_color.g)
+            element.set_child_property(prop_b, rgb_color.b)
+
+    shadows_wheel.connect("changed", color_wheel_changed_cb, "black-color-r", "black-color-g", 
"black-color-b")
+    midtones_wheel.connect("changed", color_wheel_changed_cb, "gray-color-r", "gray-color-g", "gray-color-b")
+    highlights_wheel.connect("changed", color_wheel_changed_cb, "white-color-r", "white-color-g", 
"white-color-b")
+
+    def color_picker_value_changed_cb(color_picker_button, prop_r, prop_g, prop_b):
+        """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("Effect property change",
+                                finalizing_action=CommitTimelineFinalizingAction(pipeline),
+                                toplevel=True):
+            element.set_child_property(prop_r, color_picker_button.color_r / 255)
+            element.set_child_property(prop_g, color_picker_button.color_g / 255)
+            element.set_child_property(prop_b, color_picker_button.color_b / 255)
+
+    shadows_color_picker_button.connect("value-changed", color_picker_value_changed_cb,
+                                        "black-color-r", "black-color-g", "black-color-b")
+    midtones_color_picker_button.connect("value-changed", color_picker_value_changed_cb,
+                                         "gray-color-r", "gray-color-g", "gray-color-b")
+    highlights_color_picker_button.connect("value-changed", color_picker_value_changed_cb,
+                                           "white-color-r", "white-color-g", "white-color-b")
+
+    def update_wheel(prop_r, prop_g, prop_b, wheel, numeric_widget, value):
+        """Updates the widgets with the value from the Gst element."""
+        _, r = element_setting_widget.element.get_child_property(prop_r)
+        _, g = element_setting_widget.element.get_child_property(prop_g)
+        _, b = element_setting_widget.element.get_child_property(prop_b)
+        new_hsv = rgb_to_hsv(r, g, b)
+        # GtkHSV always emits `changed` signal when set_color is used.
+        # But we need to only emit it when the color has actually changed!
+        current_hsv = wheel.get_color()
+        if current_hsv != new_hsv:
+            wheel.set_color(*new_hsv)
+        numeric_widget.block_signals()
+        try:
+            numeric_widget.setWidgetValue(round(value * 255))
+        finally:
+            numeric_widget.unblock_signals()
+
+    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 ("black-color-r", "black-color-g", "black-color-b"):
+            update_wheel("black-color-r", "black-color-g", "black-color-b", shadows_wheel, widget, value)
+        elif pspec.name in ("gray-color-r", "gray-color-g", "gray-color-b"):
+            update_wheel("gray-color-r", "gray-color-g", "gray-color-b", midtones_wheel, widget, value)
+        elif pspec.name in ("white-color-r", "white-color-g", "white-color-b"):
+            update_wheel("white-color-r", "white-color-g", "white-color-b", highlights_wheel, widget, value)
+        else:
+            widget.setWidgetValue(value)
+
+    element.connect("deep-notify", property_changed_cb)
+
+    shadows_reset_button = builder.get_object("shadows_reset_button")
+    midtones_reset_button = builder.get_object("midtones_reset_button")
+    highlights_reset_button = builder.get_object("highlights_reset_button")
+
+    def reset_wheel_cb(unused_arg, wheel, value):
+        """Handles the click of a reset button."""
+        wheel.set_color(0, 0, value)
+
+    shadows_reset_button.connect("clicked", reset_wheel_cb, shadows_wheel, 0)
+    midtones_reset_button.connect("clicked", reset_wheel_cb, midtones_wheel, 0.5)
+    highlights_reset_button.connect("clicked", reset_wheel_cb, highlights_wheel, 1)
+
+    # Initialize the wheels with the correct values
+
+    shadows_wheel.set_color(0, 0, 0)
+    midtones_wheel.set_color(0, 0, 0.5)
+    highlights_wheel.set_color(0, 0, 1)
+
+    return color_balance_grid
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bcaa84e..5b08e34 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ data/pitivi.desktop.in
 [type: gettext/glade]data/ui/clipmediaprops.ui
 [type: gettext/glade]data/ui/cliptransformation.ui
 [type: gettext/glade]data/ui/customwidgets/alpha.ui
+[type: gettext/glade]data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui
 [type: gettext/glade]data/ui/depsmanager.ui
 [type: gettext/glade]data/ui/effectslibrary.ui
 [type: gettext/glade]data/ui/elementsettingsdialog.ui


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