Browse Source

Milestone: Layers now save,
Layers can be added and removed,
Everything still works and is backwards compatible with the base layer,
The layer list is only shown if there are more than one layers,
All that needs to be done is the drawing and processing of masks on layers.

Billy Barrow 8 years ago
parent
commit
af6ea29ee1
4 changed files with 231 additions and 23 deletions
  1. 28 1
      PF2/Layer.py
  2. 118 11
      PF2/__init__.py
  3. 0 4
      Tool/__init__.py
  4. 85 7
      ui/PF2_Activity.glade

+ 28 - 1
PF2/Layer.py

@@ -2,6 +2,7 @@ from gi.repository import Gtk, GLib
 
 class Layer:
     def __init__(self, base, name, on_change):
+        print("init", name)
         self.mask = []
         self.tools = []
         self.tool_map = {}
@@ -9,13 +10,22 @@ class Layer:
         self.enabled = True
         self.selected_tool = 0
         self.editable = not base
+
+        self.selector_row = None
+
         self.tool_box = Gtk.FlowBox()
+        self.tool_box.set_orientation(1)
+
         self.tool_stack = Gtk.Stack()
+        self.tool_stack.set_transition_type(6)
+        self.tool_stack.set_homogeneous(False)
+
 
         self.layer_changed = on_change
 
 
     def add_tool(self, tool):
+        print("add tool", tool)
         self.tool_box.add(tool.tool_button)
         self.tool_stack.add(tool.widget)
         self.tool_map[tool.tool_button] = tool
@@ -25,6 +35,9 @@ class Layer:
 
         self.tools += [tool,]
 
+        if(len(self.tools) == 1):
+            tool.tool_button.set_active(True)
+
 
     def on_tool_change(self, tool, prop):
         self.layer_changed(self)
@@ -56,6 +69,7 @@ class Layer:
         return layerDict
 
     def set_from_layer_dict(self, dict):
+        print("set_from_layer_dict", dict)
         # Load Tool Data
         for tool in self.tools:
             if(tool.id in dict["tools"]):
@@ -91,11 +105,24 @@ class Layer:
                 layer = tool.on_update(layer)
                 count += 1
 
+            image = layer
+
         ## Here we would blend with the mask
-        image = layer
 
         return image
 
 
+    def show_all(self):
 
+        self.tool_box.show_all()
+        self.tool_stack.show_all()
+
+        for tool in self.tools:
+            tool.widget.show_all()
+            tool.tool_button.show_all()
+
+
+    def reset_tools(self):
+        for tool in self.tools:
+            tool.reset()
 

+ 118 - 11
PF2/__init__.py

@@ -69,6 +69,10 @@ class PF2(Activity.Activity):
             "mask_erase_toggle",
             "mask_brush_size",
             "layers_list",
+            "new_layer",
+            "layer_mask_reveal",
+            "add_layer_button",
+            "remove_layer_button"
         ]
 
         for component in components:
@@ -142,10 +146,14 @@ class PF2(Activity.Activity):
         self.ui["undo"].connect("clicked", self.on_undo)
         self.ui["redo"].connect("clicked", self.on_redo)
         self.ui["reset"].connect("clicked", self.on_reset)
-
         self.ui["preview_eventbox"].connect('motion-notify-event', self.preview_dragged)
         self.ui["mask_draw_toggle"].connect("toggled", self.mask_draw_toggled)
         self.ui["mask_erase_toggle"].connect("toggled", self.mask_erase_toggled)
+        self.ui["new_layer"].connect("clicked", self.new_layer_button_clicked)
+        self.ui["layers_list"].connect("row-activated", self.layer_ui_activated)
+        self.ui["add_layer_button"].connect("clicked", self.new_layer_button_clicked)
+        self.ui["remove_layer_button"].connect("clicked", self.remove_layer_button_clicked)
+
 
 
 
@@ -164,6 +172,8 @@ class PF2(Activity.Activity):
         self.ui["original_toggle"].set_sensitive(True)
         self.ui["export_image"].set_sensitive(True)
         self.ui["reset"].set_sensitive(True)
+        self.ui["new_layer"].set_sensitive(True)
+        self.ui["layers_reveal"].set_reveal_child(False)
         self.is_editing = True
         if(path == None):
             self.image_path = self.ui["open_chooser"].get_filename()
@@ -176,6 +186,15 @@ class PF2(Activity.Activity):
         self.show_message("Loading Photo…", "Please wait while PhotoFiddle loads your photo", True)
         self.root.get_titlebar().set_subtitle("%s…" % (self.image_path))
 
