[gthumb] rotate image: simplified the align horizonal/vertical function



commit 527ea0312a0cf91854e9946ab436117760169a51
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Tue May 17 23:59:25 2011 +0200

    rotate image: simplified the align horizonal/vertical function

 extensions/file_tools/Makefile.am               |    2 +
 extensions/file_tools/data/ui/rotate-options.ui |  820 ++++++++++++++---------
 extensions/file_tools/gth-file-tool-rotate.c    |  176 ++----
 extensions/file_tools/gth-image-line-tool.c     |  404 +++++++++++
 extensions/file_tools/gth-image-line-tool.h     |   65 ++
 5 files changed, 1012 insertions(+), 455 deletions(-)
---
diff --git a/extensions/file_tools/Makefile.am b/extensions/file_tools/Makefile.am
index 74a619a..f2dffce 100644
--- a/extensions/file_tools/Makefile.am
+++ b/extensions/file_tools/Makefile.am
@@ -28,6 +28,7 @@ HEADER_FILES = 				\
 	gth-file-tool-save-as.h		\
 	gth-file-tool-sharpen.h		\
 	gth-file-tool-undo.h		\
+	gth-image-line-tool.h		\
 	gth-image-rotator.h		\
 	preferences.h
 
@@ -76,6 +77,7 @@ libfile_tools_la_SOURCES = 		\
 	gth-file-tool-save-as.c		\
 	gth-file-tool-sharpen.c		\
 	gth-file-tool-undo.c		\
+	gth-image-line-tool.c		\
 	gth-image-rotator.c		\
 	main.c
 
diff --git a/extensions/file_tools/data/ui/rotate-options.ui b/extensions/file_tools/data/ui/rotate-options.ui
index ebe6edd..3de50ba 100644
--- a/extensions/file_tools/data/ui/rotate-options.ui
+++ b/extensions/file_tools/data/ui/rotate-options.ui
@@ -1,47 +1,60 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <object class="GtkAlignment" id="options">
+  <requires lib="gtk+" version="2.24"/>
+  <object class="GtkNotebook" id="options_notebook">
     <property name="visible">True</property>
-    <property name="can_focus">False</property>
-    <property name="top_padding">6</property>
+    <property name="can_focus">True</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
     <child>
-      <object class="GtkVBox" id="vbox2">
+      <object class="GtkAlignment" id="rotation_options">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="top_padding">6</property>
         <child>
-          <object class="GtkVBox" id="vbox1">
+          <object class="GtkVBox" id="vbox2">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="spacing">12</property>
             <child>
-              <object class="GtkFrame" id="rotation_frame">
+              <object class="GtkVBox" id="vbox1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label_xalign">0</property>
-                <property name="shadow_type">none</property>
+                <property name="spacing">12</property>
                 <child>
-                  <object class="GtkAlignment" id="alignment12">
+                  <object class="GtkFrame" id="rotation_frame">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="top_padding">6</property>
-                    <property name="left_padding">12</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
                     <child>
-                      <object class="GtkVBox" id="vbox4">
+                      <object class="GtkAlignment" id="alignment12">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
                         <child>
-                          <object class="GtkHBox" id="hbox4">
+                          <object class="GtkVBox" id="vbox4">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="spacing">6</property>
                             <child>
-                              <object class="GtkHBox" id="rotation_angle_hbox">
+                              <object class="GtkHBox" id="hbox4">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
                                 <child>
-                                  <placeholder/>
+                                  <object class="GtkHBox" id="rotation_angle_hbox">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
                                 </child>
                               </object>
                               <packing>
@@ -50,79 +63,228 @@
                                 <property name="position">0</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkHButtonBox" id="hbuttonbox2">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <property name="layout_style">spread</property>
+                                <child>
+                                  <object class="GtkButton" id="align_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="use_underline">True</property>
+                                    <child>
+                                      <object class="GtkLabel" id="label5">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="label" translatable="yes">Align</property>
+                                        <attributes>
+                                          <attribute name="size" value="8000"/>
+                                        </attributes>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
                           </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
                         </child>
                       </object>
                     </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label11">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Angle</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
                 </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label11">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Angle</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFrame" id="crop_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="GtkAlignment" id="alignment3">
+                  <object class="GtkFrame" id="crop_frame">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="top_padding">6</property>
-                    <property name="left_padding">12</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
                     <child>
-                      <object class="GtkVBox" id="vbox5">
+                      <object class="GtkAlignment" id="alignment3">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
                         <child>
-                          <object class="GtkComboBox" id="resize_combobox">
+                          <object class="GtkVBox" id="vbox5">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="model">resize_liststore</property>
+                            <property name="spacing">6</property>
                             <child>
