[oliver@first.in-berlin.de: Re: small Wishlist regarding Guides]
This discussion is connected to the gimp-developer-list.gnome.org mailing list which is provided by the GIMP developers and not related to gimpusers.com.
This is a read-only list on gimpusers.com so this discussion thread is read-only, too.
[oliver@first.in-berlin.de: Re: small Wishlist regarding Guides] | oliver@first.in-berlin.de | 01 Aug 23:44 |
[oliver@first.in-berlin.de: Re: small Wishlist regarding Guides]
hello,
this should have been sent to the list...
so my answer forwarded to here.
----- Forwarded message from oliver@first.in-berlin.de -----
Date: Sun, 1 Aug 2010 23:40:45 +0200
From: oliver@first.in-berlin.de
To: LightningIsMyName
Subject: Re: [Gimp-developer] small Wishlist regarding Guides
User-Agent: Mutt/1.5.20 (2009-06-14)
Hi,
On Sun, Aug 01, 2010 at 06:42:00PM +0300, LightningIsMyName wrote:
Hello
- non-rectangle-bound guides:
Guides that can be enabled to have any angle, which means that they do
[...]
I think we have seen this request already several times and I definitely agree it could be useful. Your request made me take a look at the code (app/display/gimpdisplayshell-draw.c, app/core/gimpimage-guides.c, /app/core/gimpguide.c) and it actually seems possible. I'll add it to my to-try list for when I have some more time.
Fine :)
[...]
- boundary guides, instead of middle.guides: Guides, where the outer boundary of a drawing tool snaps to the guide (instead the middle of the drawing tool snapping to the guide).
This would be helpful for drawing in general, and correcting pictures: the color will not pass this line of the guide, which means, you can be sure no color enters a certain region.
This does not seem trivial to code - in fact with how I remember the paint core works, this is going to be one very hard hack... Also, I think that if the purpose is just to stay inside of the lines you can use a selection (create it using the guides and freeform
[...]
The selection does not has the magnetic behaviour as a guide has.
Maybe even a freely definable guide would help here, or a magnetic selection, or something like this.... ?!
[...]
- Adding Multiple Guides
(there is a Script for this on www.meetthegimp.org, but native would be nice)This feature is good for some repetitive tasks, where a lot of Guides will be needed, something like a guide-grid.
Can you give a direct link to the script?
I didn't found the link by myself, but I have the script local on my machine and can attach it. It's not writen by me. But I may look for the original link later (or ask the admin).
I definitely agree this
sounds useful - it's worth checking if we can simply include this script with GIMP
The GUI/behaviour could be enhanced, and could be more Gimp-like. But it's already useful and has saved me a lot of time in some tasks.
(or at least if you give us a link to it, we'll be able to write something similar with extra features if needed).
I will attach it here.
I hope attachements are not blocked here.
Ciao, Oliver
import os
from gimpfu import *
import os.path
import pygtk
import gtk
gettext.install("gimp20-python", gimp.locale_directory, unicode=True)
def debugMessage(Message):
dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, Message)
dialog.run()
dialog.hide()
def findMaxDimensionOfImage(Image, Direction):
if (Direction == 0):
limit_value = pdb.gimp_image_height(Image) -1
else:
limit_value = pdb.gimp_image_width(Image) -1
return limit_value
# This defines the class class addMultipleGuidesDialog:
# Things to do with the image reference
imageRef = 0
def set_imageRef(self,Image):
self.imageRef = Image
def get_imageRef(self):
return self.imageRef
# Things to do with the guides we create
thisGuide = 0
def set_thisGuide(self, guideRef):
self.thisGuide = guideRef
def get_thisGuide(self):
return self.thisGuide
# RadioGroup
radio_group = []
def set_radioGroup(self, radioGroup):
self.radio_group = radioGroup
def get_radioGroup(self):
return self.radio_group
# Adjustment
the_adjustment = 0
def set_adjustment(self, newAdjustment):
self.the_adjustment = newAdjustment;
def get_adjustment(self):
return self.the_adjustment
# Labels (possible to change later for translation purposes)
Labels = ["Horizontal", "Vertical", "Add", "Close", "Remove Last"]
# Labels = ["H", "V", "A", "C"]
def get_Labels(self, labelIndex):
return self.Labels[labelIndex]
# This is a callback function. The data arguments are ignored
# in this example. More on callbacks below.
def hello(self, widget, data=None):
print "Finished"
def findActiveRadioButton(self):
active = [r for r in self.get_radioGroup() if r.get_active()][0]
return active.get_label()
# call back for the Add button
def add_guide(self, widget, Data):
activeLabel = self.findActiveRadioButton()
position = Data.get_value()
if (activeLabel == self.get_Labels(0)):
currentGuide = pdb.gimp_image_add_hguide(self.get_imageRef(), position)
else:
currentGuide = pdb.gimp_image_add_vguide(self.get_imageRef(), position)
self.set_thisGuide(currentGuide)
def remove_last_guide(self, widget, Data):
thisGuide = self.get_thisGuide()
if (thisGuide != 0):
pdb.gimp_image_delete_guide(self.get_imageRef(), thisGuide)
# Limit the upper value for the spin button
def limit_spin(self, widget, Data):
# find out which radio button is selected
activeLabel = self.findActiveRadioButton()
if (activeLabel == self.get_Labels(0)): # horizontal selected
limit_value = findMaxDimensionOfImage(self.get_imageRef(), 0)
else: # vertical selected
limit_value = findMaxDimensionOfImage(self.get_imageRef(), 1)
# get the current value of the spinbutton
adjustment = self.get_adjustment()
current_value = adjustment.get_value()
# if the current value is greater than the new limit, force the value to be the new limit
if (current_value > limit_value): current_value = limit_value
adjustment.set_all(current_value, 0, limit_value, 1, 10, 0) # set the new value and upper limit
def delete_event(self, widget, event, data=None):
# If you return FALSE in the "delete_event" signal handler,
# GTK will emit the "destroy" signal. Returning TRUE means
# you don't want the window to be destroyed.
# This is useful for popping up 'are you sure you want to quit?'
# type dialogs.
print "delete event occurred"
# Change FALSE to TRUE and the main window will not be destroyed
# with a "delete_event".
return False
# Another callback
def destroy(self, widget, data=None):
Image = self.get_imageRef()
Image.undo_group_end()
gtk.main_quit()
# things to do after the instance has been created but before doing any work
def setup(self, widget, Data):
Image = Data[0]
self.set_imageRef(Image) # set the image reference
self.limit_spin(None,None) # set the max value allowed for position based on image size
Image.undo_group_start()
def __init__(self):
# create a new window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Add Multiple Guides")
# When the window is given the "delete_event" signal (this is given
# by the window manager, usually by the "close" option, or on the
# titlebar), we ask it to call the delete_event () function
# as defined above. The data passed to the callback
# function is NULL and is ignored in the callback function.
self.window.connect("delete_event", self.delete_event)
# Here we connect the "destroy" event to a signal handler. # This event occurs when we call gtk_widget_destroy() on the window, # or if we return FALSE in the "delete_event" callback. self.window.connect("destroy", self.destroy)
# Sets the border width of the window. self.window.set_border_width(10)
# We create a box to pack widgets into. This is described in detail
# in the "packing" section. The box is not really visible, it
# is just used as a tool to arrange widgets.
self.window_box = gtk.VBox(False, 0)
self.window.add(self.window_box)
self.box1 = gtk.HBox(False, 0)
self.box2 = gtk.HBox(False, 0)
self.box3 = gtk.HBox(False, 0)
self.window_box.pack_start(self.box1, True, True, 10)
self.window_box.pack_start(self.box3, True, True, 10)
self.window_box.pack_start(self.box2, True, True, 10)
# Creates a new button with the label "Close". self.button1 = gtk.Button(self.get_Labels(3))
# When the button receives the "clicked" signal, it will call the # function hello() passing it None as its argument. The hello() # function is defined above. self.button1.connect("clicked", self.hello, None)
# This will cause the window to be destroyed by calling # gtk_widget_destroy(window) when "clicked". Again, the destroy # signal could come from here, or the window manager. self.button1.connect_object("clicked", gtk.Widget.destroy, self.window)
# This packs the button into the window (a GTK container). self.box2.pack_start(self.button1, True, True, 10)
# The final step is to display this newly created widget.
self.button1.show()
# Create the first radio button widget
self.radio1 = gtk.RadioButton(None, self.get_Labels(0), False)
# Create the second radio button, passing a ref to the first to define the group
self.radio2 = gtk.RadioButton(self.radio1, self.get_Labels(1), False)
# pack them into a box
self.box1.pack_start(self.radio1, True, True, 5)
self.box1.pack_start(self.radio2, True, True, 5)
# and make them visible
self.radio1.show()
self.radio2.show()
self.set_radioGroup(self.radio1.get_group())
# create an adjustment for the spin widget
# At the moment the upper value is set the same as the standard new guide dialog
# value lower upper step_incr, page_incr, page_size
limit_value = 1000
# limit_value = findMaxValue(self.get_imageRef(), 0)
self.adjustment = gtk.Adjustment(0, 0, limit_value, 1, 10, 0)
self.set_adjustment(gtk.Adjustment(0, 0, limit_value, 1, 10, 0))
# create a spin widget to alow user to set the position required
self.spin_button = gtk.SpinButton(self.get_adjustment(), climb_rate=0.0, digits=0)
# pack the spinbutton into the box
self.box1.pack_start(self.spin_button, True, True, 5)
self.spin_button.show()
# Create a button to add the guide when pressed
self.button2 = gtk.Button(self.get_Labels(2))
self.button2.connect("clicked", self.add_guide, self.spin_button)
self.box1.pack_start(self.button2, True, True, 10)
self.button2.show()
# create a button to remove the last guide
self.button3 = gtk.Button(self.get_Labels(4))
self.button3.connect("clicked", self.remove_last_guide, None)
self.box3.pack_end(self.button3, False, False, 10)
self.button3.show()
# connect the radio buttons to a call back self.radio1.connect("released", self.limit_spin, self.adjustment) self.radio2.connect("released", self.limit_spin, self.adjustment)
# Show everything
self.box1.show()
self.box2.show()
self.box3.show()
self.window_box.show()
self.window.show()
def main(self): # All PyGTK applications must have a gtk.main(). Control ends here # and waits for an event to occur (like a key press or mouse event). gtk.main()
# The important stuff starts here def pygtk_addMultipleGuides(img, drw): hello = addMultipleGuidesDialog() # create an instance of the dialog hello.setup(None,[img,drw]) # initialise some important things hello.main() # start the gui
register(
"python-fu-pygtk_addMultipleGuides",
"Add Multiple Guides",
"(Version 0.1)",
"Meetthegimp-Community http://forum.meetthegimp.org",
"GPL License",
"2009",
"/contributed/Add Multiple Guides",
"*",
[],
[],
pygtk_addMultipleGuides)
main()
----- End forwarded message -----