It is currently Wed Jul 24, 2024 12:22 pm


All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 51 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 11:21 am  (#21) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
Well, as we haven't had any other replies on this issue, I am sticking with the tracing one.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 3:41 pm  (#22) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
There are some improvements in the latest version, like an optimized UI.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 3:58 pm  (#23) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
Thats nice to know, It still doesn't work.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:04 pm  (#24) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
molly wrote:
Thats nice to know, It still doesn't work.


Do you get something in the log?

Edit: If you are on Linux/OSX, there is no log file, the messages show up in a terminal window from which you start Gimp.

_________________
Image


Last edited by ofnuts on Sat Feb 08, 2014 5:18 pm, edited 1 time in total.

Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:11 pm  (#25) 
Offline
Script Coder
User avatar

Joined: Feb 18, 2011
Posts: 4827
Location: Bendigo Vic. Australia
ofnuts I'm staying with your original release as it's not broken, so why fix it

_________________
Image
No matter how much you push the envelope, it'll still be stationery.


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:16 pm  (#26) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
Graechan, are you using the addonCollectionManager-tracing?

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:30 pm  (#27) 
Offline
Script Coder
User avatar

Joined: Feb 18, 2011
Posts: 4827
Location: Bendigo Vic. Australia
No Molly I'm using the very original file posted by ofnuts

_________________
Image
No matter how much you push the envelope, it'll still be stationery.


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:43 pm  (#28) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
o, you mean the MrQ one?

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 5:49 pm  (#29) 
Offline
Script Coder
User avatar

Joined: Feb 18, 2011
Posts: 4827
Location: Bendigo Vic. Australia
No I mean the original 'addonCollectionManager.py' posted by offnuts

#!/usr/bin/env python
#-*- coding: utf-8 -*-

authors='Sean Bogie, MareroQ, Ofnuts'

import pygtk,gtk,os,glob,shutil,ConfigParser,codecs,copy,zipfile,time
pygtk.require('2.0')
from gimpfu import *

def trace(s):
#   print s
   pass

def brushes_callback():
   call_back('brushes')
   
def dynamics_callback():
   call_back('dynamics')
   
def fonts_callback():   
   call_back('fonts')
   
def gradients_callback():   
   call_back('gradients')
   
def palettes_callback():
   call_back('palettes')
   
def patterns_callback():
   call_back('patterns')
   
def scripts_callback():
   call_back('scripts')
   
def call_back(addonType):
   trace('Called in %s callback' % addonType)
   configuration=Configuration(builtinSections)
   configuration.loadConfiguration()
   manager=AddonCollectionManager(configuration,commonConfigVars,addonType)
   manager.showMainDialog()
   manager.main()

builtinSections={
      'all': {
         #'enable':'brushes scripts',
         'enable':'brushes dynamics fonts gradients palettes patterns scripts',
         'addons_active':'{GimpUser}/{type}',
         'addons_stored':'{GimpUser}/{type}_storage',
         'menu_location':'<{Type}>',
         'menu_entry':'{Type} sets...',
         'menu_description':'Manage {type} sets...',
         'dialog_title':'{Type} sets manager'
         },
      'brushes':{
         'extensions':'.gbr .vbr .gih .abr .GBR .VBR .GIH'
         },
      'dynamics':{
         'extensions':'.gdyn .GDYN'
         },
      'fonts':{
         'extensions':'.ttf .otf .TTF .OTF'
         },
      'gradients':{
         'extensions':'.ggr .GGR'
         },
      'palettes':{
         'extensions':'.pal .PAL'
         },
      'patterns':{
         'extensions':'.png .pat .PNG .PAT'
         },
      'scripts':{
         'menu_location':'<Image>/Help',
         'extensions':'.scm .SCM',
         },
   }
   
# gradients, dynamics, scripts, palettes   
   
# Technical data specific to each type
initData={
      'brushes':{
         'gimpRefresh':'gimp_brushes_refresh',
         'gimpProcedure':'addon-manager-brushes',
         'gimpCallback':brushes_callback
         },
      'dynamics':{
         'gimpRefresh':'gimp_dynamics_refresh',
         'gimpProcedure':'addon-manager-dynamics',
         'gimpCallback':dynamics_callback
         },
      'fonts':{
         'gimpRefresh':'gimp_fonts_refresh',
         'gimpProcedure':'addon-manager-fonts',
         'gimpCallback':fonts_callback
         },
      'gradients':{
         'gimpRefresh':'gimp_gradients_refresh',
         'gimpProcedure':'addon-manager-gradients',
         'gimpCallback':gradients_callback
         },
      'palettes':{
         'gimpRefresh':'gimp_palettes_refresh',
         'gimpProcedure':'addon-manager-palettes',
         'gimpCallback':palettes_callback
         },
      'patterns':{
         'gimpRefresh':'gimp_patterns_refresh',
         'gimpProcedure':'addon-manager-patterns',
         'gimpCallback':patterns_callback
         },
      'scripts':{
         'gimpRefresh':'script-fu-refresh',
         'gimpProcedure':'addon-manager-scripts',
         'gimpCallback':scripts_callback
         }
   }
   

commonConfigVars={
      '{UserHome}':os.path.expanduser('~/')[:-1],
      '{GimpUser}':gimp.directory,
      '{GimpData}':gimp.data_directory,
      '{GimpPlugin}':gimp.plug_in_directory
   }

class Configuration(object):
   '''Class handling all the configuration data'''
   def __init__(self,defaults):
      self.configData=ConfigParser.ConfigParser()
      for section in defaults:
         self.configData.add_section(section)
         options=defaults[section]
         for option in options:
            self.configData.set(section,option,options[option])
      trace('Configuration initialized OK')
   
   def loadConfiguration(self):
      pluginDir=os.path.join(gimp.directory,'plug-ins')
      configFilePath=os.path.join(pluginDir,'addonCollectionManager.ini')
      trace('Reading configuration file %s' % configFilePath)
      try:
         with codecs.open(configFilePath, 'r', encoding='utf-8') as configFile:
            self.configData.readfp(configFile)
         trace('Configuration file %s read successfully' % configFilePath)
      except Exception as e:
         trace('Configuration file %s not found or not readable: %s' % (configFilePath,e))

   def getValue(self,section,option,configVars):
      value=self.configData.get(section,option)
      if configVars:
         for v in configVars:
            value=value.replace(v,configVars[v])
      return value
   
   def getAddonTypeSection(self,addonType,configVars):
      addonTypeData={}
      for option in self.configData.options('all'):
         addonTypeData[option]=self.getValue('all',option,configVars)
      for option in self.configData.options(addonType):
         addonTypeData[option]=self.getValue(addonType,option,configVars)
      return addonTypeData
   
# Classes to handle the places where we keep the addOns
class AddonContainer(object):
   '''Parent of classes that handle the places where we keep the addons '''
   def __init__(self,containerPath,activeDir,extensions):
      self.containerPath=containerPath
      self.containerName=os.path.basename(containerPath)
      self.activeDir=activeDir
      self.extensions=extensions
      
   def storedAddons(self):
      '''returns the list of names of stored addons.
      This method is implemented by the derived classes'''
      pass
      
   def addonName(self,fullname):
      '''Returns just the file name of any addons.
      This method is implemented by the derived classes'''
      pass

   def activeAddonPath(self,storedAddonName):
      '''computes the activaed addon name'''
      return self.activeDir+'/'+self.containerName+'-'+self.addonName(storedAddonName)
      
   def deactivate(self,storedAddon):
      '''Removes the addon from active storage'''
      filePath=self.activeAddonPath(storedAddon)
      try:
         os.remove(filePath)
      except:
         trace('Cannot de-activate %s' % filePath)
   
   def activate(self,storedAddon):
      '''Implemented by derived classes'''
      pass
   
class AddonDirectory(AddonContainer):
   '''Class to handle directory with addons'''
   def __init__(self,containerPath,activeDir,extensions):
      super(AddonDirectory, self).__init__(containerPath,activeDir,extensions)
      
   def storedAddons(self):
      storedAddons=[f for f in glob.glob(self.containerPath+u'/*') if f.endswith(self.extensions)]
      trace('%d addons stored in %s' % (len(storedAddons),self.containerPath))
      return storedAddons
      
   def addonName(self,fullname):
      return fullname.split('/')[-1]
   
   def activate(self,storedAddon):
      activeAddonPath=self.activeAddonPath(storedAddon)
      trace('Activating %s as %s' % (storedAddon,activeAddonPath))
      if 'symlink' in dir(os):
         os.symlink(storedAddon,activeAddonPath)
      else:
         shutil.copyfile(storedAddon,activeAddonPath)

class AddonZip(AddonContainer):
   '''Class to handle zip with addons'''
   def __init__(self,containerPath,activeDir,extensions):
      super(AddonZip, self).__init__(containerPath,activeDir,extensions)
      self.zipFile=zipfile.ZipFile(containerPath)
      
   def storedAddons(self):
      storedAddons=[f for f in self.zipFile.namelist() if f.endswith(self.extensions)]
      trace('%d addons stored in %s' % (len(storedAddons),self.containerPath))
      return storedAddons

      
   def addonName(self,fullname):
      return fullname.split('/')[-1]

   def activate(self,storedAddon):
      activeAddonPath=self.activeAddonPath(storedAddon)
      trace('Activating %s as %s' % (storedAddon,activeAddonPath))
      try:
         activeAddon=open(activeAddonPath,"wb")
         activeAddon.write(self.zipFile.read(storedAddon))
      except Exception as e:
         trace('Error activating %s from %s/%s: %s' % (activeAddonPath,self.containerName,storedAddon,e))
      finally:
         activeAddon.close()

class AddonCollectionManager(object):
   
   def __init__(self,config,commonConfigVars,addonType):
      self.addonType=addonType
      self.configVars=self.extendConfigVars(commonConfigVars)
      self.config=config.getAddonTypeSection(addonType,self.configVars)
      self.data=initData[addonType]
      self.addonsActive=self.config['addons_active']
      self.addonsStored=self.config['addons_stored']
      self.extensions=tuple(self.config['extensions'].split())
      self.activelist=os.path.join(self.addonsStored,'.active')
      self.containers = self.getContainers()
      self.activeContainersNames=self.getActiveContainersNames()
      self.statusDialog=None
      trace('Manager of %s created OK' % addonType)

   def extendConfigVars(self,commonConfigVars):
      configVars=copy.copy(commonConfigVars)
      configVars['{type}']=self.addonType
      configVars['{Type}']=self.addonType.capitalize()
      return configVars
      
   def getContainers(self):
      containers={}
      trace('Searching directories as %s for %s' % (self.addonsStored+u'/*',self.addonType))
      dirs=[d for d in glob.glob(self.addonsStored+u'/*') if os.path.isdir(d)]
      trace('%d directories as %s for %s' % (len(dirs),self.addonsStored+u'/*',self.addonType))
      for d in dirs:
         containers[os.path.basename(d)]=AddonDirectory(d,self.addonsActive,self.extensions)
      zips=[z for z in glob.glob(self.addonsStored+u'/*.zip') if os.path.isfile(z) and zipfile.is_zipfile(z)]
      for z in zips:
         containers[os.path.basename(z)]=AddonZip(z,self.addonsActive,self.extensions)
      return containers
      
   def getActiveContainersNames(self):
      activeContainersNames=[]
      try:
         with codecs.open(self.activelist,'r',encoding='utf-8') as f:
            activeContainersNames=f.read().splitlines()
      except IOError:
         pass;
      return activeContainersNames
   
   def saveActiveContainersNames(self,activeContainersNames):
      try:
         with codecs.open(self.activelist,'w',encoding='utf-8') as f:
            f.write('\n'.join(activeContainersNames))
      except Exception as e:
         trace('Cannot write back active containers list to %s: %s' % (activelist,e))

   def deleteStatusDialog(self,widget,event,data=None):
      return True

   def showStatusDialog(self):
      if not self.statusDialog:
         self.statusDialog = gtk.Dialog("Please Wait...", self.mainDialog,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
         self.statusDialog.connect("delete_event", self.deleteStatusDialog)
         self.statusDialog.set_size_request(200, 100)
         
         self.statuslabel = gtk.Label("Status:")
         self.statusDialog.vbox.pack_start(self.statuslabel, False, False, 0)
         
         self.progressbar = gtk.ProgressBar()
         self.statusDialog.vbox.pack_start(self.progressbar, False, True, 0)

      self.statuslabel.show()
      self.progressbar.show()
      self.statusDialog.show()

   def hideStatusDialog(self):
      self.statuslabel.hide()
      self.progressbar.hide()
      self.statusDialog.hide()

   def doUpdateActiveAddons(self,deactivatedContainersNames,activatedContainersNames):
      totalUpdates=0

      deactivatedContainersLists={}
      for containerName in deactivatedContainersNames:
         addons=self.containers[containerName].storedAddons()
         totalUpdates=totalUpdates+len(addons)
         deactivatedContainersLists[containerName]=addons
         
      activatedContainersLists={}
      for containerName in activatedContainersNames:
         addons=self.containers[containerName].storedAddons()
         totalUpdates=totalUpdates+len(addons)
         activatedContainersLists[containerName]=addons
         
      self.showStatusDialog()
      
      currentUpdates = 0
      self.progressbar.set_fraction(0.)

      self.statuslabel.set_text("Deactivating removed addons...")
      for containerName in deactivatedContainersLists:
         container=self.containers[containerName]
         addons=deactivatedContainersLists[containerName]
         for addon in addons:
            container.deactivate(addon)
            currentUpdates=currentUpdates+1
            self.progressbar.set_fraction(float(currentUpdates)/totalUpdates)
            gtk.main_iteration()
            
      self.statuslabel.set_text("Activating added addons...")
      for containerName in activatedContainersLists:
         container=self.containers[containerName]
         addons=activatedContainersLists[containerName]
         for addon in addons:
            container.activate(addon)
            currentUpdates=currentUpdates+1
            self.progressbar.set_fraction(float(currentUpdates)/totalUpdates)
            gtk.main_iteration()
            
      self.statuslabel.set_text("Refreshing list...")
      gtk.main_iteration()
      try:
         trace('Refresh: %s' % self.data['gimpRefresh'])
         pdb[self.data['gimpRefresh']]()
         trace('Refresh OK')
      except:
         pass
      self.hideStatusDialog()


   def clickedOK(self, widget, data=None):
      trace('OK sensed')
      oldActiveContainersNames = set(self.getActiveContainersNames())
      newActiveContainersNames = set([unicode(button.get_label()) for button in self.checkButtons if button.get_active()])
      
      activatedContainersNames=newActiveContainersNames-oldActiveContainersNames
      deactivatedContainersNames=oldActiveContainersNames-newActiveContainersNames
      
      trace('Old containers; %s' % oldActiveContainersNames)
      trace('New containers; %s' % newActiveContainersNames)
      trace('Activated containers; %s' % activatedContainersNames)
      trace('Deactivated containers; %s' % deactivatedContainersNames)
      
      self.doUpdateActiveAddons(deactivatedContainersNames,activatedContainersNames)

      self.saveActiveContainersNames(newActiveContainersNames)


   def destroyMainDialog(self, widget, data=None):
      trace('Destroying main')
      gtk.main_quit()

   def showMainDialog(self):
      trace('Creating main dialog')
      self.mainDialog=gtk.Dialog()
      self.mainDialog.connect("destroy", self.destroyMainDialog)
      self.mainDialog.set_title(self.config['dialog_title'])
      self.mainDialog.set_border_width(10)
      self.mainDialog.set_size_request(200, 400)
      trace('Main dialog created')
   
      scrollBox = gtk.ScrolledWindow()
      scrollBox.set_border_width(10)
      scrollBox.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
      self.mainDialog.vbox.pack_start(scrollBox, True, True, 0)
      scrollBox.show()
      trace('Scrollbox created')

      vbox = gtk.VBox()
      self.checkButtons=[]
      for containerName in sorted(self.containers.keys()):
         button=gtk.CheckButton(containerName)
         button.set_active(containerName in self.activeContainersNames)
         self.checkButtons.append(button)
         vbox.pack_start(button, False, False, 1)
         button.show()
      scrollBox.add_with_viewport(vbox)
      vbox.show()
      trace('VBox created')

      cancelButton = gtk.Button(stock=gtk.STOCK_CLOSE)
      cancelButton.connect_object("clicked", gtk.Widget.destroy, self.mainDialog)
      self.mainDialog.action_area.pack_start(cancelButton, True, True, 0)
      cancelButton.show()
      trace('Cancel button created')

      okButton = gtk.Button(stock=gtk.STOCK_OK)
      okButton.connect("clicked", self.clickedOK)
      self.mainDialog.action_area.pack_start(okButton, True, True, 0)
      okButton.show()
      trace('OK button created')

      self.mainDialog.show()
      gtk.main_iteration()

   def main(self):
      gtk.main()
       
   def register(self):
           register(
         self.data['gimpProcedure'],
         self.config['menu_description'],
         'Add-on manager. This code takes no arguments, but isn\'t meant to be called programmatically.',
         authors,authors,'2013',
         self.config['menu_entry'],
         '',[],[],
         self.data['gimpCallback'],
         menu=self.config['menu_location']
      )


### Initialization
configuration=Configuration(builtinSections)
configuration.loadConfiguration()

# Initialize the managers listed in the ini file
enabled=configuration.getValue('all','enable',None).split()
for addonType in initData:
   if addonType in enabled:
      trace('Creating manager for %s' % addonType)
      manager=AddonCollectionManager(configuration,commonConfigVars,addonType)
      manager.register()
      
main()

_________________
Image
No matter how much you push the envelope, it'll still be stationery.


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 6:15 pm  (#30) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
I guess I missed that one, the one I am using runs perfect and didn't have to edit anything, or any ini file , just the plugin

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 7:10 pm  (#31) 
Offline
Script Coder
User avatar

Joined: Feb 18, 2011
Posts: 4827
Location: Bendigo Vic. Australia
With the version I have ofnuts made it very clear "Do not edit the Python file" so I did all my setup in the .ini file and it worked a breeze with all the gimps I have installed.

_________________
Image
No matter how much you push the envelope, it'll still be stationery.


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 7:14 pm  (#32) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
molly wrote:
I guess I missed that one, the one I am using runs perfect and didn't have to edit anything, or any ini file , just the plugin


The latest will also run with the same defaults if there is no .ini.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 7:19 pm  (#33) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
@ofnuts
addonCollectionManager-3.py does not work. it loads the brushes but doesn't unload them as per one of the earlier posts including screen shots.

AddonCollectionManager-tracing.py works flawlessly as I mentioned from the beginning of this thread.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 8:08 pm  (#34) 
Offline
Script Coder
User avatar

Joined: Feb 18, 2011
Posts: 4827
Location: Bendigo Vic. Australia
ofnuts will the latest run with my current .ini file and would there be any benefits for me, I use the same py and ini file for several Gimps and set my resources to load to a separate folder which I then point their preferences to

_________________
Image
No matter how much you push the envelope, it'll still be stationery.


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 8:25 pm  (#35) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
Graechan wrote:
ofnuts will the latest run with my current .ini file and would there be any benefits for me, I use the same py and ini file for several Gimps and set my resources to load to a separate folder which I then point their preferences to


Normally yes.

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 8:26 pm  (#36) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
molly wrote:
@ofnuts
addonCollectionManager-3.py does not work. it loads the brushes but doesn't unload them as per one of the earlier posts including screen shots.
In this thread? Can't find it...

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 8:53 pm  (#37) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
Start at post number 16 and work your way down,

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sat Feb 08, 2014 9:37 pm  (#38) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
molly wrote:
Start at post number 16 and work your way down,


Missed your edit... On Linux I assume? Using default settings? Using ZIPs or just directories? What messages do you get in the console?

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sun Feb 09, 2014 4:38 am  (#39) 
Offline
Global Moderator
User avatar

Joined: Apr 07, 2010
Posts: 14182
I don't get any errors at all, The blue bar just stops and doesn't deactivate the brushes that were already loaded. When I go back into it, those particular brushes are still clicked. Anyway the tracing plugin [addonCollectlionManager-tracing.py] works perfectly so I will stick to it.

This is the one that doesn't work, addonCollectionManager-3.0.py

_________________
Image


Top
 Post subject: Re: Installing the MrQ add-on Manager
PostPosted: Sun Feb 09, 2014 5:11 am  (#40) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4758
If you start Gimp from a terminal, the plugin tells you what it does:

OK sensed
Old containers: set([u'Black', u'BigZip.zip', u'Green'])
New containers: set([u'BigZip.zip'])
Activated containers: set([])
Deactivated containers: set([u'Green', u'Black'])
102 addons stored in /home/me/.gimp-2.8/patterns_storage/Green
102 addons stored in /home/me/.gimp-2.8/patterns_storage/Black
Removing /home/me/.gimp-2.8/patterns/Black
Removing /home/me/.gimp-2.8/patterns/Green
Refresh: gimp_patterns_refresh
Refresh OK


I need this information to try to guess what is happening on your system.I also need to know if you are using zip or directories.

_________________
Image


Top
Post new topic Reply to topic  [ 51 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 5 hours [ DST ]


   Similar Topics   Replies 
No new posts Attachment(s) Addon Manager not working

14

No new posts Resource Manager advice

6

No new posts Installing the Mac version of G'MIC

1

No new posts Attachment(s) GMIC not installing

2

No new posts Attachment(s) Installing SCM in Fedora Linux

2



* Login  



Powered by phpBB3 © phpBB Group