[pitivi] clipproperties: Add additional title clip properties



commit 3177bd632b4ff5b54a01999c7690264556802761
Author: Adam Leppky <aleppky2 huskers unl edu>
Date:   Thu Jul 1 20:27:56 2021 -0500

    clipproperties: Add additional title clip properties
    
    The current title clip does not allow the ability to change the outline color or drop shadow.
    
    Title clip now has color buttons to change the outline color and a checkbox to change the drop shadow.
    
    Fixes #1860

 data/ui/titleeditor.ui          | 57 ++++++++++++++++++++++++--
 pitivi/clip_properties/title.py | 77 +++++++++++++++++++++++++++++++-----
 pitivi/clipproperties.py        |  6 ++-
 tests/test_clipproperties.py    | 88 ++++++++++++++++++++++++++++++++++-------
 4 files changed, 201 insertions(+), 27 deletions(-)
---
diff --git a/data/ui/titleeditor.ui b/data/ui/titleeditor.ui
index 6c2a90cd5..1241c61ab 100644
--- a/data/ui/titleeditor.ui
+++ b/data/ui/titleeditor.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.22.2 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkAdjustment" id="position_x_adj">
@@ -147,6 +147,40 @@
                     <property name="position">4</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkColorButton" id="outline_color">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="margin_left">5</property>
+                    <property name="use_alpha">True</property>
+                    <property name="title" translatable="yes">Pick an outline color</property>
+                    <property name="rgba">rgba(0,0,0,0)</property>
+                    <signal name="color-set" handler="_front_text_outline_color_button_cb" swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAspectFrame" id="color_picker_outline">
+                    <property name="name">picker3</property>
+                    <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="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -154,6 +188,23 @@
                 <property name="position">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkCheckButton" id="check_drop_shadow">
+                <property name="label" translatable="yes">Drop Shadow</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="margin_top">10</property>
+                <property name="draw_indicator">True</property>
+                <property name="halign">start</property>
+                <signal name="toggled" handler="_drop_shadow_checkbox_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkLabel" id="label7">
                 <property name="visible">True</property>
@@ -169,7 +220,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">True</property>
-                <property name="position">2</property>
+                <property name="position">3</property>
               </packing>
             </child>
             <child>
@@ -263,7 +314,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">True</property>
-                <property name="position">3</property>
+                <property name="position">4</property>
               </packing>
             </child>
           </object>
diff --git a/pitivi/clip_properties/title.py b/pitivi/clip_properties/title.py
index fdd906196..6643d0836 100644
--- a/pitivi/clip_properties/title.py
+++ b/pitivi/clip_properties/title.py
@@ -81,6 +81,7 @@ class TitleProperties(Gtk.Expander, Loggable):
         self.font_button = builder.get_object("fontbutton1")
         self.foreground_color_button = builder.get_object("fore_text_color")
         self.background_color_button = builder.get_object("back_color")
+        self.outline_color_button = builder.get_object("outline_color")
 
         self.color_picker_foreground_widget = ColorPickerButton()
         self.color_picker_foreground_widget.show()
@@ -94,6 +95,14 @@ class TitleProperties(Gtk.Expander, Loggable):
         self.background_color_picker.add(self.color_picker_background_widget)
         self.color_picker_background_widget.connect("value-changed", self._color_picker_value_changed_cb, 
self.background_color_button, "foreground-color")
 
+        self.color_picker_outline_widget = ColorPickerButton()
+        self.color_picker_outline_widget.show()
+        self.outline_color_picker = builder.get_object("color_picker_outline")
+        self.outline_color_picker.add(self.color_picker_outline_widget)
+        self.color_picker_outline_widget.connect("value-changed", self._color_picker_value_changed_cb, 
self.outline_color_button, "outline-color")
+
+        self.drop_shadow_checkbox = builder.get_object("check_drop_shadow")
+
         self.valignment_combo = builder.get_object("valignment")
         self.halignment_combo = builder.get_object("halignment")
         self.x_absolute_spin = builder.get_object("x-absolute")