-                              <object class="GtkCellRendererText" id="cellrenderertext1"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
+                              <object class="GtkComboBox" id="resize_combobox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="model">resize_liststore</property>
+                                <child>
+                                  <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                                  <attributes>
+                                    <attribute name="text">0</attribute>
+                                  </attributes>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkTable" id="crop_options_table">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="n_rows">3</property>
+                                <property name="n_columns">2</property>
+                                <property name="column_spacing">6</property>
+                                <property name="row_spacing">6</property>
+                                <child>
+                                  <object class="GtkHBox" id="crop_p1_hbox">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkHBox" id="crop_p2_hbox">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="crop_p1_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Point 1:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="crop_p2_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Point 2:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="keep_aspect_ratio">
+                                    <property name="label" translatable="yes">Keep aspect ratio</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="right_attach">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
                             </child>
                           </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
                         </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Image size</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="options_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="GtkAlignment" id="alignment4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
                         <child>
-                          <object class="GtkTable" id="crop_options_table">
+                          <object class="GtkTable" id="table2">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="n_rows">3</property>
+                            <property name="n_rows">2</property>
                             <property name="n_columns">2</property>
                             <property name="column_spacing">6</property>
                             <property name="row_spacing">6</property>
                             <child>
-                              <object class="GtkHBox" id="crop_p1_hbox">
+                              <object class="GtkVBox" id="crop_grid_hbox">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
                                 <child>
@@ -132,238 +294,279 @@
                               <packing>
                                 <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
-                                <property name="top_attach">1</property>
-                                <property name="bottom_attach">2</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkHBox" id="crop_p2_hbox">
+                              <object class="GtkLabel" id="crop_grid_label">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <child>
-                                  <placeholder/>
-                                </child>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Grid:</property>
                               </object>
                               <packing>
-                                <property name="left_attach">1</property>
-                                <property name="right_attach">2</property>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
+                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkLabel" id="crop_p1_label">
+                              <object class="GtkHBox" id="hbox2">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Point 1:</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkColorButton" id="background_colorbutton">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="title" translatable="yes">Pick a background color</property>
+                                    <property name="color">#000000000000</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="background_transparent_checkbutton">
+                                    <property name="label" translatable="yes">_Transparent</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
                               </object>
                               <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
-                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkLabel" id="crop_p2_label">
+                              <object class="GtkLabel" id="label6">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Point 2:</property>
+                                <property name="label" translatable="yes">_Background:</property>
+                                <property name="use_underline">True</property>
                               </object>
                               <packing>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
                                 <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
-                            <child>
-                              <object class="GtkCheckButton" id="keep_aspect_ratio">
-                                <property name="label" translatable="yes">Keep aspect ratio</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
-                                <property name="xalign">0</property>
-                                <property name="active">True</property>
-                                <property name="draw_indicator">True</property>
-                              </object>
-                              <packing>
-                                <property name="right_attach">2</property>
-                              </packing>
-                            </child>
                           </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
                         </child>
                       </object>
                     </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Options</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
                   </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
                 </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label3">
+                <child>
+                  <object class="GtkHBox" id="hbox3">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Image size</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
+                    <property name="border_width">6</property>
+                    <child>
+                      <object class="GtkButton" id="reset_button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_action_appearance">False</property>
+                        <child>
+                          <object class="GtkLabel" id="label9">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">Reset</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
                   </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
                 </child>
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="fill">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHSeparator" id="hseparator1">
+                <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="padding">6</property>
                 <property name="position">1</property>
               </packing>
             </child>
             <child>
-              <object class="GtkFrame" id="align_frame">
+              <object class="GtkHButtonBox" id="hbuttonbox1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label_xalign">0</property>
-                <property name="shadow_type">none</property>
+                <property name="spacing">12</property>
+                <property name="layout_style">center</property>
                 <child>
-                  <object class="GtkAlignment" id="alignment2">
+                  <object class="GtkButton" id="apply_button">
+                    <property name="label">gtk-apply</property>
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="top_padding">6</property>
-                    <property name="left_padding">12</property>
-                    <child>
-                      <object class="GtkHButtonBox" id="hbuttonbox3">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <property name="layout_style">spread</property>
-                        <child>
-                          <object class="GtkButton" id="align_h_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_underline">True</property>
-                            <child>
-                              <object class="GtkLabel" id="label6">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="label" translatable="yes">Align horizontally</property>
-                                <attributes>
-                                  <attribute name="size" value="8000"/>
-                                </attributes>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="align_v_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_underline">True</property>
-                            <child>
-                              <object class="GtkLabel" id="label7">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="label" translatable="yes">Align vertically</property>
-                                <attributes>
-                                  <attribute name="size" value="8000"/>
-                                </attributes>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="use_stock">True</property>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
                 </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label12">
+                <child>
+                  <object class="GtkButton" id="cancel_button">
+                    <property name="label">gtk-cancel</property>
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Automatic alignment</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_stock">True</property>
+                    <property name="xalign">0.47999998927116394</property>
                   </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
               </object>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
+                <property name="padding">6</property>
                 <property name="position">2</property>
               </packing>
             </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label">page 1</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkAlignment" id="alignment_options">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="top_padding">6</property>