+        # Delete all layers, except the base
+        for layer in self.layers:
+            if(layer.name != "base"):
+                self.ui["layers_list"].remove(layer.selector_row)
+
+        self.layers = [self.base_layer,]
+
+        self.select_layer(self.base_layer)
+
         thread = threading.Thread(target=self.open_image,
                                   args=(w, h))
         thread.start()
@@ -324,8 +343,8 @@ class PF2(Activity.Activity):
         self.update_from_undo_stack(self.undo_stack[self.undo_position])
 
     def on_reset(self, sender):
-        for tool in self.tools:
-            tool.reset()
+        for layer in self.layers:
+            layer.reset_tools()
 
 
 
@@ -504,11 +523,7 @@ class PF2(Activity.Activity):
                 data = ast.literal_eval(sdata)
                 if(data["format-revision"] == 1):
                     for layer in data["layers"]:
-                        if(layer == "base"):
-                            self.base_layer.set_from_layer_dict(data["layers"][layer])
-                        else:
-                            ilayer = self.create_layer(layer, False)
-                            ilayer.set_from_layer_dict(data["layers"][layer])
+                        GLib.idle_add(self.create_layer_with_data, layer, data["layers"][layer])
 
                     self.undo_stack = [data["layers"],]
                     self.undo_position = 0
@@ -534,6 +549,15 @@ class PF2(Activity.Activity):
         self.undoing = False
 
 
+    def create_layer_with_data(self, layer, data):
+        if (layer == "base"):
+            self.base_layer.set_from_layer_dict(data)
+        else:
+            GLib.idle_add(self.show_layers)
+            ilayer = self.create_layer(layer, False)
+            ilayer.set_from_layer_dict(data)
+
+
     def update_from_undo_stack(self, data):
         self.undoing = True
         for layer in data:
@@ -582,22 +606,105 @@ class PF2(Activity.Activity):
 
         self.layers += [layer,]
 
-        self.create_layer_ui(layer)
+        GLib.idle_add(self.create_layer_ui, layer)
 
         return layer
 
     def create_layer_ui(self, layer):
         layer_box = Gtk.HBox()
+        layer_box.set_hexpand(False)
+        layer_box.set_halign(Gtk.Align.START)
+
         layer_toggle = Gtk.CheckButton()
-        layer_toggle.set_sensitive(not layer.editable)
+        layer_toggle.set_sensitive(layer.editable)
         layer_toggle.set_active(layer.enabled)
+        layer_toggle.set_hexpand(False)
+        layer_toggle.set_halign(Gtk.Align.START)
+        layer_toggle.set_margin_right(8)
+        layer_toggle.set_margin_left(8)
+        layer_toggle.set_margin_top(4)
+        layer_toggle.set_margin_bottom(4)
+
+
         layer_label = Gtk.Label()
         layer_label.set_label(layer.name)
+        layer_label.set_hexpand(True)
+        layer_label.set_halign(Gtk.Align.FILL)
+        layer_label.set_margin_top(4)
+        layer_label.set_margin_bottom(4)
 
         layer_box.add(layer_toggle)
         layer_box.add(layer_label)
 
+        layer.show_all()
+        layer_box.show_all()
+
         self.ui["layers_list"].add(layer_box)
 
+        layer.selector_row = layer_box.get_parent()
+
         self.ui["tool_box_stack"].add(layer.tool_box)
-        self.ui["tool_stack"].add(layer.tool_stack)
+        self.ui["tool_stack"].add(layer.tool_stack)
+
+
+    def layer_ui_activated(self, widget, row):
+        layer_index = row.get_index()
+        self.ui["tool_stack"].set_visible_child(self.layers[layer_index].tool_stack)
+        self.ui["tool_box_stack"].set_visible_child(self.layers[layer_index].tool_box)
+        self.ui["layer_mask_reveal"].set_reveal_child(self.layers[layer_index].editable)
+        self.ui["remove_layer_button"].set_sensitive(self.layers[layer_index].editable)
+
+
+    def new_layer_button_clicked(self, widget):
+        self.show_layers()
+        # Allocate an un-used layer name
+        layer_number = len(self.layers)
+        layer_name = "Layer %i" % layer_number
+
+        while(self.layer_exists(layer_name)):
+            layer_number += 1
+            layer_name = "Layer %i" % layer_number
+
+        # Create the layer
+        layer = self.create_layer(layer_name, False)
+
+        # Save changes
+        threading.Thread(target=self.save_image_data).start()
+
+
+    def remove_layer_button_clicked(self, widget):
+        layer_row = self.ui["layers_list"].get_selected_row()
+
+        selected_index = 1
+
+        new_layers = []
+        for layer in self.layers:
+            if(layer.selector_row != layer_row):
+                new_layers += [layer]
+            else:
+                selected_index = self.layers.index(layer)
+
+        self.ui["layers_list"].remove(layer_row)
+        self.layers = new_layers
+
+        # Select next layer
+        self.select_layer(self.layers[selected_index -1])
+
+        if(len(self.layers) == 1):
+            self.ui["layers_reveal"].set_reveal_child(False)
+
+        # Save changes
+        threading.Thread(target=self.save_image_data).start()
+
+    def layer_exists(self, layer_name):
+        for layer in self.layers:
+            if(layer.name == layer_name):
+                return True
+        return False
+
+    def show_layers(self):
+        self.ui["layers_reveal"].set_reveal_child(True)
+
+    def select_layer(self, layer):
+        self.ui["layers_list"].select_row(layer.selector_row)
+        self.layer_ui_activated(self.ui["layers_list"], layer.selector_row)