@@ -125,6 +134,15 @@ class TitleProperties(Gtk.Expander, Loggable):
             finally:
                 self._setting_props = False
 
+    def _drop_shadow_checkbox_cb(self, checkbox):
+        if not self.source:
+            # Nothing to update.
+            return
+
+        active = checkbox.get_active()
+        self.debug("Setting drop shadow checkbox to %s", active)
+        self._set_child_property("draw-shadow", active)
+
     def _color_picker_value_changed_cb(self, widget, color_button, color_layer):
         argb = widget.calculate_argb()
         self.debug("Setting text %s to %x", color_layer, argb)
@@ -144,29 +162,63 @@ class TitleProperties(Gtk.Expander, Loggable):
         # TitleClips
         self._set_child_property("color", color)
 
+    def _front_text_outline_color_button_cb(self, widget):
+        color = gdk_rgba_to_argb(widget.get_rgba())
+        self.debug("Setting title outline color to %x", color)
+        self._set_child_property("outline-color", color)
+
     def _font_button_cb(self, widget):
         font_desc = widget.get_font_desc().to_string()
         self.debug("Setting font desc to %s", font_desc)
         self._set_child_property("font-desc", font_desc)
 
     def _update_from_source(self, source):
-        self.textbuffer.props.text = html.unescape(source.get_child_property("text")[1] or "")
-        self.x_absolute_spin.set_value(source.get_child_property("x-absolute")[1])
-        self.y_absolute_spin.set_value(source.get_child_property("y-absolute")[1])
-        self.valignment_combo.set_active_id(source.get_child_property("valignment")[1].value_name)
-        self.halignment_combo.set_active_id(source.get_child_property("halignment")[1].value_name)
+        res, text = source.get_child_property("text")
+        assert res
+        self.textbuffer.props.text = html.unescape(text or "")
+
+        res, x_absolute = source.get_child_property("x-absolute")
+        assert res
+        self.x_absolute_spin.set_value(x_absolute)
+
+        res, y_absolute = source.get_child_property("y-absolute")
+        assert res
+        self.y_absolute_spin.set_value(y_absolute)
+
+        res, valignment = source.get_child_property("valignment")
+        assert res
+        self.valignment_combo.set_active_id(valignment.value_name)
+
+        res, halignment = source.get_child_property("halignment")
+        assert res
+        self.halignment_combo.set_active_id(halignment.value_name)
+
         self._update_absolute_alignment_widgets_visibility()
 
-        font_desc = Pango.FontDescription.from_string(
-            source.get_child_property("font-desc")[1])
+        res, font = source.get_child_property("font-desc")
+        assert res
+        font_desc = Pango.FontDescription.from_string(font)
         self.font_button.set_font_desc(font_desc)
 
-        color = argb_to_gdk_rgba(source.get_child_property("color")[1])
+        res, argb = source.get_child_property("color")
+        assert res
+        color = argb_to_gdk_rgba(argb)
         self.foreground_color_button.set_rgba(color)
 
-        color = argb_to_gdk_rgba(source.get_child_property("foreground-color")[1])
+        res, argb = source.get_child_property("foreground-color")
+        assert res
+        color = argb_to_gdk_rgba(argb)
         self.background_color_button.set_rgba(color)
 
+        res, draw_shadow = source.get_child_property("draw-shadow")
+        assert res
+        self.drop_shadow_checkbox.set_active(draw_shadow)
+
+        res, argb = source.get_child_property("outline-color")
+        assert res
+        color = argb_to_gdk_rgba(argb)
+        self.outline_color_button.set_rgba(color)
+
     def _text_changed_cb(self, unused_text_buffer):
         if not self.source:
             # Nothing to update.