+        <child>
+          <object class="GtkVBox" id="vbox3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <child>
-              <object class="GtkFrame" id="options_frame">
+              <object class="GtkVBox" id="vbox6">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label_xalign">0</property>
-                <property name="shadow_type">none</property>
+                <property name="spacing">12</property>
                 <child>
-                  <object class="GtkAlignment" id="alignment4">
+                  <object class="GtkVBox" id="box2">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="top_padding">6</property>
-                    <property name="left_padding">12</property>
+                    <property name="border_width">5</property>
                     <child>
-                      <object class="GtkTable" id="table2">
+                      <object class="GtkLabel" id="label8">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="n_rows">2</property>
-                        <property name="n_columns">2</property>
-                        <property name="column_spacing">6</property>
-                        <property name="row_spacing">6</property>
-                        <child>
-                          <object class="GtkVBox" id="crop_grid_hbox">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <child>
-                              <placeholder/>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="crop_grid_label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Grid:</property>
-                          </object>
-                          <packing>
-                            <property name="x_options">GTK_FILL</property>
-                          </packing>
-                        </child>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Draw a line on the image 
+to set the alignment.</property>
+                        <property name="wrap">True</property>
+                        <property name="wrap_mode">word-char</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="rotation_frame1">
+                    <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="GtkAlignment" id="alignment1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
                         <child>
-                          <object class="GtkHBox" id="hbox2">
+                          <object class="GtkVBox" id="box1">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="spacing">6</property>
                             <child>
-                              <object class="GtkColorButton" id="background_colorbutton">
+                              <object class="GtkRadioButton" id="alignment_parallel_radiobutton">
+                                <property name="label" translatable="yes">Parallel</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
+                                <property name="receives_default">False</property>
                                 <property name="use_action_appearance">False</property>
-                                <property name="title" translatable="yes">Pick a background color</property>
-                                <property name="color">#000000000000</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
@@ -372,163 +575,124 @@
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkCheckButton" id="background_transparent_checkbutton">
-                                <property name="label" translatable="yes">_Transparent</property>
+                              <object class="GtkRadioButton" id="alignment_perpendicular_radiobutton">
+                                <property name="label" translatable="yes">Perpendicular</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
                                 <property name="use_action_appearance">False</property>
-                                <property name="use_underline">True</property>
                                 <property name="xalign">0</property>
+                                <property name="active">True</property>
                                 <property name="draw_indicator">True</property>
+                                <property name="group">alignment_parallel_radiobutton</property>
                               </object>
                               <packing>
-                                <property name="expand">True</property>
+                                <property name="expand">False</property>
                                 <property name="fill">True</property>
                                 <property name="position">1</property>
                               </packing>
                             </child>
                           </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label4">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Background:</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_FILL</property>
-                          </packing>
                         </child>
                       </object>
                     </child>
-                  </object>
-                </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Options</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">3</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkHBox" id="hbox3">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <child>
-                  <object class="GtkButton" id="reset_button">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <property name="use_action_appearance">False</property>
-                    <child>
-                      <object class="GtkLabel" id="label1">
+                    <child type="label">
+                      <object class="GtkLabel" id="label13">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">Reset</property>
+                        <property name="label" translatable="yes">Alignment</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
                       </object>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">0</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
               </object>
               <packing>
-                <property name="expand">True</property>
+                <property name="expand">False</property>
                 <property name="fill">True</property>
-                <property name="position">4</property>
+                <property name="position">0</property>
               </packing>
             </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkHSeparator" id="hseparator1">
-            <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="padding">6</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkHButtonBox" id="hbuttonbox1">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="spacing">12</property>
-            <property name="layout_style">center</property>
             <child>
-              <object class="GtkButton" id="apply_button">
-                <property name="label">gtk-apply</property>
+              <object class="GtkHSeparator" id="hseparator2">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_action_appearance">False</property>
-                <property name="use_underline">True</property>
-                <property name="use_stock">True</property>
+                <property name="can_focus">False</property>
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
+                <property name="fill">True</property>
+                <property name="padding">6</property>
+                <property name="position">1</property>
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="cancel_button">
-                <property name="label">gtk-cancel</property>
+              <object class="GtkHButtonBox" id="hbuttonbox4">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_action_appearance">False</property>
-                <property name="use_stock">True</property>
-                <property name="xalign">0.47999998927116394</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">12</property>
+                <property name="layout_style">center</property>
+                <child>
+                  <object class="GtkButton" id="alignment_cancel_button">
+                    <property name="label">gtk-cancel</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_stock">True</property>
+                    <property name="xalign">0.47999998927116394</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">1</property>
+                <property name="padding">6</property>
+                <property name="position">2</property>
               </packing>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="padding">6</property>
-            <property name="position">2</property>
-          </packing>
         </child>
       </object>
+      <packing>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label">page 2</property>
+      </object>
+      <packing>
+        <property name="position">1</property>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label3">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label">page 3</property>
+      </object>
+      <packing>
+        <property name="position">2</property>
+        <property name="tab_fill">False</property>
+      </packing>
     </child>
   </object>
   <object class="GtkListStore" id="resize_liststore">
