""" python/ui/COLOUR.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009 University of York Copyright (C) 2012 STFC This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php 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 Lesser General Public License for more details. """ import pickle import os import re from global_definitions import * # colours stored as a list of colour definitions in rgbreps # The individual colour definition is a list of two items: # the name of the colour and the rgb representation which # is a three integer list # The colour of atoms etc is usually represented by an integer # number which is the index to the colour in the rgbreps list # The initial colours are stores as python list in resource file #execfile(os.path.join(os.environ["CCP4MG"],"python","etc","colour.py")) # or are restored from $HOME/.CCP4MG/mg_colours.pkl class COLOUR: insts = '' #------------------------------------------------------------------- def __init__(self): #------------------------------------------------------------------- COLOUR.insts = self usingOldColours = False # A number code for the next user defined colour self.new_name_number = 1 self.rgbreps = [] self.n_standard_rgbreps = 0 self.load_default() import cprim self.RGBReps = cprim.RGBReps() self.initialiseRGBReps() #----------------------------------------------------------------- def initialiseRGBReps(self): #----------------------------------------------------------------- # Initiallise the C class ii = 0 for name,rep in self.rgbreps: self.RGBReps.AddColour(name,rep[0],rep[1],rep[2],rep[3]) #print "COLOUR.initialiseRGBReps",ii,name,rep,self.RGBReps.GetNumberOfColours() ii = ii + 1 #------------------------------------------------------------------- def new(self,newname='',newrgb=[],rep=None): #------------------------------------------------------------------- # Add a new colour representation to the rgbreps list if not newname: newname = 'user_'+str(self.new_name_number) while self.index(newname,safe=0)>=0: self.new_name_number = self.new_name_number +1 newname = 'user_'+str(self.new_name_number) self.new_name_number = self.new_name_number +1 else: if newname[0:5] == 'user_': import utils nn = utils.safeInt(newname[5:],-1) if nn>0: self.new_name_number = max(self.new_name_number,nn+1) if not newrgb: newrgb = [0.5,0.5,0.5,1.0] elif len(newrgb) == 3: newrgb.append(1.0) for rgbrep in self.rgbreps: if newname == rgbrep[0]: #print "Colour already defined:",newname self.reset(newname,newrgb) return newname self.rgbreps.append([newname,newrgb]) self.RGBReps.AddColour(newname,newrgb[0],newrgb[1],newrgb[2],newrgb[3]) return newname #------------------------------------------------------------------- def index(self,name,safe=1): #------------------------------------------------------------------- # Return the list index for the colour name # Also test if there is a match for the name with underscore # replaced by spaces i = -1 for rgbrep in self.rgbreps: i = i + 1 if name == rgbrep[0]: return i # Usually return a 'safe' value if safe: return 0 else: return -1 #------------------------------------------------------------------- def colour_index(self,name,safe=1): #------------------------------------------------------------------- # Return the list index for the colour name # Also test if there is a match for the name with underscore # replaced by spaces i = -1 for rgbrep in self.rgbreps: i = i + 1 if name == rgbrep[0]: return i # Usually return a 'safe' value if safe: return 0 else: return -1 #------------------------------------------------------------------ def RGB(self,name): #------------------------------------------------------------------ #col = self.RGBReps.GetColour(name) #colv = [] #for item in col: colv.append(int(item)) #print "RGB colv",colv #return colv i = self.index(name,safe=0) if i < 0: if name == 'complement': col = self.RGBReps.GetColour(name) colv = [] for item in col: colv.append(int(item)) return colv else: i = 0 return self.rgbreps[i][1] #------------------------------------------------------------------ def RGB255(self,name): #------------------------------------------------------------------ rgb = self.RGB(name) return [int(rgb[0]*255.0), int(rgb[1]*255.0),int(rgb[2]*255.0)] #------------------------------------------------------------------ def hexadecimal(self,name): #------------------------------------------------------------------ #col = self.RGBReps.GetColour(name) #colv = [] #for item in col: colv.append(int(item)) #print "RGB colv",colv #return colv import math conv = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'] i = self.index(name,safe=0) if i < 0: if name == 'complement': col = self.RGBReps.GetColour(name) colv = [] for item in col: colv.append(int(item)) return colv else: i = 0 ret = '' for item in self.rgbreps[i][1][0:3]: ff,ii = math.modf(min(item,0.9961)*16.0) ret = ret + conv[int(ii)] ff,ii = math.modf(ff*16.0) ret = ret + conv[int(ii)] return ret #------------------------------------------------------------------- def next(self,name,exclude=[]): #------------------------------------------------------------------- # Return next colour in list after name i = 0 incr = 1 if name: nm = re.sub('_',' ',name) # nb the first item in list is 'default' - skip this for rgbrep in self.rgbreps[1:]: i = i + 1 if nm == rgbrep[0]: break while incr != 0: i = i + incr incr = 0 if i >= len(self.rgbreps): incr = 1 - i elif exclude.count( self.rgbreps[i][0] ) > 0: incr = 1 return self.rgbreps[i][0] #------------------------------------------------------------------- def colourlist(self): #------------------------------------------------------------------- # Return a list of the text representations - mostly for # use in menus l = [] for rgbrep in self.rgbreps: if rgbrep[0] != None: l.append(rgbrep[0]) return l #-------------------------------------------------------------------- def colour_menu (self,complement=0,interactive=0): #-------------------------------------------------------------------- if complement: mm = ['complement'] nn = ['complement'] else: mm = [] nn = [] for rep in self.rgbreps[1:]: if rep[0] != None: mm.append(rep[0]) nn.append(re.sub(' ','_',rep[0])) if interactive: mm.append('Interactive') nn.append('interactive') #print "colour_menu",mm,nn return [mm ,nn] #------------------------------------------------------------------- def colourkeys(self): #------------------------------------------------------------------- # Return a list of the text representations with no space # characters - replace by underscore l = [] for rgbrep in self.rgbreps: if rgbrep[0] != None: l.append(re.sub(' ','_',rgbrep[0])) return l #------------------------------------------------------------------- def delete(self,name): #------------------------------------------------------------------- # Replace the name of colour definition by None # This should mean that the colour is no longer used but the # rgb definition is still there just in case i = self.index(name,safe=0) if i >= 0: rgb = self.rgbreps[i][1] self.rgbreps.pop(i) self.rgbreps.insert(i,[None,rgb]) return 1 else: return 0 #------------------------------------------------------------------- def clear_custom_colours(self): #------------------------------------------------------------------- for ii in range(self.n_standard_rgbreps,len(self.rgbreps)): self.rgbreps[ii][0] = None #------------------------------------------------------------------- def rename(self,name,newname): #------------------------------------------------------------------- # Give a new name to a colour i = self.index(name,safe=0) if i >= 0: rgb = self.rgbreps[i][1] self.rgbreps.pop(i) self.rgbreps.insert(i,[newname,rgb]) return 1 else: return 0 ### BEWARE - THIS WILL NOT WORK #self.RGBReps.AddColour(name,rgb[0],rgb[1],rgb[2],rgb[3]) #------------------------------------------------------------------- def reset(self,name='', newrgb=[]): #------------------------------------------------------------------- if not name: for nm,rgb in self.rgbreps: # Beware nm may be set to None if nm: self.RGBReps.AddColour(nm,rgb[0],rgb[1],rgb[2],rgb[3]) else: i = self.index(name,safe=0) if i >= 0: self.rgbreps.pop(i) self.rgbreps.insert(i,[name,newrgb]) self.RGBReps.AddColour(name,newrgb[0],newrgb[1],newrgb[2],newrgb[3]) #----------------------------------------------------------------------- def getparams(self): #----------------------------------------------------------------------- # Remove any cancelled colours which will not have a colour name rgbreps = [] for rep in self.rgbreps: if rep[0]: rgbreps.append(rep) n_standard_rgbreps = self.n_standard_rgbreps return [rgbreps,n_standard_rgbreps] def get_standard_colours(self): cols = [] for n in range(0,self.n_standard_rgbreps): if self.rgbreps[n][0] != 'default': col = [self.rgbreps[n][0]] for ii in range(0,3): col.append(int(self.rgbreps[n][1][ii]*255.0)) cols.append(col) #print "COLOUR.get_standard_colours",cols return cols def get_custom_colours(self): cols = [] for n in range(self.n_standard_rgbreps,len(self.rgbreps)): if self.rgbreps[n][0]: name = self.rgbreps[n][0] col = [self.rgbreps[n][0]] for ii in range(0,3): col.append(int(self.rgbreps[n][1][ii]*255.0)) cols.append(col) #print "COLOUR.get_custom_colours",cols return cols #-------------------------------------------------------------------- def save_picture_definition(self,pretty_print,style='method',all=1): #-------------------------------------------------------------------- import utils,re #print "self.rgbreps",self.rgbreps indent=5 if style == 'method': b_end = ')' stream = 'Colours ( ' else: b_end = '}' stream = self.name + ' = {' reps = {} for item in self.rgbreps: if item[0]: reps[item[0]] = item[1] stream=stream+"colour_definitions = {\n" for item in self.rgbreps: if item[0]: stream=stream+" '"+item[0]+"' : [" for ii in item[1]: stream=stream+ str(ii)+',' stream=stream[0:-1]+'],\n' stream=stream[0:-2] + ' } \n' # stream=stream+utils.picture_defn_item('colour_definitions',reps,pretty_print,style=style) # ii = 0 # for item in self.rgbreps: # # Make sure don't save same colour def twice (fouls up reading # # the pic def file cos have duplicate argements to initialise method # safe = re.sub(' ','_',item[0]) # if self.rgbreps.index(item)==ii: # stream = stream+utils.picture_defn_item(safe,item[1],pretty_print,style=style,indent=indent) # ii=ii+1 stream = stream[0:-1]+ '\n '+b_end+'\n\n' return stream #--------------------------------------------------------------------- def setparams(self,params=[]): #--------------------------------------------------------------------- if len(params)==2: rgbreps,n_standard_rgbreps=params # Remove any null definitions if self.n_standard_rgbreps<=0 : self.n_standard_rgbreps = n_standard_rgbreps for name,rgb in rgbreps: self.new( name,rgb ) #print 'COLOUR.setparams',self.rgbreps #-------------------------------------------------------------------- def compare_objects(self,initial_status=None,final_status=None): #-------------------------------------------------------------------- final = {} initial_changed = {} final_changed = {} for item in final_status[0]:final[item[0]]=item[1] for item in initial_status[0]: if final.has_key(item[0]) and final[item[0]] != item[1]: initial_changed[item[0]]=item[1] final_changed[item[0]] = final[item[0]] return [initial_changed,final_changed] #------------------------------------------------------------------- def update_data_status(self,status): #------------------------------------------------------------------- #self.setparams(params=status) if len(status)==2: rgbreps,nrgbreps=status for name,rgb in rgbreps: #print "COLOUR update_data_status", name,rgb self.reset(name=name, newrgb=rgb) self.handle_colour_change() #------------------------------------------------------------------ def movie_interpolation(self,initial_status=None,final_status=None, \ fraction=0.0,step='',**keywords): #------------------------------------------------------------------ #print "COLOUR",fraction,initial_status,final_status for key,value in initial_status.items(): rgb=[] for i in [0,1,2]: rgb.append(((1-fraction)*value[i]) + (fraction*final_status[key][i])) rgb.append(255) #print "COLOUR",key,rgb self.reset(name=key, newrgb=rgb) self.handle_colour_change() #------------------------------------------------------------------- def dump(self,filename=None): #------------------------------------------------------------------- # Remove any cancelled colours which will not have a colour name rgbreps = [] for rep in self.rgbreps: if rep[0]: rgbreps.append(rep) n_standard_rgbreps = self.n_standard_rgbreps if not filename: import utils filename = utils.get_HOME() + "/.CCP4MG/mg_colours.pkl" f = open(filename,'w') p = pickle.Pickler(f) p.dump([rgbreps,n_standard_rgbreps]) f.close() #------------------------------------------------------------------- def load(self,filename=None): #------------------------------------------------------------------- if not filename: import utils filename = utils.get_HOME() + "/.CCP4MG/mg_colours.pkl" if os.path.exists(filename): try: f = open(filename,'r') p = pickle.Unpickler(f) self.rgbreps,self.n_standard_rgbreps = p.load() f.close() except: f.close() self.load_default() print "Error loading colour data from file:", filename return 0 else: #print "calling load_default" self.load_default() #print "COLOUR.load rgbreps",self.rgbreps ''' # Remove any null definitions i = 0 maxj = 0 for rgbrep in self.rgbreps: if not rgbrep[0]: self.rgbreps.pop(i) else: i = i +1 if rgbrep[0][0:5] == 'user_': try: jj = int(rgbrep[0][5:]) if jj > maxj: maxj = jj except: pass self.new_name_number = maxj + 1 ''' #--------------------------------------------------------------------- def load_old_default(self,filename = None,colour=''): #--------------------------------------------------------------------- filename = os.path.join(os.environ["CCP4MG" ],'python','etc','colour_252.py') self.load_default(filename,colour) #--------------------------------------------------------------------- def load_default(self,filename = None,colour=''): #--------------------------------------------------------------------- if not filename: filename = os.path.join(os.environ["CCP4MG" ], \ 'python','etc','colour.py') # etc/colour.py defines a list called rgbreps globals = {} locals= {} execfile(filename,globals,locals) if colour: # Reset specific colour to default i = -1 for rgb in locals['rgbreps']: i = i+1 if colour == rgb[0]: self.rgbreps.pop(i) self.rgbreps.insert(i,rgb) return else: # Load all colours to rgbreps # Do NOT reinititiallise self.rgbreps - this may be for # just resetting all 'standard' colours to default for colour,defn in locals['rgbreps']: ii = self.index(colour,safe=0) if ii >= 0: self.rgbreps.pop(ii) self.rgbreps.insert(ii,[colour,defn]) else: self.rgbreps.append([colour,defn]) # If the number of standard colours is not known set it now if not self.n_standard_rgbreps: self.n_standard_rgbreps=len(locals['rgbreps']) #print " load_default rgbreps ", self.rgbreps #------------------------------------------------------------------- def handle_colour_change(self,name='',rename='',delete=0): #------------------------------------------------------------------- import dataobj if delete: for obj in dataobj.get_dispobj(): obj.handle_colour_change(name=name,delete=delete) if rename: for obj in dataobj.get_dispobj(): obj.handle_colour_change(name=name,rename=rename) #print "handle_colour_change",name else: standard = 1 if not name or self.index(name)>=self.n_standard_rgbreps: standard = 0 for obj in dataobj.get_dispobj(): obj.handle_colour_change(name=name,standard=standard) return