@@ -283,5 +335,12 @@ class TitleProperties(Gtk.Expander, Loggable):
             if color == self.background_color_button.get_rgba():
                 return
             self.background_color_button.set_rgba(color)
+        elif pspec.name == "outline-color":
+            color = argb_to_gdk_rgba(value)
+            if color == self.outline_color_button.get_rgba():
+                return
+            self.outline_color_button.set_rgba(color)
+        elif pspec.name == "draw-shadow":
+            self.drop_shadow_checkbox.set_active(value)
 
         self.app.project_manager.current_project.pipeline.commit_timeline()
diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py
index c7d47e3a4..8f632ac28 100644
--- a/pitivi/clipproperties.py
+++ b/pitivi/clipproperties.py
@@ -64,9 +64,11 @@ from pitivi.utils.ui import SPACING
 DEFAULT_TEXT = _("Title Clip")
 FOREGROUND_DEFAULT_COLOR = 0xFFFFFFFF  # White
 BACKGROUND_DEFAULT_COLOR = 0x00000000  # Transparent
+OUTLINE_DEFAULT_COLOR = 0xFF000000  # Black
 DEFAULT_FONT_DESCRIPTION = "Sans 36"
 DEFAULT_VALIGNMENT = "absolute"
 DEFAULT_HALIGNMENT = "absolute"
+DEFAULT_DROP_SHADOW = True
 
 # Max speed rate we allow to be applied to clips.
 # The minimum is 1 / MAX_RATE.
@@ -174,9 +176,11 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable):
             properties = {"text": DEFAULT_TEXT,
                           "foreground-color": BACKGROUND_DEFAULT_COLOR,
                           "color": FOREGROUND_DEFAULT_COLOR,
+                          "outline-color": OUTLINE_DEFAULT_COLOR,
                           "font-desc": DEFAULT_FONT_DESCRIPTION,
                           "valignment": DEFAULT_VALIGNMENT,
-                          "halignment": DEFAULT_HALIGNMENT}
+                          "halignment": DEFAULT_HALIGNMENT,
+                          "draw-shadow": DEFAULT_DROP_SHADOW}
             for prop, value in properties.items():
                 res = source.set_child_property(prop, value)
                 assert res, prop
diff --git a/tests/test_clipproperties.py b/tests/test_clipproperties.py
index c4e51fb3b..bd95c4c0c 100644
--- a/tests/test_clipproperties.py
+++ b/tests/test_clipproperties.py
@@ -288,7 +288,9 @@ class TitlePropertiesTest(common.TestCase):
                           "valignment", "halignment",
                           "font-desc",
                           "color",
-                          "foreground-color")}
+                          "foreground-color",
+                          "outline-color",
+                          "draw-shadow")}
 
     @common.setup_timeline
     @common.setup_clipproperties
@@ -297,17 +299,17 @@ class TitlePropertiesTest(common.TestCase):
         self.project.pipeline.get_position = mock.Mock(return_value=0)
 
         self.clipproperties.create_title_clip_cb(None)
-        ps1 = self._get_title_source_child_props()
-        self.assertTrue(ps1["text"][1])
-        self.assertNotEqual(ps1["text"][1], "", "Title clip does not have an initial text")
+        properties1 = self._get_title_source_child_props()
+        self.assertTrue(properties1["text"][0])
+        self.assertNotEqual(properties1["text"][1], "", "Title clip does not have an initial text")
 
         self.action_log.undo()
         clips = self.layer.get_clips()
         self.assertEqual(len(clips), 0, clips)
 
         self.action_log.redo()
-        ps2 = self._get_title_source_child_props()
-        self.assertDictEqual(ps1, ps2)
+        properties2 = self._get_title_source_child_props()
+        self.assertDictEqual(properties1, properties2)
 
     @common.setup_timeline
     @common.setup_clipproperties