diff --git a/extensions/file_tools/gth-file-tool-rotate.c b/extensions/file_tools/gth-file-tool-rotate.c
index 51866c7..ddda9dc 100644
--- a/extensions/file_tools/gth-file-tool-rotate.c
+++ b/extensions/file_tools/gth-file-tool-rotate.c
@@ -26,6 +26,7 @@
 #include "cairo-rotate.h"
 #include "enum-types.h"
 #include "gth-file-tool-rotate.h"
+#include "gth-image-line-tool.h"
 #include "gth-image-rotator.h"
 #include "preferences.h"
 
@@ -40,7 +41,6 @@ struct _GthFileToolRotatePrivate {
 	cairo_surface_t    *image;
 	gboolean            has_alpha;
 	GtkBuilder         *builder;
-	GtkWidget          *options;
 	GtkWidget          *crop_grid;
 	GtkAdjustment      *rotation_angle_adj;
 	GtkAdjustment      *crop_p1_adj;
@@ -48,12 +48,8 @@ struct _GthFileToolRotatePrivate {
 	gboolean            crop_enabled;
 	double              crop_p1_plus_p2;
 	GdkRectangle        crop_region;
-	GthImageSelector   *selector_crop;
-	GthImageSelector   *selector_align;
+	GthImageViewerTool *alignment;
 	GthImageViewerTool *rotator;
-	guint               selector_align_direction;
-	guint               selector_align_point;
-	GdkPoint            align_points[2];
 };
 
 
@@ -160,91 +156,67 @@ update_crop_grid (GthFileToolRotate *self)
 
 
 static void
-align_begin (GthFileToolRotate *self)
+alignment_changed_cb (GthImageLineTool  *line_tool,
+		      GthFileToolRotate *self)
 {
 	GtkWidget *window;
 	GtkWidget *viewer_page;
 	GtkWidget *viewer;
+	GdkPoint   p1;
+	GdkPoint   p2;
+	double     angle;
 
 	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (GET_WIDGET ("options_notebook")), 0);
+	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->rotator);
 
-	self->priv->selector_align_point = 0;
-
-	gtk_widget_set_sensitive (self->priv->options, FALSE);
+	gth_image_line_tool_get_points (line_tool, &p1, &p2);
+	angle = _cairo_image_surface_rotate_get_align_angle (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("alignment_parallel_radiobutton"))), p1, p2);
+	gtk_adjustment_set_value (self->priv->rotation_angle_adj, angle);
+}
 
-	/* FIXME
-	gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), self->priv->src_pixbuf, FALSE); */
 
-	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector_align);
+static void
+apply_changes (GthFileToolRotate *self)
+{
+	gth_image_rotator_set_angle (GTH_IMAGE_ROTATOR (self->priv->rotator), gtk_adjustment_get_value (self->priv->rotation_angle_adj));
+	update_crop_parameters (self);
+	update_crop_region (self);
 }
 
 
 static void
-align_end (GthFileToolRotate *self)
+alignment_cancel_button_clicked_cb (GtkButton         *button,
+				    GthFileToolRotate *self)
 {
 	GtkWidget *window;
 	GtkWidget *viewer_page;
-	double     angle;
+	GtkWidget *viewer;
 
 	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
-
-	angle = _cairo_image_surface_rotate_get_align_angle (self->priv->selector_align_direction == 1,
-						    	     self->priv->align_points[0],
-						    	     self->priv->align_points[1]),
-
-	self->priv->selector_align_direction = 0;
-	self->priv->selector_align_point = 0;
-
-	gtk_widget_set_sensitive (self->priv->options, TRUE);
-
-	if (angle == gtk_adjustment_get_value (self->priv->rotation_angle_adj)) {
-
-		/* We already have the pixmap ready */
-
-		/* FIXME
-		gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), self->priv->rotate_pixbuf, FALSE);
-		*/
-
-		update_crop_parameters (self);
-		update_crop_region (self);
-	}
-	else {
-		/* This triggers the rotation and the update of crop parameters */
-
-		gtk_adjustment_set_value (self->priv->rotation_angle_adj, angle);
-	}
+	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (GET_WIDGET ("options_notebook")), 0);
+	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->rotator);
 }
 
 
 static void
-apply_changes (GthFileToolRotate *self)
+align_button_clicked_cb (GtkButton         *button,
+			 GthFileToolRotate *self)
 {
-	/* FIXME
-	cairo_color_t      background_color;
-	if (self->priv->background_transparent) {
-		background_color.r = 0.0;
-		background_color.g = 0.0;
-		background_color.b = 0.0;
-		background_color.a = 0.0;
-	}
-	else {
-		GdkColor color;
+	GtkWidget *window;
+	GtkWidget *viewer_page;
+	GtkWidget *viewer;
 
-		gtk_color_button_get_color (GTK_COLOR_BUTTON (self->priv->background_colorbutton), &color);
-		background_color.r = (double) color.red / 65535;
-		background_color.g = (double) color.green / 65535;
-		background_color.b = (double) color.blue / 65535;
-		background_color.a = 1.0;
-	}
-	gth_image_rotator_set_background (GTH_IMAGE_ROTATOR (self->priv->rotator), &self->priv->background_color);
-	 */
+	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
 
-	gth_image_rotator_set_angle (GTH_IMAGE_ROTATOR (self->priv->rotator), gtk_adjustment_get_value (self->priv->rotation_angle_adj));
-	update_crop_parameters (self);
-	update_crop_region (self);
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (GET_WIDGET ("options_notebook")), 1);
+	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->alignment);
 }
 
 