+ 0 - 4
Tool/__init__.py

@@ -34,7 +34,6 @@ class Tool:
                     # Add a Separator
                     separator = Gtk.Separator()
                     separator.set_margin_top(6)
-                    separator.show()
                     self.widget.attach(separator, 0, vpos, 3, 1)
                     vpos += 1
 
@@ -159,11 +158,8 @@ class Tool:
 
         separator = Gtk.Separator()
         separator.set_margin_top(6)
-        separator.show()
         self.widget.attach(separator, 0, vpos, 3, 1)
 
-        self.widget.show_all()
-
         self.tool_button = Gtk.ToggleButton()
         self.tool_button.set_tooltip_text(self.name)
         icon = Gtk.Image()

+ 85 - 7
ui/PF2_Activity.glade

@@ -315,7 +315,6 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="transition_type">slide-up</property>
-                        <property name="reveal_child">True</property>
                         <child>
                           <object class="GtkBox">
                             <property name="visible">True</property>
@@ -338,7 +337,7 @@
                             </child>
                             <child>
                               <object class="GtkScrolledWindow">
-                                <property name="height_request">150</property>
+                                <property name="height_request">100</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="hscrollbar_policy">never</property>
@@ -362,6 +361,59 @@
                                 <property name="position">1</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkButtonBox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <property name="layout_style">end</property>
+                                <child>
+                                  <object class="GtkButton" id="PF2_add_layer_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <child>
+                                      <object class="GtkImage">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="icon_name">list-add-symbolic</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                    <property name="non_homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkButton" id="PF2_remove_layer_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <child>
+                                      <object class="GtkImage">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="icon_name">list-remove-symbolic</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                    <property name="non_homogeneous">True</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
                             <child>
                               <object class="GtkSeparator">
                                 <property name="visible">True</property>
@@ -370,7 +422,7 @@
                               <packing>
                                 <property name="expand">False</property>
                                 <property name="fill">True</property>
-                                <property name="position">2</property>
+                                <property name="position">3</property>
                               </packing>
                             </child>
                           </object>
@@ -387,7 +439,6 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="transition_type">slide-up</property>
-                        <property name="reveal_child">True</property>
                         <child>
                           <object class="GtkBox">
                             <property name="visible">True</property>
@@ -547,6 +598,8 @@
                           <object class="GtkStack" id="PF2_tool_box_stack">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
+                            <property name="halign">start</property>
+                            <property name="valign">start</property>
                             <property name="transition_type">crossfade</property>
                             <child>
                               <placeholder/>
@@ -593,7 +646,7 @@
                                 <property name="can_focus">False</property>
                                 <property name="hhomogeneous">False</property>
                                 <property name="vhomogeneous">False</property>
-                                <property name="transition_type">slide-left-right</property>
+                                <property name="transition_type">crossfade</property>
                                 <child>
                                   <placeholder/>
                                 </child>
@@ -732,6 +785,32 @@
             <property name="position">3</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkModelButton" id="PF2_new_layer">
+            <property name="visible">True</property>
+            <property name="sensitive">False</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="tooltip_text" translatable="yes">Reset all settings for this image</property>
+            <property name="text" translatable="yes">New Layer</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSeparator">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
         <child>
           <object class="GtkModelButton" id="PF2_reset">
             <property name="visible">True</property>
@@ -744,13 +823,12 @@
           <packing>
             <property name="expand">False</property>
             <property name="fill">True</property>
-            <property name="position">4</property>
+            <property name="position">6</property>
           </packing>
         </child>
       </object>
       <packing>
         <property name="submenu">main</property>
-        <property name="position">1</property>
       </packing>
     </child>
   </object>