@@ -316,24 +318,82 @@ class TitlePropertiesTest(common.TestCase):
         self.project.pipeline.get_position = mock.Mock(return_value=0)
 
         self.clipproperties.create_title_clip_cb(None)
-        ps1 = self._get_title_source_child_props()
+        properties1 = self._get_title_source_child_props()
 
         # Modify the title.
         mod_title = "Modifed Title"
         self.clipproperties.title_expander.textbuffer.props.text = mod_title
-        ps2 = self._get_title_source_child_props()
-        self.assertEqual(ps2["text"][1], mod_title)
-        self.assertNotEqual(ps1["text"], ps2["text"])
+        properties2 = self._get_title_source_child_props()
+        self.assertEqual(properties2["text"], (True, mod_title))
+        self.assertNotEqual(properties1["text"], properties2["text"])
 
         # Undo modify title.
         self.action_log.undo()
-        ps3 = self._get_title_source_child_props()
-        self.assertDictEqual(ps1, ps3)
+        properties3 = self._get_title_source_child_props()
+        self.assertDictEqual(properties1, properties3)
 
         # Redo modify title.
         self.action_log.redo()
-        ps4 = self._get_title_source_child_props()
-        self.assertDictEqual(ps2, ps4)
+        properties4 = self._get_title_source_child_props()
+        self.assertDictEqual(properties2, properties4)
+
+    @common.setup_timeline
+    @common.setup_clipproperties
+    def test_modify_outline_color(self):
+        """Exercise modifying the outline color."""
+        self.project.pipeline.get_position = mock.Mock(return_value=0)
+
+        self.clipproperties.create_title_clip_cb(None)
+        properties1 = self._get_title_source_child_props()
+
+        # Modify the outline color.
+        mod_outline_color = 0xFFFFFFFF
+        color_button_mock = mock.Mock()
+        color_picker_mock = mock.Mock()
+        color_picker_mock.calculate_argb.return_value = mod_outline_color
+        self.clipproperties.title_expander._color_picker_value_changed_cb(color_picker_mock, 
color_button_mock, "outline-color")
+        properties2 = self._get_title_source_child_props()
+        self.assertEqual(properties2["outline-color"], (True, mod_outline_color))
+        self.assertNotEqual(properties1["outline-color"], properties2["outline-color"])
+
+        # Undo modify outline color.
+        self.action_log.undo()
+        properties3 = self._get_title_source_child_props()
+        self.assertDictEqual(properties1, properties3)
+
+        # Redo modify outline color.
+        self.action_log.redo()
+        properties4 = self._get_title_source_child_props()
+        self.assertDictEqual(properties2, properties4)
+
+    @common.setup_timeline
+    @common.setup_clipproperties
+    def test_modify_drop_shadow(self):
+        """Exercise modifying the drop shadow."""
+        self.project.pipeline.get_position = mock.Mock(return_value=0)
+
+        self.clipproperties.create_title_clip_cb(None)
+        properties1 = self._get_title_source_child_props()
+
+        # Modify the drop shadow.
+        drop_shadow = False
+        drop_shadow_checkbox_mock = mock.Mock()
+        drop_shadow_checkbox_mock.get_active.return_value = drop_shadow
+        self.clipproperties.title_expander._drop_shadow_checkbox_cb(drop_shadow_checkbox_mock)
+
+        properties2 = self._get_title_source_child_props()
+        self.assertEqual(properties2["draw-shadow"], (True, drop_shadow))
+        self.assertNotEqual(properties1["draw-shadow"], properties2["draw-shadow"])
+
+        # Undo modify drop shadow.
+        self.action_log.undo()
+        properties3 = self._get_title_source_child_props()
+        self.assertDictEqual(properties1, properties3)
+
+        # Redo modify drop shadow.
+        self.action_log.redo()
+        properties4 = self._get_title_source_child_props()
+        self.assertDictEqual(properties2, properties4)
 
     @common.setup_timeline
     @common.setup_clipproperties


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