@@ -257,26 +229,6 @@ reset_button_clicked_cb (GtkButton         *button,
 
 
 static void
-align_h_button_clicked_cb (GtkButton         *button,
-			   GthFileToolRotate *self)
-{
-	self->priv->selector_align_direction = 0;
-
-	align_begin (self);
-}
-
-
-static void
-align_v_button_clicked_cb (GtkButton         *button,
-			   GthFileToolRotate *self)
-{
-	self->priv->selector_align_direction = 1;
-
-	align_begin (self);
-}
-
-
-static void
 apply_button_clicked_cb (GtkButton         *button,
 			 GthFileToolRotate *self)
 {
@@ -386,24 +338,6 @@ background_transparent_toggled_cb (GtkToggleButton   *toggle_button,
 
 
 static void
-selector_selected_cb (GthImageSelector  *selector,
-		      int                x,
-		      int                y,
-		      GthFileToolRotate *self)
-{
-	guint i;
-
-	i = self->priv->selector_align_point++;
-
-	self->priv->align_points[i].x = x;
-	self->priv->align_points[i].y = y;
-
-	if (self->priv->selector_align_point == 2)
-		align_end (self);
-}
-
-
-static void
 resize_combobox_changed_cb (GtkComboBox       *combo_box,
 			    GthFileToolRotate *self)
 {
@@ -441,9 +375,6 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 
 	self->priv->builder = _gtk_builder_new_from_file ("rotate-options.ui", "file_tools");
 
-	self->priv->options = _gtk_builder_get_widget (self->priv->builder, "options");
-	gtk_widget_show (self->priv->options);
-
 	self->priv->rotation_angle_adj = gimp_scale_entry_new (GET_WIDGET ("rotation_angle_hbox"),
 							       GTK_LABEL (GET_WIDGET ("rotation_angle_label")),
 							       0.0, -90.0, 90.0, 0.1, 1.0, 1);
@@ -471,12 +402,9 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("keep_aspect_ratio")), eel_gconf_get_boolean (PREF_ROTATE_KEEP_ASPECT_RATIO, TRUE));
 
-	self->priv->selector_crop = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_REGION);
-	self->priv->selector_align = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_POINT);
-	gth_image_selector_set_mask_visible (self->priv->selector_crop, TRUE);
-	gth_image_selector_set_mask_visible (self->priv->selector_align, FALSE);
+	self->priv->alignment = gth_image_line_tool_new ();
 
-	self->priv->rotator = gth_image_rotator_new (GTH_IMAGE_VIEWER (viewer));
+	self->priv->rotator = gth_image_rotator_new ();
 	gth_image_rotator_set_center (GTH_IMAGE_ROTATOR (self->priv->rotator),
 				      cairo_image_surface_get_width (self->priv->image) / 2,
 				      cairo_image_surface_get_height (self->priv->image) / 2);
@@ -503,12 +431,8 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 	gth_image_rotator_set_background (GTH_IMAGE_ROTATOR (self->priv->rotator), &background_color);
 
 	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->rotator);
-	gth_image_viewer_set_zoom_enabled (GTH_IMAGE_VIEWER (viewer), FALSE);
 	gth_viewer_page_update_sensitivity (GTH_VIEWER_PAGE (viewer_page));
 
-	self->priv->selector_align_direction = 0;
-	self->priv->selector_align_point = 0;
-
 	self->priv->crop_enabled = TRUE;
 	self->priv->crop_region.x = 0;
 	self->priv->crop_region.y = 0;
@@ -527,13 +451,9 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 			  "clicked",
 			  G_CALLBACK (reset_button_clicked_cb),
 			  self);
-	g_signal_connect (GET_WIDGET ("align_h_button"),
+	g_signal_connect (GET_WIDGET ("align_button"),
 			  "clicked",
-			  G_CALLBACK (align_h_button_clicked_cb),
-			  self);
-	g_signal_connect (GET_WIDGET ("align_v_button"),
-			  "clicked",
-			  G_CALLBACK (align_v_button_clicked_cb),
+			  G_CALLBACK (align_button_clicked_cb),
 			  self);
 	g_signal_connect (G_OBJECT (self->priv->rotation_angle_adj),
 			  "value-changed",
@@ -563,9 +483,13 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 			  "changed",
 			  G_CALLBACK (crop_grid_changed_cb),
 			  self);
-	g_signal_connect (self->priv->selector_align,
-			  "selected",
-			  G_CALLBACK (selector_selected_cb),
+	g_signal_connect (self->priv->alignment,
+			  "changed",
+			  G_CALLBACK (alignment_changed_cb),
+			  self);
+	g_signal_connect (GET_WIDGET ("alignment_cancel_button"),
+			  "clicked",
+			  G_CALLBACK (alignment_cancel_button_clicked_cb),
 			  self);
 	g_signal_connect (GET_WIDGET ("resize_combobox"),
 			  "changed",
@@ -576,7 +500,7 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
 	update_crop_region (self);
 	update_crop_grid (self);
 
-	return self->priv->options;
+	return GET_WIDGET ("options_notebook");
 }
 
 
@@ -620,10 +544,8 @@ gth_file_tool_rotate_destroy_options (GthFileTool *base)
 	cairo_surface_destroy (self->priv->image);
 	self->priv->image = NULL;
 	_g_clear_object (&self->priv->builder);
-	_g_clear_object (&self->priv->selector_crop);
-	_g_clear_object (&self->priv->selector_align);
-	self->priv->selector_align_direction = 0;
-	self->priv->selector_align_point = 0;
+	_g_clear_object (&self->priv->rotator);
+	_g_clear_object (&self->priv->alignment);
 }
 
 
diff --git a/extensions/file_tools/gth-image-line-tool.c b/extensions/file_tools/gth-image-line-tool.c
new file mode 100644
index 0000000..66442a9
--- /dev/null
+++ b/extensions/file_tools/gth-image-line-tool.c
@@ -0,0 +1,404 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <math.h>
+#include <gthumb.h>
+#include "gth-image-line-tool.h"
+
+
+#define MIN4(a,b,c,d) MIN(MIN((a),(b)),MIN((c),(d)))
+#define MAX4(a,b,c,d) MAX(MAX((a),(b)),MAX((c),(d)))
+
+
+enum {
+	CHANGED,
+	LAST_SIGNAL
+};
+
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static gpointer parent_class = NULL;
+
+
+struct _GthImageLineToolPrivate {
+	GthImageViewer     *viewer;
+
+	/* options */
+
+	GdkPoint            p1;
+	GdkPoint            p2;
+
+	/* utility variables */
+
+	int                 original_width;
+	int                 original_height;
+	double              preview_zoom;
+	cairo_surface_t    *preview_image;
+	GdkRectangle        preview_image_area;
+	GdkPoint            preview_center;
+	GdkRectangle        clip_area;
+	cairo_matrix_t      matrix;
+	gboolean            first_point_set;
+	GthFit              original_fit_mode;
+	gboolean            original_zoom_enabled;
+};
+
+
+static void
+gth_image_line_tool_set_viewer (GthImageViewerTool *base,
+			        GthImageViewer     *viewer)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	self->priv->viewer = viewer;
+	self->priv->original_fit_mode = gth_image_viewer_get_fit_mode (GTH_IMAGE_VIEWER (viewer));
+	self->priv->original_zoom_enabled = gth_image_viewer_get_zoom_enabled (GTH_IMAGE_VIEWER (viewer));
+	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (viewer), GTH_FIT_SIZE_IF_LARGER);
+	gth_image_viewer_set_zoom_enabled (GTH_IMAGE_VIEWER (viewer), FALSE);
+	self->priv->first_point_set = FALSE;
+}
+
+
+static void
+gth_image_line_tool_unset_viewer (GthImageViewerTool *base,
+			          GthImageViewer     *viewer)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (viewer), self->priv->original_fit_mode);
+	gth_image_viewer_set_zoom_enabled (GTH_IMAGE_VIEWER (viewer), self->priv->original_zoom_enabled);
+	self->priv->viewer = NULL;
+	self->priv->first_point_set = FALSE;
+}
+
+
+static void
+gth_image_line_tool_realize (GthImageViewerTool *base)
+{
+	/* void */
+}
+
+
+static void
+gth_image_line_tool_unrealize (GthImageViewerTool *base)
+{
+	/* void */
+}
+
+
+static void
+update_image_surface (GthImageLineTool *self)
+{
+	GtkAllocation    allocation;
+	cairo_surface_t *image;
+	int              max_size;
+	int              width;
+	int              height;
+	cairo_surface_t *preview_image;
+
+	if (self->priv->preview_image != NULL) {
+		cairo_surface_destroy (self->priv->preview_image);
+		self->priv->preview_image = NULL;
+	}
+
+	image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (self->priv->viewer));
+	if (image == NULL)
+		return;
+
+	self->priv->original_width = cairo_image_surface_get_width (image);
+	self->priv->original_height = cairo_image_surface_get_height (image);
+	width = self->priv->original_width;
+	height = self->priv->original_height;
+	gtk_widget_get_allocation (GTK_WIDGET (self->priv->viewer), &allocation);
+	max_size = MAX (allocation.width, allocation.height) / G_SQRT2 + 2;
+	if (scale_keeping_ratio (&width, &height, max_size, max_size, FALSE))
+		preview_image = _cairo_image_surface_scale_to (image, width, height, CAIRO_FILTER_BILINEAR);
+	else
+		preview_image = cairo_surface_reference (image);
+
+	self->priv->preview_zoom = (double) width / self->priv->original_width;
+	self->priv->preview_image = preview_image;
+	self->priv->preview_image_area.width = width;
+	self->priv->preview_image_area.height = height;
+	self->priv->preview_image_area.x = MAX ((allocation.width - self->priv->preview_image_area.width) / 2 - 0.5, 0);
+	self->priv->preview_image_area.y = MAX ((allocation.height - self->priv->preview_image_area.height) / 2 - 0.5, 0);
+}
+
+
+static void
+gth_image_line_tool_size_allocate (GthImageViewerTool *base,
+				   GtkAllocation      *allocation)
+{
+	update_image_surface (GTH_IMAGE_LINE_TOOL (base));
+}
+
+
+static void
+gth_image_line_tool_map (GthImageViewerTool *base)
+{
+	/* void */
+}
+
+
+static void
+gth_image_line_tool_unmap (GthImageViewerTool *base)
+{
+	/* void */
+}
+
+
+static void
+paint_image (GthImageLineTool *self,
+	     cairo_t          *cr)
+{
+	cairo_save (cr);
+
+	cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+	cairo_set_source_surface (cr, self->priv->preview_image,
+				  self->priv->preview_image_area.x,
+				  self->priv->preview_image_area.y);
+	cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
+  	cairo_rectangle (cr,
+  			 self->priv->preview_image_area.x,
+  			 self->priv->preview_image_area.y,
+  			 self->priv->preview_image_area.width,
+  			 self->priv->preview_image_area.height);
+  	cairo_fill (cr);
+
+  	cairo_restore (cr);
+}
+
+
+static void
+gth_image_line_tool_expose (GthImageViewerTool *base,
+			    GdkEventExpose     *event,
+			    cairo_t            *cr)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	if (self->priv->preview_image == NULL)
+		return;
+
+	cairo_save (cr);
+
+  	cairo_rectangle (cr,
+  			 event->area.x,
+  			 event->area.y,
+  			 event->area.width,
+  			 event->area.height);
+  	cairo_clip (cr);
+
+	paint_image (self, cr);
+
+	if (self->priv->first_point_set) {
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 2)
+		cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
+#endif
+		cairo_set_line_width (cr, 5.0);
+		cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
+		cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+		cairo_translate (cr, self->priv->preview_image_area.x, self->priv->preview_image_area.y);
+		cairo_scale (cr, self->priv->preview_zoom, self->priv->preview_zoom);
+		cairo_move_to (cr, self->priv->p1.x, self->priv->p1.y);
+		cairo_line_to (cr, self->priv->p2.x, self->priv->p2.y);
+		cairo_stroke (cr);
+	}
+
+	cairo_restore (cr);
+}
+
+
+static gboolean
+gth_image_line_tool_button_release (GthImageViewerTool *base,
+				    GdkEventButton     *event)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	g_signal_emit (self, signals[CHANGED], 0);
+	return FALSE;
+}
+
+
+static gboolean
+gth_image_line_tool_button_press (GthImageViewerTool *base,
+				  GdkEventButton     *event)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	if (event->type == GDK_BUTTON_PRESS) {
+		self->priv->p1.x = self->priv->p2.x = (event->x - self->priv->preview_image_area.x) / self->priv->preview_zoom;
+		self->priv->p1.y = self->priv->p2.y = (event->y - self->priv->preview_image_area.y) / self->priv->preview_zoom;
+		self->priv->first_point_set = TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static gboolean
+gth_image_line_tool_motion_notify (GthImageViewerTool *base,
+				   GdkEventMotion     *event)
+{
+	GthImageLineTool *self = GTH_IMAGE_LINE_TOOL (base);
+
+	if (! self->priv->first_point_set)
+		return FALSE;
+
+	self->priv->p2.x = (event->x - self->priv->preview_image_area.x) / self->priv->preview_zoom;
+	self->priv->p2.y = (event->y - self->priv->preview_image_area.y) / self->priv->preview_zoom;
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->viewer));
+
+	return FALSE;
+}
+
+
+static void
+gth_image_line_tool_image_changed (GthImageViewerTool *base)
+{
+	update_image_surface (GTH_IMAGE_LINE_TOOL (base));
+}
+
+
+static void
+gth_image_line_tool_zoom_changed (GthImageViewerTool *base)
+{
+	update_image_surface (GTH_IMAGE_LINE_TOOL (base));
+}
+
+
+static void
+gth_image_line_tool_instance_init (GthImageLineTool *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_IMAGE_LINE_TOOL, GthImageLineToolPrivate);
+	self->priv->preview_image = NULL;
+	self->priv->first_point_set = FALSE;
+}
+
+
+static void
+gth_image_line_tool_finalize (GObject *object)
+{
+	GthImageLineTool *self;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GTH_IS_IMAGE_LINE_TOOL (object));
+
+	self = (GthImageLineTool *) object;
+	if (self->priv->preview_image != NULL)
+		cairo_surface_destroy (self->priv->preview_image);
+
+	/* Chain up */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_image_line_tool_class_init (GthImageLineToolClass *class)
+{
+	GObjectClass *gobject_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GthImageLineToolPrivate));
+
+	gobject_class = (GObjectClass*) class;
+	gobject_class->finalize = gth_image_line_tool_finalize;
+
+	signals[CHANGED] = g_signal_new ("changed",
+					 G_TYPE_FROM_CLASS (class),
+					 G_SIGNAL_RUN_LAST,
+					 G_STRUCT_OFFSET (GthImageLineToolClass, changed),
+					 NULL, NULL,
+					 g_cclosure_marshal_VOID__VOID,
+					 G_TYPE_NONE,
+					 0);
+}
+
+
+static void
+gth_image_line_tool_gth_image_tool_interface_init (GthImageViewerToolIface *iface)
+{
+	iface->set_viewer = gth_image_line_tool_set_viewer;
+	iface->unset_viewer = gth_image_line_tool_unset_viewer;
+	iface->realize = gth_image_line_tool_realize;
+	iface->unrealize = gth_image_line_tool_unrealize;
+	iface->size_allocate = gth_image_line_tool_size_allocate;
+	iface->map = gth_image_line_tool_map;
+	iface->unmap = gth_image_line_tool_unmap;
+	iface->expose = gth_image_line_tool_expose;
+	iface->button_press = gth_image_line_tool_button_press;
+	iface->button_release = gth_image_line_tool_button_release;
+	iface->motion_notify = gth_image_line_tool_motion_notify;
+	iface->image_changed = gth_image_line_tool_image_changed;
+	iface->zoom_changed = gth_image_line_tool_zoom_changed;
+}
+
+
+GType
+gth_image_line_tool_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthImageLineToolClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_image_line_tool_class_init,
+			NULL,
+			NULL,
+			sizeof (GthImageLineTool),
+			0,
+			(GInstanceInitFunc) gth_image_line_tool_instance_init
+		};
+		static const GInterfaceInfo gth_image_tool_info = {
+			(GInterfaceInitFunc) gth_image_line_tool_gth_image_tool_interface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL
+		};
+
+		type = g_type_register_static (G_TYPE_OBJECT,
+					       "GthImageLineTool",
+					       &type_info,
+					       0);
+		g_type_add_interface_static (type, GTH_TYPE_IMAGE_VIEWER_TOOL, &gth_image_tool_info);
+	}
+
+	return type;
+}
+
+
+GthImageViewerTool *
+gth_image_line_tool_new (void)
+{
+	return (GthImageViewerTool *) g_object_new (GTH_TYPE_IMAGE_LINE_TOOL, NULL);
+}
+
+
+void
+gth_image_line_tool_get_points (GthImageLineTool *self,
+		       	        GdkPoint         *p1,
+		       	        GdkPoint         *p2)
+{
+	*p1 = self->priv->p1;
+	*p2 = self->priv->p2;
+}
diff --git a/extensions/file_tools/gth-image-line-tool.h b/extensions/file_tools/gth-image-line-tool.h
new file mode 100644
index 0000000..4860ce8
--- /dev/null
+++ b/extensions/file_tools/gth-image-line-tool.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_IMAGE_LINE_TOOL_H
+#define GTH_IMAGE_LINE_TOOL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_IMAGE_LINE_TOOL            (gth_image_line_tool_get_type ())
+#define GTH_IMAGE_LINE_TOOL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE_LINE_TOOL, GthImageLineTool))
+#define GTH_IMAGE_LINE_TOOL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_IMAGE_LINE_TOOL, GthImageLineToolClass))
+#define GTH_IS_IMAGE_LINE_TOOL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_IMAGE_LINE_TOOL))
+#define GTH_IS_IMAGE_LINE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_IMAGE_LINE_TOOL))
+#define GTH_IMAGE_LINE_TOOL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_IMAGE_LINE_TOOL, GthImageLineToolClass))
+
+typedef struct _GthImageLineTool         GthImageLineTool;
+typedef struct _GthImageLineToolClass    GthImageLineToolClass;
+typedef struct _GthImageLineToolPrivate  GthImageLineToolPrivate;
+
+struct _GthImageLineTool
+{
+	GObject __parent;
+	GthImageLineToolPrivate *priv;
+};
+
+struct _GthImageLineToolClass
+{
+	GObjectClass __parent_class;
+
+	/*< signals >*/
+
+	void (* changed) (GthImageLineTool *rotator);
+};
+
+GType                 gth_image_line_tool_get_type    (void);
+GthImageViewerTool *  gth_image_line_tool_new         (void);
+void                  gth_image_line_tool_get_points  (GthImageLineTool  *self,
+						       GdkPoint          *p1,
+						       GdkPoint          *p2);
+
+G_END_DECLS
+
+#endif /* GTH_IMAGE_LINE_TOOL_H */



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