def __init__(self): assert isinstance(self, CanvasMixin), "Missing CanvasMixin class" from .CanvasObject import drawCatalog # For interactive drawing self.candraw = False self.draw_dict = drawCatalog # canvas objects which we know how to draw have an "idraw" # class method self.drawtypes = [ key for key in self.draw_dict.keys() if hasattr(self.draw_dict[key], 'idraw') ] self.drawtypes.sort() self.t_drawtype = 'point' self.t_drawparams = {} # holds the drawing context self._draw_cxt = None # For interactive editing self.canedit = False # Set to False to disable drag moves except from move control pt self.easymove = True self._start_x = 0 self._start_y = 0 self._cp_index = None self._edit_obj = None self._edit_status = False # For modes self._mode = 'draw' self._mode_tbl = Bunch() self.add_draw_mode(None) self.add_draw_mode('draw', down=self.draw_start, move=self.draw_motion, up=self.draw_stop, poly_add=self.draw_poly_add, poly_delete=self.draw_poly_delete) self.add_draw_mode('edit', down=self.edit_start, move=self.edit_motion, up=self.edit_stop, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) # For selection self._selected = [] self.multi_select_ok = False # this controls whether an object is automatically selected for # editing immediately after being drawn self.edit_follows_draw = False self._process_time = 0.0 # time delta threshold for deciding whether to update the image self._delta_time = 0.020 self._draw_obj = None # NOTE: must be mixed in with a Callback.Callbacks for name in ('draw-event', 'draw-down', 'draw-move', 'draw-up', 'cursor-down', 'cursor-up', 'cursor-move', 'draw-scroll', 'keydown-poly_add', 'keydown-poly_del', 'keydown-edit_del', 'edit-event', 'edit-select', 'drag-drop'): self.enable_callback(name)
def add_global_plugin(self, module_name, ws_name, path=None, klass=None, category='Global', tab_name=None, start_plugin=True, pfx=None): self.add_plugin_spec( Bunch(module=module_name, workspace=ws_name, tab=tab_name, path=path, klass=klass, category=category, ptype='global', start=start_plugin, pfx=pfx))
def createTab(self): # If we have already created (and possibly closed) this # proposal tab before, just reload it. Otherwise, we have to # create it from scratch. proposal = self.model.proposalForPropTab self.logger.info('Creating tab for proposal %s' % proposal) if self.view.gpmon.has_plugin(proposal): self.view.reload_plugin(proposal) else: spec = Bunch(module='ProposalTab', klass='ProposalTab', ws='report', tab=proposal, name=proposal, start=False, ptype='global') self.view.load_plugin(proposal, spec) self.view.start_plugin(proposal) # Raise the tab we just created self.view.ds.raise_tab(proposal)
def draw_start(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_obj = None self.clear_selected() # get the drawing coordinate type (default 'data') crdtype = self.t_drawparams.get('coord', 'data') crdmap = viewer.get_coordmap(crdtype) x, y = crdmap.data_to(data_x, data_y) klass = self.draw_dict.get(self.t_drawtype, None) # create the drawing context self._draw_cxt = Bunch(start_x=x, start_y=y, points=[(x, y)], x=x, y=y, data_x=data_x, data_y=data_y, drawparams=self.t_drawparams, crdmap=crdmap, viewer=viewer, draw_class=klass, logger=self.logger) self._draw_update(data_x, data_y, self._draw_cxt, force_update=True) return True
def _get_stginga_plugins(): # TODO: When we use stable Ginga release, not the dev, we can remove this # and just have version check in setup.py if ginga_version < '2.5.20160222004742': warnings.warn('Your Ginga version {0} is old, stginga might not work ' 'properly'.format(ginga_version), AstropyUserWarning) gpfx = 'stginga.plugins' # To load custom plugins in Ginga namespace global_plugins = [] local_plugins = [ Bunch(module='MultiImage', ws='dialogs', pfx=gpfx), Bunch(module='MIPick', ws='dialogs', pfx=gpfx), Bunch(module='BackgroundSub', ws='dialogs', pfx=gpfx), Bunch(module='BadPixCorr', ws='dialogs', pfx=gpfx), Bunch(module='DQInspect', ws='dialogs', pfx=gpfx), Bunch(module='SNRCalc', ws='dialogs', pfx=gpfx), ] return global_plugins, local_plugins
def setup_CSU_initializer(): spec = Bunch(path=os.path.join(p_path, 'CSU_initializer.py'), module='CSU_initializer', klass='CSU_initializer', ptype='local', workspace='dialogs', category="Keck", menu="CSU_initializer", tab='CSU_initializer') return spec
def __init__(self): assert isinstance(self, CanvasMixin), "Missing CanvasMixin class" from .CanvasObject import drawCatalog # For interactive drawing self.candraw = False self.draw_dict = drawCatalog # canvas objects which we know how to draw have an "idraw" # class method self.drawtypes = [ key for key in self.draw_dict.keys() if hasattr(self.draw_dict[key], 'idraw') ] self.drawtypes.sort() self.t_drawtype = 'point' self.t_drawparams = {} # holds the drawing context self._draw_cxt = None # For interactive editing self.canedit = False # Set to False to disable drag moves except from move control pt self.easymove = True self._start_x = 0 self._start_y = 0 self._cp_index = None self._edit_obj = None self._edit_status = False self._edit_detail = {} self._pick_cur_obj = None # For modes self._mode = 'draw' self._mode_tbl = Bunch() self.add_draw_mode(None) self.add_draw_mode('draw', down=self.draw_start, move=self.draw_motion, up=self.draw_stop, poly_add=self.draw_poly_add, poly_delete=self.draw_poly_delete) self.add_draw_mode('edit', down=self.edit_start, move=self.edit_motion, up=self.edit_stop, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) self.add_draw_mode('pick', down=self.pick_start, move=self.pick_motion, up=self.pick_stop, hover=self.pick_hover, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) # For selection self._selected = [] self.multi_select_ok = False # this controls whether an object is automatically selected for # editing immediately after being drawn self.edit_follows_draw = False self._process_time = 0.0 # time delta threshold for deciding whether to update the image self._delta_time = 0.020 self._draw_obj = None # NOTE: must be mixed in with a Callback.Callbacks for name in ('draw-event', 'draw-down', 'draw-move', 'draw-up', 'cursor-down', 'cursor-up', 'cursor-move', 'draw-scroll', 'keydown-poly_add', 'keydown-poly_del', 'keydown-edit_del', 'edit-event', 'edit-select', 'drag-drop', 'cursor-changed'): self.enable_callback(name)
stretch=1), dict(row=[ 'ws', dict(name='toolbar', wstype='stack', height=40, group=2) ], stretch=0), dict(row=['hbox', dict(name='status')], stretch=0), ] ] plugins = [ # hidden plugins, started at program initialization Bunch(module='Operations', workspace='operations', start=True, hidden=True, category='System', menu="Operations [G]", ptype='global'), Bunch(module='Toolbar', workspace='toolbar', start=True, hidden=True, category='System', menu="Toolbar [G]", ptype='global'), Bunch(module='Pan', workspace='uleft', start=True, hidden=True, category='System',
def setup_cometaryenhancements(): spec = Bunch(path=os.path.join(p_path, 'CometaryEnhancements.py'), module='CometaryEnhancements', klass='CometaryEnhancements', workspace='dialogs') return spec
['ws', dict(name='dialogs', wstype='tabs', group=2)])] ], ], stretch=1), dict(row=[ 'ws', dict(name='toolbar', wstype='stack', height=40, group=2) ], stretch=0), dict(row=['hbox', dict(name='status')], stretch=0), ] ] global_plugins = [ Bunch(module='Toolbar', tab='Toolbar', ws='toolbar'), Bunch(module='Pan', tab='_pan', ws='uleft', raisekey=None), Bunch(module='Info', tab='Synopsis', ws='lleft', raisekey=None), Bunch(module='Header', tab='Header', ws='left', raisekey='H'), Bunch(module='Zoom', tab='Zoom', ws='left', raisekey='Z'), Bunch(module='Thumbs', tab='Thumbs', ws='right', raisekey='T'), Bunch(module='Contents', tab='Contents', ws='right', raisekey='c'), Bunch(module='Colorbar', tab='_cbar', ws='cbar', start=True), Bunch(module='Cursor', tab='_readout', ws='readout', start=True), Bunch(module='Operations', tab='_opns', ws='operations', start=True), Bunch(module='WBrowser', tab='Help', ws='channels', raisekey='?', start=False), Bunch(module='FBrowser', tab='Open File', ws='right', start=False),
def main(self, options, args): """ Main routine for running the reference viewer. `options` is a OptionParser object that has been populated with values from parsing the command line. It should at least include the options from add_default_options() `args` is a list of arguments to the viewer after parsing out options. It should contain a list of files or URLs to load. """ # Create a logger logger = log.get_logger(name='ginga', options=options) # Get settings (preferences) basedir = paths.ginga_home if not os.path.exists(basedir): try: os.mkdir(basedir) except OSError as e: logger.warn("Couldn't create ginga settings area (%s): %s" % (basedir, str(e))) logger.warn("Preferences will not be able to be saved") # Set up preferences prefs = Settings.Preferences(basefolder=basedir, logger=logger) settings = prefs.createCategory('general') settings.load(onError='silent') settings.setDefaults(useMatplotlibColormaps=False, widgetSet='choose', WCSpkg='choose', FITSpkg='choose', recursion_limit=2000) # default of 1000 is a little too small sys.setrecursionlimit(settings.get('recursion_limit')) # So we can find our plugins sys.path.insert(0, basedir) moduleHome = os.path.split(sys.modules['ginga.version'].__file__)[0] childDir = os.path.join(moduleHome, 'misc', 'plugins') sys.path.insert(0, childDir) pluginDir = os.path.join(basedir, 'plugins') sys.path.insert(0, pluginDir) # Choose a toolkit if options.toolkit: toolkit = options.toolkit else: toolkit = settings.get('widgetSet', 'choose') if toolkit == 'choose': try: from ginga.qtw import QtHelp except ImportError: try: from ginga.gtkw import GtkHelp except ImportError: print("You need python-gtk or python-qt to run Ginga!") sys.exit(1) else: ginga_toolkit.use(toolkit) tkname = ginga_toolkit.get_family() logger.info("Chosen toolkit (%s) family is '%s'" % (ginga_toolkit.toolkit, tkname)) # these imports have to be here, otherwise they force the choice # of toolkit too early from ginga.gw.GingaGw import GingaView from ginga.Control import GingaControl, GuiLogHandler # Define class dynamically based on toolkit choice class GingaShell(GingaControl, GingaView): def __init__(self, logger, thread_pool, module_manager, prefs, ev_quit=None): GingaView.__init__(self, logger, ev_quit, thread_pool) GingaControl.__init__(self, logger, thread_pool, module_manager, prefs, ev_quit=ev_quit) if settings.get('useMatplotlibColormaps', False): # Add matplotlib color maps if matplotlib is installed try: from ginga import cmap cmap.add_matplotlib_cmaps() except Exception as e: logger.warn("failed to load matplotlib colormaps: %s" % (str(e))) # User wants to customize the WCS package? if options.wcspkg: wcspkg = options.wcspkg else: wcspkg = settings.get('WCSpkg', 'choose') try: from ginga.util import wcsmod assert wcsmod.use(wcspkg) == True except Exception as e: logger.warn("failed to set WCS package preference: %s" % (str(e))) # User wants to customize the FITS package? if options.fitspkg: fitspkg = options.fitspkg else: fitspkg = settings.get('FITSpkg', 'choose') try: from ginga.util import io_fits assert io_fits.use(fitspkg) == True except Exception as e: logger.warn("failed to set FITS package preference: %s" % (str(e))) # Check whether user wants to use OpenCv use_opencv = settings.get('use_opencv', False) if use_opencv or options.opencv: from ginga import trcalc try: trcalc.use('opencv') except Exception as e: logger.warn("failed to set OpenCv preference: %s" % (str(e))) # Create the dynamic module manager mm = ModuleManager.ModuleManager(logger) # Create and start thread pool ev_quit = threading.Event() thread_pool = Task.ThreadPool(options.numthreads, logger, ev_quit=ev_quit) thread_pool.startall() # Create the Ginga main object ginga_shell = GingaShell(logger, thread_pool, mm, prefs, ev_quit=ev_quit) ginga_shell.set_layout(self.layout) gc = os.path.join(basedir, "ginga_config.py") have_ginga_config = os.path.exists(gc) # User configuration (custom star catalogs, etc.) if have_ginga_config: try: import ginga_config ginga_config.pre_gui_config(ginga_shell) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error importing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Build desired layout ginga_shell.build_toplevel() # Did user specify a particular geometry? if options.geometry: ginga_shell.set_geometry(options.geometry) # make the list of disabled plugins disabled_plugins = [] if not (options.disable_plugins is None): disabled_plugins = options.disable_plugins.lower().split(',') # Add desired global plugins for spec in self.global_plugins: if not spec.module.lower() in disabled_plugins: ginga_shell.add_global_plugin(spec) # Add GUI log handler (for "Log" global plugin) guiHdlr = GuiLogHandler(ginga_shell) guiHdlr.setLevel(options.loglevel) fmt = logging.Formatter(log.LOG_FORMAT) guiHdlr.setFormatter(fmt) logger.addHandler(guiHdlr) # Load any custom modules if options.modules: modules = options.modules.split(',') for longPluginName in modules: if '.' in longPluginName: tmpstr = longPluginName.split('.') pluginName = tmpstr[-1] pfx = '.'.join(tmpstr[:-1]) else: pluginName = longPluginName pfx = None spec = Bunch(name=pluginName, module=pluginName, tab=pluginName, ws='right', pfx=pfx) ginga_shell.add_global_plugin(spec) # Load modules for "local" (per-channel) plug ins for spec in self.local_plugins: if not spec.module.lower() in disabled_plugins: ginga_shell.add_local_plugin(spec) # Load any custom plugins if options.plugins: plugins = options.plugins.split(',') for longPluginName in plugins: if '.' in longPluginName: tmpstr = longPluginName.split('.') pluginName = tmpstr[-1] pfx = '.'.join(tmpstr[:-1]) else: pluginName = longPluginName pfx = None spec = Bunch(module=pluginName, ws='dialogs', hidden=False, pfx=pfx) ginga_shell.add_local_plugin(spec) ginga_shell.update_pending() # TEMP? tab_names = list( map(lambda name: name.lower(), ginga_shell.ds.get_tabnames(group=None))) if 'info' in tab_names: ginga_shell.ds.raise_tab('Info') if 'thumbs' in tab_names: ginga_shell.ds.raise_tab('Thumbs') # Add custom channels channels = options.channels.split(',') for chname in channels: ginga_shell.add_channel(chname) ginga_shell.change_channel(channels[0]) # User configuration (custom star catalogs, etc.) if have_ginga_config: try: ginga_config.post_gui_config(ginga_shell) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error processing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Redirect warnings to logger for hdlr in logger.handlers: logging.getLogger('py.warnings').addHandler(hdlr) # Display banner the first time run, unless suppressed showBanner = True try: showBanner = settings.get('showBanner') except KeyError: # disable for subsequent runs settings.set(showBanner=False) settings.save() if (not options.nosplash) and (len(args) == 0) and showBanner: ginga_shell.banner(raiseTab=True) # Assume remaining arguments are fits files and load them. for imgfile in args: ginga_shell.nongui_do(ginga_shell.load_file, imgfile) try: try: # if there is a network component, start it if hasattr(ginga_shell, 'start'): task = Task.FuncTask2(ginga_shell.start) thread_pool.addTask(task) # Main loop to handle GUI events logger.info("Entering mainloop...") ginga_shell.mainloop(timeout=0.001) except KeyboardInterrupt: logger.error("Received keyboard interrupt!") finally: logger.info("Shutting down...") ev_quit.set() sys.exit(0)
qexec.py --help qexec.py [options] """ import sys, os from ginga.misc.Bunch import Bunch from qplan import main, version defaultServiceName = 'qexecute' plugins = [ Bunch(name='slewchart', module='SlewChart', klass='SlewChart', ptype='global', tab='Slew Chart', ws='sub2', start=True), Bunch(name='airmasschart', module='AirMassChart', klass='AirMassChart', ptype='global', tab='Airmass Chart', ws='sub1', start=True), Bunch(name='schedule', module='Schedule', klass='Schedule', ptype='global', tab='Schedule',
def main(options, args): # default of 1000 is a little too small sys.setrecursionlimit(2000) # Create a logger logger = log.get_logger(name='ginga', options=options) # Get settings (preferences) basedir = paths.ginga_home if not os.path.exists(basedir): try: os.mkdir(basedir) except OSError as e: logger.warn("Couldn't create ginga settings area (%s): %s" % (basedir, str(e))) logger.warn("Preferences will not be able to be saved") # Set up preferences prefs = Settings.Preferences(basefolder=basedir, logger=logger) settings = prefs.createCategory('general') settings.load(onError='silent') settings.setDefaults(useMatplotlibColormaps=False, widgetSet='choose', WCSpkg='choose', FITSpkg='choose') # So we can find our plugins sys.path.insert(0, basedir) moduleHome = os.path.split(sys.modules['ginga.version'].__file__)[0] childDir = os.path.join(moduleHome, 'misc', 'plugins') sys.path.insert(0, childDir) pluginDir = os.path.join(basedir, 'plugins') sys.path.insert(0, pluginDir) # Choose a toolkit if options.toolkit: toolkit = options.toolkit else: toolkit = settings.get('widgetSet', 'choose') ginga_toolkit.use(toolkit) tkname = ginga_toolkit.get_family() if tkname == 'gtk': from ginga.gtkw.GingaGtk import GingaView elif tkname == 'qt': from ginga.qtw.GingaQt import GingaView else: try: from ginga.qtw.GingaQt import GingaView except ImportError: try: from ginga.gtkw.GingaGtk import GingaView except ImportError: print("You need python-gtk or python-qt4 to run Ginga!") sys.exit(1) # Define class dynamically based on toolkit choice class Ginga(GingaControl, GingaView): def __init__(self, logger, threadPool, module_manager, prefs, ev_quit=None): GingaView.__init__(self, logger, ev_quit) GingaControl.__init__(self, logger, threadPool, module_manager, prefs, ev_quit=ev_quit) if settings.get('useMatplotlibColormaps', False): # Add matplotlib color maps if matplotlib is installed try: from ginga import cmap cmap.add_matplotlib_cmaps() except Exception as e: logger.warn("failed to load matplotlib colormaps: %s" % (str(e))) # User wants to customize the WCS package? if options.wcs: wcspkg = options.wcs else: wcspkg = settings.get('WCSpkg', 'choose') try: from ginga.util import wcsmod assert wcsmod.use(wcspkg) == True except Exception as e: logger.warn("failed to set WCS package preference: %s" % (str(e))) # User wants to customize the FITS package? if options.fits: fitspkg = options.fits else: fitspkg = settings.get('FITSpkg', 'choose') try: from ginga.util import io_fits assert io_fits.use(fitspkg) == True except Exception as e: logger.warn("failed to set FITS package preference: %s" % (str(e))) # Create the dynamic module manager mm = ModuleManager.ModuleManager(logger) # Create and start thread pool ev_quit = threading.Event() threadPool = Task.ThreadPool(options.numthreads, logger, ev_quit=ev_quit) threadPool.startall() # Create the Ginga main object ginga = Ginga(logger, threadPool, mm, prefs, ev_quit=ev_quit) ginga.set_layout(default_layout) # User configuration (custom star catalogs, etc.) try: import ginga_config ginga_config.pre_gui_config(ginga) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error importing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Build desired layout ginga.build_toplevel() # Did user specify a particular geometry? if options.geometry: ginga.setGeometry(options.geometry) # Add desired global plugins for spec in global_plugins: ginga.add_global_plugin(spec) # Add GUI log handler (for "Log" global plugin) guiHdlr = GuiLogHandler(ginga) guiHdlr.setLevel(options.loglevel) fmt = logging.Formatter(log.LOG_FORMAT) guiHdlr.setFormatter(fmt) logger.addHandler(guiHdlr) # Load any custom modules if options.modules: modules = options.modules.split(',') for pluginName in modules: spec = Bunch(name=pluginName, module=pluginName, tab=pluginName, ws='right') ginga.add_global_plugin(spec) # Load modules for "local" (per-channel) plug ins for spec in local_plugins: ginga.add_local_plugin(spec) # Load any custom plugins if options.plugins: plugins = options.plugins.split(',') for pluginName in plugins: spec = Bunch(module=pluginName, ws='dialogs', hidden=False) ginga.add_local_plugin(spec) ginga.update_pending() # TEMP? ginga.ds.raise_tab('Info') ginga.ds.raise_tab('Thumbs') # Add custom channels channels = options.channels.split(',') for chname in channels: datasrc = Datasrc.Datasrc(length=options.bufsize) ginga.add_channel(chname, datasrc) ginga.change_channel(channels[0]) # User configuration (custom star catalogs, etc.) try: ginga_config.post_gui_config(ginga) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error processing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Display banner the first time run, unless suppressed showBanner = True try: showBanner = settings.get('showBanner') except KeyError: # disable for subsequent runs settings.set(showBanner=False) settings.save() if (not options.nosplash) and (len(args) == 0) and showBanner: ginga.banner() # Assume remaining arguments are fits files and load them. for imgfile in args: ginga.nongui_do(ginga.load_file, imgfile) try: try: # Main loop to handle GUI events logger.info("Entering mainloop...") ginga.mainloop(timeout=0.001) except KeyboardInterrupt: logger.error("Received keyboard interrupt!") finally: logger.info("Shutting down...") ev_quit.set() sys.exit(0)
def edit_start(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False self._edit_tmp = self._edit_obj self._edit_status = False self._edit_detail = Bunch() self._cp_index = None #shift_held = 'shift' in event.modifiers shift_held = False selects = self.get_selected() if len(selects) == 0: #print("no objects already selected") # <-- no objects already selected # check for objects at this location #print("getting items") objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("items: %s" % (str(objs))) if len(objs) == 0: # <-- no objects under cursor return False # pick top object obj = objs[-1] self._prepare_to_move(obj, data_x, data_y) else: self._edit_status = True # Ugh. Check each selected object's control points # for a match contains = [] for obj in selects: #print("editing: checking for cp") edit_pts = obj.get_edit_points(viewer) #print((self._edit_obj, edit_pts)) i = obj.get_pt(viewer, edit_pts, data_x, data_y, obj.cap_radius) #print(('got point', i)) if i is not None: #print("editing cp #%d" % (i)) # editing a control point from an existing object self._edit_obj = obj self._cp_index = i if hasattr(obj, 'rot_deg'): x, y = self._rot_xlate(self._edit_obj, data_x, data_y) else: x, y = data_x, data_y self._edit_detail.start_pos = (x, y) obj.setup_edit(self._edit_detail) self._edit_update(data_x, data_y, viewer) return True ## if obj.contains(data_x, data_y): ## contains.append(obj) # update: check if objects bbox contains this point x1, y1, x2, y2 = obj.get_llur() if (x1 <= data_x <= x2) and (y1 <= data_y <= y2): contains.append(obj) # <-- no control points match, is there an object that contains # this point? if len(contains) > 0: # TODO?: make a compound object of contains and move it? obj = contains[-1] if self.is_selected(obj) and shift_held: # deselecting object self.select_remove(obj) else: self._prepare_to_move(obj, data_x, data_y) ## Compound = self.get_draw_class('compoundobject') ## c_obj = Compound(*self.get_selected()) ## c_obj.inherit_from(obj) ## self._prepare_to_move(c_obj, data_x, data_y) else: # <-- user clicked outside any selected item's control pt # and outside any selected item if not shift_held: self.clear_selected() # see now if there is an unselected item at this location objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("new items: %s" % (str(objs))) if len(objs) > 0: # pick top object obj = objs[-1] #print(("top object", obj)) if self.num_selected() > 0: #print("there are previously selected items") # if there are already some selected items, then # add this object to the selection, make a compound # object self.edit_select(obj) Compound = self.get_draw_class('compoundobject') c_obj = Compound(*self.get_selected()) c_obj.inherit_from(obj) self._prepare_to_move(c_obj, data_x, data_y) else: # otherwise just start over with this new object #print(("starting over")) self._prepare_to_move(obj, data_x, data_y) self.process_drawing() return True
def update_scheduler(self, use_db=False, ignore_pgm_skip_flag=False): sdlr = self.model.get_scheduler() try: sdlr.set_weights(self.weights_qf.weights) sdlr.set_schedule_info(self.schedule_qf.schedule_info) pgms = self.programs_qf.programs_info sdlr.set_programs_info(pgms, ignore_pgm_skip_flag) self.logger.info('list of programs to be scheduled %s' % sdlr.programs.keys()) # TODO: this maybe should be done in the Model ob_keys = set([]) propnames = list(self.programs_qf.programs_info.keys()) okprops = [] ob_dict = {} # Note: if the ignore_pgm_skip_flag is set to True, then # we don't pay attention to the "skip" flag in the # Programs sheet and thus consider all OB's in all # Programs. Otherwise, we do pay attention to the "skip" # flag and ignore all OB's in "skipped" programs. for propname in propnames: if not ignore_pgm_skip_flag and pgms[propname].skip: self.logger.info( 'skip flag for program %s is set - skipping all OB in this program' % propname) continue okprops.append(propname) # get all OB keys for this program for ob in self.ob_qf_dict[propname].obs_info: key = (propname, ob.name) ob_keys.add(key) ob_dict[key] = ob self.logger.info("%s OBs after excluding skipped programs." % (len(ob_keys))) # Remove keys for OBs that are already executed if use_db: self.connect_qdb() do_not_execute = set(self.qq.get_do_not_execute_ob_keys()) # Painful reconstruction of time already accumulated # running the programs for executed OBS. Inform scheduler # so that it can correcly calculate when to stop # allocating OBs for a program that has reached its # time limit. props = {} for ob_key in do_not_execute: (propid, obcode) = ob_key[:2] ob = self.qq.get_ob(ob_key) bnch = props.setdefault(propid, Bunch(obcount=0, sched_time=0.0)) bnch.sched_time += ob.acct_time bnch.obcount += 1 sdlr.set_apriori_program_info(props) ob_keys -= do_not_execute elif self.model.completed_obs is not None: do_not_execute = set(self.model.completed_obs.keys()) # See comment above. props = {} for ob_key in do_not_execute: (propid, obcode) = ob_key[:2] bnch = props.setdefault(propid, Bunch(obcount=0, sched_time=0.0)) info = self.model.completed_obs[ob_key] bnch.sched_time += info['acct_time'] bnch.obcount += 1 sdlr.set_apriori_program_info(props) ob_keys -= do_not_execute self.logger.info("%s OBs after removing executed OBs." % (len(ob_keys))) # for a deterministic result ob_keys = list(ob_keys) ob_keys.sort() # Now turn the keys back into actual OB list oblist_info = [] for key in ob_keys: oblist_info.append(ob_dict[key]) self.oblist_info = oblist_info # TODO: only needed if we ADD or REMOVE programs sdlr.set_oblist_info(self.oblist_info) except Exception as e: self.logger.error("Error storing into scheduler: %s" % (str(e))) self.logger.info("scheduler initialized")
def setup_MultiBars(): spec = Bunch(path=os.path.join(p_path, 'MultiBars.py'), module='MultiBars', klass='MultiBars', workspace='dialogs') return spec
def setup_CSU_initializer(): spec = Bunch(path=os.path.join(p_path, 'CSU_initializer.py'), module='CSU_initializer', klass='CSU_initializer', workspace='dialogs') return spec
def setup_mylocalplugin(): spec = Bunch(path=os.path.join(p_path, 'MyLocalPlugin.py'), module='MyLocalPlugin', klass='MyLocalPlugin', workspace='dialogs') return spec
class DrawingMixin(object): """The DrawingMixin is a mixin class that adds drawing capability for some of the basic CanvasObject-derived types. The set_surface method is used to associate a ImageViewCanvas object for layering on. """ def __init__(self): assert isinstance(self, CanvasMixin), "Missing CanvasMixin class" from .CanvasObject import drawCatalog # For interactive drawing self.candraw = False self.draw_dict = drawCatalog # canvas objects which we know how to draw have an "idraw" # class method self.drawtypes = [ key for key in self.draw_dict.keys() if hasattr(self.draw_dict[key], 'idraw') ] self.drawtypes.sort() self.t_drawtype = 'point' self.t_drawparams = {} # holds the drawing context self._draw_cxt = None # For interactive editing self.canedit = False # Set to False to disable drag moves except from move control pt self.easymove = True self._start_x = 0 self._start_y = 0 self._cp_index = None self._edit_obj = None self._edit_status = False # For modes self._mode = 'draw' self._mode_tbl = Bunch() self.add_draw_mode(None) self.add_draw_mode('draw', down=self.draw_start, move=self.draw_motion, up=self.draw_stop, poly_add=self.draw_poly_add, poly_delete=self.draw_poly_delete) self.add_draw_mode('edit', down=self.edit_start, move=self.edit_motion, up=self.edit_stop, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) # For selection self._selected = [] self.multi_select_ok = False # this controls whether an object is automatically selected for # editing immediately after being drawn self.edit_follows_draw = False self._process_time = 0.0 # time delta threshold for deciding whether to update the image self._delta_time = 0.020 self._draw_obj = None # NOTE: must be mixed in with a Callback.Callbacks for name in ('draw-event', 'draw-down', 'draw-move', 'draw-up', 'cursor-down', 'cursor-up', 'cursor-move', 'draw-scroll', 'keydown-poly_add', 'keydown-poly_del', 'keydown-edit_del', 'edit-event', 'edit-select', 'drag-drop'): self.enable_callback(name) def set_surface(self, viewer): self.viewer = viewer # register this canvas for events of interest canvas = self # for legacy drawing via draw mode in Bindmap canvas.add_callback('draw-down', self.draw_start, viewer) canvas.add_callback('draw-move', self.draw_motion, viewer) canvas.add_callback('draw-up', self.draw_stop, viewer) canvas.add_callback('key-press', self._draw_key, 'key', viewer) canvas.add_callback('keydown-poly_add', self._draw_op, 'poly_add', viewer) canvas.add_callback('keydown-poly_del', self._draw_op, 'poly_delete', viewer) canvas.add_callback('keydown-edit_del', self.edit_delete_cb, viewer) #canvas.add_callback('draw-scroll', self._edit_rotate_cb, viewer) #canvas.add_callback('draw-scroll', self._edit_scale_cb, viewer) def get_surface(self): return self.viewer def register_for_cursor_drawing(self, viewer): canvas = self canvas.add_callback('cursor-down', self._draw_op, 'down', viewer) canvas.add_callback('cursor-move', self._draw_op, 'move', viewer) canvas.add_callback('cursor-up', self._draw_op, 'up', viewer) ##### MODE LOGIC ##### def add_draw_mode(self, name, **kwargs): try: bnch = self._mode_tbl[name] except KeyError: bnch = Bunch(name=name, **kwargs) self._mode_tbl[name] = bnch return bnch def set_draw_mode(self, mode): if not mode in self._mode_tbl: modes = list(self._mode_tbl.keys()) raise ValueError("mode must be one of: %s" % (str(modes))) self._mode = mode if mode != 'edit': self.clear_selected() self.update_canvas() def get_draw_mode(self): return self._mode def _draw_op(self, canvas, event, data_x, data_y, opn, viewer): if viewer != event.viewer: return False mode = self._mode # Hack to handle legacy drawing using draw mode in Bindmap if self.is_drawing(): mode = 'draw' try: method = self._mode_tbl[mode][opn] except KeyError: return False if method is not None: return method(canvas, event, data_x, data_y, viewer) return False def _draw_key(self, canvas, keyname, opn, viewer): # synthesize a KeyEvent # TODO: this is hacky--see if we can rethink how this is handled # so that we get passed an event similar to _draw_op() last_x, last_y = viewer.get_last_data_xy() event = KeyEvent(key=keyname, state='down', mode=self._mode, modifiers=[], viewer=viewer, data_x=last_x, data_y=last_y) return self._draw_op(canvas, event, last_x, last_y, opn, viewer) ##### DRAWING LOGIC ##### def _draw_update(self, data_x, data_y, cxt): ## self.logger.debug("drawing a '%s' x,y=%f,%f" % ( ## self.t_drawtype, data_x, data_y)) klass = self.draw_dict[self.t_drawtype] obj = None # update the context with current position x, y = cxt.crdmap.data_to(data_x, data_y) cxt.setvals(x=x, y=y, data_x=data_x, data_y=data_y) obj = klass.idraw(self, cxt) # elif self.t_drawtype == 'equilateraltriangle': # len_x = self._start_x - x # len_y = self._start_y - y # length = max(abs(len_x), abs(len_y)) # obj = klass(self._start_x, self._start_y, # length, length, **self.t_drawparams) if obj is not None: obj.initialize(None, cxt.viewer, self.logger) #obj.initialize(None, cxt.viewer, viewer.logger) self._draw_obj = obj if time.time() - self._process_time > self._delta_time: self.process_drawing() return True def draw_start(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_obj = None # get the drawing coordinate type (default 'data') crdtype = self.t_drawparams.get('coord', 'data') crdmap = viewer.get_coordmap(crdtype) x, y = crdmap.data_to(data_x, data_y) # create the drawing context self._draw_cxt = Bunch(start_x=x, start_y=y, points=[(x, y)], x=x, y=y, data_x=data_x, data_y=data_y, drawparams=self.t_drawparams, crdmap=crdmap, viewer=viewer, logger=self.logger) self._draw_update(data_x, data_y, self._draw_cxt) self.process_drawing() return True def draw_stop(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_update(data_x, data_y, self._draw_cxt) obj, self._draw_obj = self._draw_obj, None if obj: objtag = self.add(obj) self.make_callback('draw-event', objtag) if self.edit_follows_draw: #self.set_draw_mode('edit') self.clear_selected() self.edit_select(obj) self.make_callback('edit-select', self._edit_obj) return True else: self.process_drawing() def draw_motion(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_update(data_x, data_y, self._draw_cxt) return True def draw_poly_add(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False cxt = self._draw_cxt if self.t_drawtype in ('polygon', 'path'): x, y = cxt.crdmap.data_to(data_x, data_y) cxt.points.append((x, y)) elif self.t_drawtype == 'beziercurve' and len(cxt.points) < 3: x, y = cxt.crdmap.data_to(data_x, data_y) cxt.points.append((x, y)) return True def draw_poly_delete(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False cxt = self._draw_cxt if self.t_drawtype in ('polygon', 'path', 'beziercurve'): if len(cxt.points) > 0: cxt.points.pop() return True def is_drawing(self): return self._draw_obj is not None def enable_draw(self, tf): self.candraw = tf def set_drawcolor(self, colorname): self.t_drawparams['color'] = colorname def set_drawtype(self, drawtype, **drawparams): drawtype = drawtype.lower() assert drawtype in self.drawtypes, \ ValueError("Bad drawing type '%s': must be one of %s" % ( drawtype, self.drawtypes)) self.t_drawtype = drawtype self.t_drawparams = drawparams.copy() def get_drawtypes(self): return self.drawtypes def get_drawtype(self): return self.t_drawtype def get_draw_class(self, drawtype): drawtype = drawtype.lower() klass = self.draw_dict[drawtype] return klass def get_drawparams(self): return self.t_drawparams.copy() def process_drawing(self): self._process_time = time.time() #viewer.redraw(whence=3) #self.redraw(whence=3) self.update_canvas() def register_canvas_type(self, name, klass): drawtype = name.lower() self.draw_dict[drawtype] = klass if not drawtype in self.drawtypes: self.drawtypes.append(drawtype) self.drawtypes.sort() ##### EDITING LOGIC ##### def get_edit_object(self): return self._edit_obj def is_editing(self): return self.get_edit_obj() is not None def enable_edit(self, tf): self.canedit = tf def _edit_update(self, data_x, data_y, viewer): if (not self.canedit) or (self._cp_index is None): return False x, y = self._edit_obj.crdmap.data_to(data_x, data_y) if self._cp_index < 0: if self.easymove: ## self._edit_obj.move_to(x - self._start_x, ## y - self._start_y) self._edit_obj.set_edit_point(0, (x - self._start_x, y - self._start_y)) else: # special hack for objects that have rot_deg attribute if hasattr(self._edit_obj, 'rot_deg') and (self._cp_index > 0): rot_deg = - self._edit_obj.rot_deg xoff, yoff = self._edit_obj.get_center_pt() x, y = self._edit_obj.crdmap.rotate_pt(x, y, rot_deg, xoff=xoff, yoff=yoff) self._edit_obj.set_edit_point(self._cp_index, (x, y)) #self._edit_obj.sync_state() if time.time() - self._process_time > self._delta_time: self.process_drawing() return True def _is_editable(self, obj, x, y, is_inside): return is_inside and obj.editable def _prepare_to_move(self, obj, data_x, data_y): #print(("moving an object", obj.editable)) self.edit_select(obj) self._cp_index = -1 ref_x, ref_y = self._edit_obj.get_reference_pt() x, y = obj.crdmap.data_to(data_x, data_y) self._start_x, self._start_y = x - ref_x, y - ref_y #print(("end moving an object", obj.editable)) def edit_start(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False self._edit_tmp = self._edit_obj self._edit_status = False self._cp_index = None #shift_held = 'shift' in event.modifiers shift_held = False selects = self.get_selected() if len(selects) == 0: #print("no objects already selected") # <-- no objects already selected # check for objects at this location #print("getting items") objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("items: %s" % (str(objs))) if len(objs) == 0: # <-- no objects under cursor return False # pick top object obj = objs[-1] self._prepare_to_move(obj, data_x, data_y) else: self._edit_status = True # Ugh. Check each selected object's control points # for a match contains = [] for obj in selects: #print("editing: checking for cp") #edit_pts = self._edit_obj.get_edit_points() edit_pts = list(map(lambda pt: obj.crdmap.to_data(*pt), obj.get_edit_points())) #print((self._edit_obj, edit_pts)) i = obj.get_pt(viewer, edit_pts, data_x, data_y, obj.cap_radius) #print(('got point', i)) if i is not None: #print("editing cp #%d" % (i)) # editing a control point from an existing object self._edit_obj = obj self._cp_index = i self._edit_update(data_x, data_y, viewer) return True if obj.contains(data_x, data_y): contains.append(obj) # <-- no control points match, is there an object that contains # this point? if len(contains) > 0: # TODO?: make a compound object of contains and move it? obj = contains[-1] if self.is_selected(obj) and shift_held: # deselecting object self.select_remove(obj) else: self._prepare_to_move(obj, data_x, data_y) ## Compound = self.get_draw_class('compoundobject') ## c_obj = Compound(*self.get_selected()) ## c_obj.inherit_from(obj) ## self._prepare_to_move(c_obj, data_x, data_y) else: # <-- user clicked outside any selected item's control pt # and outside any selected item if not shift_held: self.clear_selected() # see now if there is an unselected item at this location objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("new items: %s" % (str(objs))) if len(objs) > 0: # pick top object obj = objs[-1] #print(("top object", obj)) if self.num_selected() > 0: #print("there are previously selected items") # if there are already some selected items, then # add this object to the selection, make a compound # object self.edit_select(obj) Compound = self.get_draw_class('compoundobject') c_obj = Compound(*self.get_selected()) c_obj.inherit_from(obj) self._prepare_to_move(c_obj, data_x, data_y) else: # otherwise just start over with this new object #print(("starting over")) self._prepare_to_move(obj, data_x, data_y) self.process_drawing() return True def edit_stop(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False if (self._edit_tmp != self._edit_obj) or ( (self._edit_obj is not None) and (self._edit_status != self.is_selected(self._edit_obj))): # <-- editing status has changed #print("making edit-select callback") self.make_callback('edit-select', self._edit_obj) if (self._edit_obj is not None) and (self._cp_index is not None): # <-- an object has been edited self._edit_update(data_x, data_y, viewer) self._cp_index = None self.make_callback('edit-event', self._edit_obj) return True def edit_motion(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False if (self._edit_obj is not None) and (self._cp_index is not None): self._edit_update(data_x, data_y, viewer) return True return False def edit_poly_add(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False obj = self._edit_obj if (obj is not None) and self.is_selected(obj) and \ (obj.kind in ('polygon', 'path')): self.logger.debug("checking points") # determine which line we are adding a point to points = list(obj.get_points()) if obj.kind == 'polygon': points = points + [points[0]] x0, y0 = obj.crdmap.to_data(*points[0]) insert = None for i in range(1, len(points[1:])): x1, y1 = obj.crdmap.to_data(*points[i]) self.logger.debug("checking line %d" % (i)) if obj.within_line(viewer, data_x, data_y, x0, y0, x1, y1, 8): insert = i break x0, y0 = x1, y1 if insert is not None: self.logger.debug("inserting point") # Point near a line x, y = obj.crdmap.data_to(data_x, data_y) points.insert(insert, (x, y)) obj.points = points self.process_drawing() else: self.logger.debug("cursor not near a line") return True def edit_poly_delete(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False obj = self._edit_obj if (obj is not None) and self.is_selected(obj) and \ (obj.kind in ('polygon', 'path')): self.logger.debug("checking points") # determine which point we are deleting points = list(obj.get_points()) delete = None for i in range(len(points)): x1, y1 = obj.crdmap.to_data(*points[i]) self.logger.debug("checking vertex %d" % (i)) if obj.within_radius(viewer, data_x, data_y, x1, y1, 8): delete = i break if delete is not None: self.logger.debug("deleting point") points.pop(delete) obj.points = points self.process_drawing() else: self.logger.debug("cursor not near a point") return True def edit_rotate(self, delta_deg, viewer): if self._edit_obj is None: return False self._edit_obj.rotate_by(delta_deg) self.process_drawing() self.make_callback('edit-event', self._edit_obj) return True def _edit_rotate_cb(self, canvas, event, viewer, msg=True): if not self.canedit or (viewer != event.viewer): return False bd = viewer.get_bindings() amount = event.amount if bd.get_direction(event.direction) == 'down': amount = - amount return self.edit_rotate(amount) def edit_scale(self, delta_x, delta_y, viewer): if self._edit_obj is None: return False self._edit_obj.scale_by(delta_x, delta_y) self.process_drawing() self.make_callback('edit-event', self._edit_obj) return True def _edit_scale_cb(self, canvas, event, viewer, msg=True): if not self.canedit or (viewer != event.viewer): return False bd = viewer.get_bindings() if bd.get_direction(event.direction) == 'down': amount = 0.9 else: amount = 1.1 return self.edit_scale(amount, amount) def edit_delete(self): if (self._edit_obj is not None) and self.is_selected(self._edit_obj): self.select_remove(self._edit_obj) obj, self._edit_obj = self._edit_obj, None self.deleteObject(obj) self.make_callback('edit-event', self._edit_obj) return True def edit_delete_cb(self, canvas, event, data_x, data_y, viewer): if not self.canedit or (viewer != event.viewer): return False return self.edit_delete() def edit_select(self, newobj): if not self.canedit: return False if not self.multi_select_ok: self.clear_selected() # add new object to selection self.select_add(newobj) self._edit_obj = newobj return True ##### SELECTION LOGIC ##### def _is_selectable(self, obj, x, y, is_inside): return is_inside and obj.editable #return is_inside def is_selected(self, obj): return obj in self._selected def get_selected(self): return self._selected def num_selected(self): return len(self._selected) def clear_selected(self): self._selected = [] def select_remove(self, obj): try: self._selected.remove(obj) except: pass def select_add(self, obj): if obj not in self._selected: self._selected.append(obj) def select_stop(self, canvas, button, data_x, data_y, viewer): #print("getting items") objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_selectable) if len(objs) == 0: # no objects return False # pick top object obj = objs[-1] if obj not in self._selected: self._selected.append(obj) else: self._selected.remove(obj) obj = None self.logger.debug("selected: %s" % (str(self._selected))) self.process_drawing() #self.make_callback('edit-select', obj, self._selected) return True def group_selection(self): Compound = self.get_draw_class('compoundobject') c_obj = Compound(self._selected) self._selected = [ comp_obj ] # The canvas drawing def draw(self, viewer): # Draw everything else as usual super(DrawingMixin, self).draw(viewer) # Draw our current drawing object, if any if self._draw_obj: self._draw_obj.draw(viewer) # Draw control points on edited objects # TODO: there is a problem if the object has been removed from # the canvas but not removed from the selection--we still end # up drawing the control points for it selected = self.get_selected() if len(selected) > 0: for obj in selected: cr = viewer.renderer.setup_cr(obj) obj.draw_edit(cr, viewer) ### NON-PEP8 EQUIVALENTS -- TO BE DEPRECATED ### setSurface = set_surface getSurface = get_surface getDrawClass = get_draw_class
def find_executable_obs_cb(self, widget): self.tree1.clear() self.view.update_pending() # get a handle to the control panel plugin cp = self.view.get_plugin('cp') use_db = cp.w.use_qdb.get_state() cp.update_scheduler(use_db=use_db) sdlr = self.model.get_scheduler() date_s = self.w.date.get_text().strip() time_b = self.w.start_time.get_text().strip() try: time_start = sdlr.site.get_date("%s %s" % (date_s, time_b)) except Exception as e: errmsg = 'Error parsing start date/time:: {}\n'.format(str(e)) errmsg += "\n".join([e.__class__.__name__, str(e)]) self.logger.error(errmsg) self.controller.gui_do(self.controller.show_error, errmsg, raisetab=True) return # get the string for the date of observation in HST, which is what # is used in the Schedule table if time_start.hour < 9: date_obs_local = (time_start - timedelta(hours=10)).strftime("%Y-%m-%d") else: date_obs_local = time_start.strftime("%Y-%m-%d") self.logger.info("observation date (local) is '{}'".format(date_obs_local)) # find the record in the schedule table that matches our date; # we need to get the list of filters and so on from it rec = None for _rec in sdlr.schedule_recs: if _rec.date == date_obs_local: rec = _rec break if rec is None: errmsg = "Can't find a record in the Schedule table matching '{}'".format(date_obs_local) self.logger.error(errmsg) self.controller.gui_do(self.controller.show_error, errmsg, raisetab=True) return len_s = self.w.len_time.get_text().strip() slot_length = max(0.0, float(len_s) * 60.0) data = Bunch(rec.data) # override some items from Schedule table data.cur_filter = self.w.filter.get_text().strip() data.cur_az = float(self.w.az.get_text().strip()) data.cur_el = float(self.w.el.get_text().strip()) data.seeing = float(self.w.seeing.get_text().strip()) data.transparency = float(self.w.trans.get_text().strip()) slot = entity.Slot(time_start, slot_length, data=data) self.slot = slot good, bad = sdlr.find_executable_obs(slot) tree_dict = OrderedDict() # Table header with units columns = [('Best', 'index'), ('Program', 'program'), ('OB Code', 'ob_code'), ('Priority', 'priority'), ('Grade', 'grade'), ('Prep', 'prep'), ('On Source', 'time'), ('Target', 'target'), ('Filter', 'filter'), ('Delay', 'delay'), ('Reason', 'reason')] self.tree1.setup_table(columns, 1, 'index') # This is to get around table widget not sorting numbers properly i_fmt = '{{0:0{0}d}}'.format(len(str(len(good)))) # Table contents i = 1 for rec in good: i_str = i_fmt.format(i) bnch = Bunch(index=i_str, program=rec.ob.program.proposal, ob_code=rec.ob.name, priority=rec.ob.priority, grade=rec.ob.program.grade, prep="%.2f" % (rec.prep_sec / 60.0), time="%.2f" % (rec.ob.total_time / 60.0), target=rec.ob.target.name, filter=rec.ob.inscfg.filter, delay=rec.delay_sec / 60.0, _group=good, _rec=rec, reason='OK') tree_dict[i_str] = bnch i += 1 if self.show_bad: for rec in bad: i_str = i_fmt.format(i) bnch = Bunch(index=i_str, program=rec.ob.program.proposal, ob_code=rec.ob.name, priority=rec.ob.priority, grade=rec.ob.program.grade, prep="%.2f" % (rec.prep_sec / 60.0), time="%.2f" % (rec.ob.total_time / 60.0), target=rec.ob.target.name, filter=rec.ob.inscfg.filter, delay=rec.delay_sec / 60.0, _group=bad, _rec=rec, reason='NG: ' + rec.reason) tree_dict[i_str] = bnch i += 1 self.tree1.set_tree(tree_dict) self.tree1.set_optimal_column_widths()
dict(row=['ws', dict(name='channels', group=1)], stretch=1) ], [ 'ws', dict(name='right', width=350, group=2), # (tabname, layout), ... [("Dialogs", ['ws', dict(name='dialogs', group=2)])] ], ], stretch=1), dict(row=['hbox', dict(name='status')], stretch=0), ] ] global_plugins = [ Bunch(module='Pan', tab='_pan', ws='uleft', raisekey=None), Bunch(module='Info', tab='_info', ws='lleft', raisekey=None), Bunch(module='Header', tab='Header', ws='left', raisekey='H'), Bunch(module='Zoom', tab='Zoom', ws='left', raisekey='Z'), Bunch(module='Thumbs', tab='Thumbs', ws='right', raisekey='T'), Bunch(module='Contents', tab='Contents', ws='right', raisekey='c'), Bunch(module='WBrowser', tab='Help', ws='channels', raisekey='?', start=False), Bunch(module='Errors', tab='Errors', ws='right', start=True), Bunch(module='RC', tab='RC', ws='right', start=False), Bunch(module='SAMP', tab='SAMP', ws='right', start=False), Bunch(module='IRAF', tab='IRAF', ws='right', start=False), Bunch(module='Log', tab='Log', ws='right', start=False),
def setup_SlitWavelength(): return Bunch(path=os.path.join(os.path.split(__file__)[0], 'ginga_plugins.py'), module='ginga_plugins', klass='SlitWavelength', ptype='global', workspace='right', start=False, category='PypeIt', menu='SlitWavelength', tab='SlitWavelength')
def update_scheduler(self, use_db=False, ignore_pgm_skip_flag=False): sdlr = self.model.get_scheduler() try: if use_db: if self.qdb is None: self.connect_qdb() sdlr.set_weights(self.weights_qf.weights) sdlr.set_schedule_info(self.schedule_qf.schedule_info) pgms = self.programs_qf.programs_info sdlr.set_programs_info(pgms, ignore_pgm_skip_flag) self.logger.info('list of programs to be scheduled %s' % sdlr.programs.keys()) # TODO: this maybe should be done in the Model ob_keys = set([]) ob_dict = {} propnames = list(self.programs_qf.programs_info.keys()) okprops = [] # Note: if the ignore_pgm_skip_flag is set to True, then # we don't pay attention to the "skip" flag in the # Programs sheet and thus consider all OB's in all # Programs. Otherwise, we do pay attention to the "skip" # flag and ignore all OB's in "skipped" programs. for propname in propnames: if not ignore_pgm_skip_flag and pgms[propname].skip: self.logger.info( 'skip flag for program %s is set - skipping all OB in this program' % propname) continue if propname not in self.ob_info: # If we haven't read these OBs in already, read them now if use_db: oblist = list(self.qq.get_obs_by_proposal(propname)) else: if propname not in self.ob_qf_dict: if not self.load_program(propname): continue oblist = self.ob_qf_dict[propname].obs_info # cache the information about the OBs so we don't have # to reconstruct it over and over _key_lst = [(propname, ob.name) for ob in oblist] _key_dct = dict(zip(_key_lst, oblist)) info = Bunch(oblist=oblist, obkeys=_key_lst, obdict=_key_dct) self.ob_info[propname] = info info = self.ob_info[propname] okprops.append(propname) ob_keys = ob_keys.union(set(info.obkeys)) ob_dict.update(info.obdict) self.logger.info("%s OBs after excluding skipped programs." % (len(ob_keys))) do_not_execute = set([]) props = {} # Remove keys for OBs that are already executed if use_db: self.logger.info("getting do not execute OB info") dne_obs, props = self.qq.get_do_not_execute_ob_info(okprops) do_not_execute = set(dne_obs) elif self.model.completed_obs is not None: do_not_execute = set(list(self.model.completed_obs.keys())) # Painful reconstruction of time already accumulated running the # programs for executed OBs. Needed to inform scheduler so that # it can correctly calculate when to stop allocating OBs for a # program that has reached its time limit. props = {} for ob_key in do_not_execute: (propid, obcode) = ob_key[:2] bnch = props.setdefault(propid, Bunch(obcount=0, sched_time=0.0)) info = self.model.completed_obs[ob_key] bnch.sched_time += info['acct_time'] bnch.obcount += 1 sdlr.set_apriori_program_info(props) ob_keys -= do_not_execute self.logger.info("%s OBs after removing executed OBs." % (len(ob_keys))) # for a deterministic result ob_keys = list(ob_keys) ob_keys.sort() # Now turn the keys back into actual OB list sdlr_oblist = [ob_dict[key] for key in ob_keys] # TODO: only needed if we ADD or REMOVE programs sdlr.set_oblist_info(sdlr_oblist) except Exception as e: errmsg = 'Error storing into scheduler: {}\n'.format(str(e)) #self.logger.error("Error storing into scheduler: %s" % (str(e))) errmsg += "\n".join([e.__class__.__name__, str(e)]) self.logger.error(errmsg) self.controller.gui_do(self.controller.show_error, errmsg, raisetab=True) raise e self.logger.info("scheduler initialized")
width=400, height=-1, group=2), # (tabname, layout), ... [("Dialogs", ['ws', dict(name='dialogs', wstype='tabs', group=2) ] )] ], ], stretch=1), dict(row=['ws', dict(name='toolbar', wstype='stack', height=40, group=2)], stretch=0), dict(row=['hbox', dict(name='status')], stretch=0), ]] global_plugins = [ Bunch(module='Operations', workspace='operations', start=True, hidden=True, category='system'), Bunch(module='Toolbar', workspace='toolbar', start=True, hidden=True, category='system'), Bunch(module='Pan', workspace='uleft', start=True, hidden=True, category='system'), Bunch(module='Info', tab='Synopsis', workspace='lleft', start=True, hidden=True, category='system'), Bunch(module='Header', tab='Header', workspace='left', start=True, hidden=True, category='system'), Bunch(module='Zoom', tab='Zoom', workspace='left', start=True, hidden=True, category='system'), Bunch(module='Thumbs', tab='Thumbs', workspace='right', start=True, hidden=True, category='system'), Bunch(module='Contents', tab='Contents', workspace='right', start=True, hidden=True, category='system'), Bunch(module='Colorbar', workspace='cbar', start=True,
def add_local_plugin(self, module_name, ws_name, pfx=None): self.local_plugins.append( Bunch(module=module_name, ws=ws_name, pfx=pfx))
def add_local_plugin(self, module_name, ws_name, path=None, klass=None, pfx=None, category=None): self.add_local_plugin_spec( Bunch(module=module_name, workspace=ws_name, category=category, path=path, klass=klass, pfx=pfx))
def get_ginga_plugins(op_type): """Obtain relevant custom plugins from ``stginga`` and ``wss_tools`` for the given QUIP operation type. Parameters ---------- op_type : {'normalmode', 'segment_id', 'thumbnail'} QUIP operation type. Normal mode covers anything that is neither SEGMENT_ID nor THUMBNAIL. Returns ------- global_plugins : list List of custom Ginga global plugins to load. local_plugins : list List of custom Ginga local plugins to load. """ stg_pfx = 'stginga.plugins' wss_pfx = 'wss_tools.quip.plugins' global_plugins = [ Bunch(module='AboutQUIP', tab='AboutQUIP', workspace='left', category='Custom', ptype='global', pfx=wss_pfx) ] if op_type == 'segment_id': local_plugins = [] # Add special plugin for segment ID annotations global_plugins += [ Bunch(module='SegIDHelper', tab='SegIDHelper', workspace='left', category='Custom', ptype='global', pfx=wss_pfx) ] elif op_type == 'thumbnail': local_plugins = [ Bunch(module='MosaicAuto', workspace='dialogs', category='Custom', ptype='local', pfx=wss_pfx) ] else: # normalmode global_plugins += [ Bunch(module='SaveQUIP', tab='SaveQUIP', workspace='right', category='Custom', ptype='global', pfx=wss_pfx) ] local_plugins = [ Bunch(module='BackgroundSub', workspace='dialogs', category='Custom', ptype='local', pfx=stg_pfx), Bunch(module='BadPixCorr', workspace='dialogs', category='Custom', ptype='local', pfx=stg_pfx), Bunch(module='DQInspect', workspace='dialogs', category='Custom', ptype='local', pfx=stg_pfx), Bunch(module='SNRCalc', workspace='dialogs', category='Custom', ptype='local', pfx=wss_pfx) ] return global_plugins, local_plugins
class DrawingMixin(object): """The DrawingMixin is a mixin class that adds drawing capability for some of the basic CanvasObject-derived types. The set_surface method is used to associate a ImageViewCanvas object for layering on. """ def __init__(self): assert isinstance(self, CanvasMixin), "Missing CanvasMixin class" from .CanvasObject import drawCatalog # For interactive drawing self.candraw = False self.draw_dict = drawCatalog # canvas objects which we know how to draw have an "idraw" # class method self.drawtypes = [ key for key in self.draw_dict.keys() if hasattr(self.draw_dict[key], 'idraw') ] self.drawtypes.sort() self.t_drawtype = 'point' self.t_drawparams = {} # holds the drawing context self._draw_cxt = None # For interactive editing self.canedit = False # Set to False to disable drag moves except from move control pt self.easymove = True self._start_x = 0 self._start_y = 0 self._cp_index = None self._edit_obj = None self._edit_status = False self._edit_detail = {} self._pick_cur_obj = None # For modes self._mode = 'draw' self._mode_tbl = Bunch() self.add_draw_mode(None) self.add_draw_mode('draw', down=self.draw_start, move=self.draw_motion, up=self.draw_stop, poly_add=self.draw_poly_add, poly_delete=self.draw_poly_delete) self.add_draw_mode('edit', down=self.edit_start, move=self.edit_motion, up=self.edit_stop, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) self.add_draw_mode('pick', down=self.pick_start, move=self.pick_motion, up=self.pick_stop, hover=self.pick_hover, poly_add=self.edit_poly_add, poly_delete=self.edit_poly_delete) # For selection self._selected = [] self.multi_select_ok = False # this controls whether an object is automatically selected for # editing immediately after being drawn self.edit_follows_draw = False self._process_time = 0.0 # time delta threshold for deciding whether to update the image self._delta_time = 0.020 self._draw_obj = None # NOTE: must be mixed in with a Callback.Callbacks for name in ('draw-event', 'draw-down', 'draw-move', 'draw-up', 'cursor-down', 'cursor-up', 'cursor-move', 'draw-scroll', 'keydown-poly_add', 'keydown-poly_del', 'keydown-edit_del', 'edit-event', 'edit-select', 'drag-drop', 'cursor-changed'): self.enable_callback(name) def set_surface(self, viewer): self.viewer = viewer # Register this canvas for events of interest. # Assumes we are mixed in with a canvas canvas = self # for legacy drawing via draw mode in Bindmap canvas.add_callback('draw-down', self.draw_start, viewer) canvas.add_callback('draw-move', self.draw_motion, viewer) canvas.add_callback('draw-up', self.draw_stop, viewer) canvas.add_callback('key-press', self._draw_key, 'key', viewer) canvas.add_callback('keydown-poly_add', self._draw_op, 'poly_add', viewer) canvas.add_callback('keydown-poly_del', self._draw_op, 'poly_delete', viewer) canvas.add_callback('keydown-edit_del', self.edit_delete_cb, viewer) #canvas.add_callback('draw-scroll', self._edit_rotate_cb, viewer) #canvas.add_callback('draw-scroll', self._edit_scale_cb, viewer) def register_for_cursor_drawing(self, viewer): canvas = self canvas.add_callback('cursor-down', self._draw_op, 'down', viewer) canvas.add_callback('cursor-move', self._draw_op, 'move', viewer) canvas.add_callback('cursor-up', self._draw_op, 'up', viewer) canvas.set_callback('none-move', self._draw_op, 'hover', viewer) ##### MODE LOGIC ##### def add_draw_mode(self, name, **kwargs): try: bnch = self._mode_tbl[name] except KeyError: bnch = Bunch(name=name, **kwargs) self._mode_tbl[name] = bnch return bnch def set_draw_mode(self, mode): if not mode in self._mode_tbl: modes = list(self._mode_tbl.keys()) raise ValueError("mode must be one of: %s" % (str(modes))) self._mode = mode if mode != 'edit': self.clear_selected() self.update_canvas() def get_draw_mode(self): return self._mode def _draw_op(self, canvas, event, data_x, data_y, opn, viewer): if viewer != event.viewer: return False mode = self._mode # Hack to handle legacy drawing using draw mode in Bindmap if self.is_drawing(): mode = 'draw' try: method = self._mode_tbl[mode][opn] except KeyError: return False if method is not None: return method(canvas, event, data_x, data_y, viewer) return False def _draw_key(self, canvas, keyname, opn, viewer): # synthesize a KeyEvent # TODO: this is hacky--see if we can rethink how this is handled # so that we get passed an event similar to _draw_op() last_x, last_y = viewer.get_last_data_xy() event = KeyEvent(key=keyname, state='down', mode=self._mode, modifiers=[], viewer=viewer, data_x=last_x, data_y=last_y) return self._draw_op(canvas, event, last_x, last_y, opn, viewer) ##### DRAWING LOGIC ##### def _draw_update(self, data_x, data_y, cxt, force_update=False): obj = None # update the context with current position x, y = cxt.crdmap.data_to(data_x, data_y) cxt.setvals(x=x, y=y, data_x=data_x, data_y=data_y) draw_class = cxt.draw_class if draw_class is None: return False obj = draw_class.idraw(self, cxt) # update display every delta_time secs if obj is not None: obj.initialize(self, cxt.viewer, self.logger) self._draw_obj = obj if force_update or (time.time() - self._process_time > self._delta_time): self.process_drawing() return True def draw_start(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_obj = None self.clear_selected() # get the drawing coordinate type (default 'data') crdtype = self.t_drawparams.get('coord', 'data') crdmap = viewer.get_coordmap(crdtype) x, y = crdmap.data_to(data_x, data_y) klass = self.draw_dict.get(self.t_drawtype, None) # create the drawing context self._draw_cxt = Bunch(start_x=x, start_y=y, points=[(x, y)], x=x, y=y, data_x=data_x, data_y=data_y, drawparams=self.t_drawparams, crdmap=crdmap, viewer=viewer, draw_class=klass, logger=self.logger) self._draw_update(data_x, data_y, self._draw_cxt, force_update=True) return True def draw_stop(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_update(data_x, data_y, self._draw_cxt) obj, self._draw_obj = self._draw_obj, None if obj is not None: objtag = self.add(obj) self.make_callback('draw-event', objtag) if self.edit_follows_draw: #self.set_draw_mode('edit') self.edit_select(obj) self.make_callback('edit-select', self._edit_obj) return True else: self.process_drawing() def draw_motion(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False self._draw_update(data_x, data_y, self._draw_cxt) return True def draw_poly_add(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False cxt = self._draw_cxt if self.t_drawtype in ('polygon', 'freepolygon', 'path', 'freepath'): x, y = cxt.crdmap.data_to(data_x, data_y) cxt.points.append((x, y)) elif self.t_drawtype == 'beziercurve' and len(cxt.points) < 3: x, y = cxt.crdmap.data_to(data_x, data_y) cxt.points.append((x, y)) self._draw_update(data_x, data_y, cxt, force_update=True) return True def draw_poly_delete(self, canvas, event, data_x, data_y, viewer): if not self.candraw: return False cxt = self._draw_cxt if self.t_drawtype in ('polygon', 'freepolygon', 'path', 'freepath', 'beziercurve'): if len(cxt.points) > 0: cxt.points.pop() self._draw_update(data_x, data_y, cxt, force_update=True) return True def is_drawing(self): return self._draw_obj is not None def enable_draw(self, tf): self.candraw = tf def set_drawcolor(self, colorname): self.t_drawparams['color'] = colorname def set_drawtype(self, drawtype, **drawparams): if drawtype is not None: drawtype = drawtype.lower() assert drawtype in self.drawtypes, \ ValueError("Bad drawing type '%s': must be one of %s" % ( drawtype, self.drawtypes)) self.t_drawtype = drawtype self.t_drawparams = drawparams.copy() def get_drawtypes(self): return self.drawtypes def get_drawtype(self): return self.t_drawtype def get_draw_class(self, drawtype): drawtype = drawtype.lower() klass = self.draw_dict[drawtype] return klass def get_drawparams(self): return self.t_drawparams.copy() def process_drawing(self): self._process_time = time.time() #self.redraw(whence=3) self.update_canvas() def register_canvas_type(self, name, klass): drawtype = name.lower() self.draw_dict[drawtype] = klass if not drawtype in self.drawtypes: self.drawtypes.append(drawtype) self.drawtypes.sort() ##### EDITING LOGIC ##### def get_edit_object(self): return self._edit_obj def is_editing(self): return self.get_edit_obj() is not None def enable_edit(self, tf): self.canedit = tf def _rot_xlate(self, obj, data_x, data_y): # translate point back into non-rotated form rot_deg = - obj.rot_deg xoff, yoff = obj.get_center_pt() data_x, data_y = trcalc.rotate_pt(data_x, data_y, rot_deg, xoff=xoff, yoff=yoff) return data_x, data_y def _edit_update(self, data_x, data_y, viewer): if (not self.canedit) or (self._cp_index is None): return False x, y = data_x, data_y if self._cp_index < 0: if self.easymove: self._edit_obj.set_edit_point(0, (x - self._start_x, y - self._start_y), self._edit_detail) else: # special hack for objects that have rot_deg attribute if hasattr(self._edit_obj, 'rot_deg') and (self._cp_index > 0): x, y = self._rot_xlate(self._edit_obj, x, y) self._edit_obj.set_edit_point(self._cp_index, (x, y), self._edit_detail) #self._edit_obj.sync_state() if time.time() - self._process_time > self._delta_time: self.process_drawing() return True def _is_editable(self, obj, x, y, is_inside): return is_inside and obj.editable def _prepare_to_move(self, obj, data_x, data_y): #print(("moving an object", obj.editable)) self.edit_select(obj) self._cp_index = -1 ref_x, ref_y = self._edit_obj.get_reference_pt() self._start_x, self._start_y = data_x - ref_x, data_y - ref_y #print(("end moving an object", obj.editable)) def edit_start(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False self._edit_tmp = self._edit_obj self._edit_status = False self._edit_detail = Bunch() self._cp_index = None #shift_held = 'shift' in event.modifiers shift_held = False selects = self.get_selected() if len(selects) == 0: #print("no objects already selected") # <-- no objects already selected # check for objects at this location #print("getting items") objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("items: %s" % (str(objs))) if len(objs) == 0: # <-- no objects under cursor return False # pick top object obj = objs[-1] self._prepare_to_move(obj, data_x, data_y) else: self._edit_status = True # Ugh. Check each selected object's control points # for a match contains = [] for obj in selects: #print("editing: checking for cp") edit_pts = obj.get_edit_points(viewer) #print((self._edit_obj, edit_pts)) i = obj.get_pt(viewer, edit_pts, data_x, data_y, obj.cap_radius) #print(('got point', i)) if i is not None: #print("editing cp #%d" % (i)) # editing a control point from an existing object self._edit_obj = obj self._cp_index = i if hasattr(obj, 'rot_deg'): x, y = self._rot_xlate(self._edit_obj, data_x, data_y) else: x, y = data_x, data_y self._edit_detail.start_pos = (x, y) obj.setup_edit(self._edit_detail) self._edit_update(data_x, data_y, viewer) return True ## if obj.contains(data_x, data_y): ## contains.append(obj) # update: check if objects bbox contains this point x1, y1, x2, y2 = obj.get_llur() if (x1 <= data_x <= x2) and (y1 <= data_y <= y2): contains.append(obj) # <-- no control points match, is there an object that contains # this point? if len(contains) > 0: # TODO?: make a compound object of contains and move it? obj = contains[-1] if self.is_selected(obj) and shift_held: # deselecting object self.select_remove(obj) else: self._prepare_to_move(obj, data_x, data_y) ## Compound = self.get_draw_class('compoundobject') ## c_obj = Compound(*self.get_selected()) ## c_obj.inherit_from(obj) ## self._prepare_to_move(c_obj, data_x, data_y) else: # <-- user clicked outside any selected item's control pt # and outside any selected item if not shift_held: self.clear_selected() # see now if there is an unselected item at this location objs = canvas.select_items_at(viewer, data_x, data_y, test=self._is_editable) #print("new items: %s" % (str(objs))) if len(objs) > 0: # pick top object obj = objs[-1] #print(("top object", obj)) if self.num_selected() > 0: #print("there are previously selected items") # if there are already some selected items, then # add this object to the selection, make a compound # object self.edit_select(obj) Compound = self.get_draw_class('compoundobject') c_obj = Compound(*self.get_selected()) c_obj.inherit_from(obj) self._prepare_to_move(c_obj, data_x, data_y) else: # otherwise just start over with this new object #print(("starting over")) self._prepare_to_move(obj, data_x, data_y) self.process_drawing() return True def edit_stop(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False if (self._edit_tmp != self._edit_obj) or ( (self._edit_obj is not None) and (self._edit_status != self.is_selected(self._edit_obj))): # <-- editing status has changed #print("making edit-select callback") self.make_callback('edit-select', self._edit_obj) if (self._edit_obj is not None) and (self._cp_index is not None): # <-- an object has been edited self._edit_update(data_x, data_y, viewer) self._cp_index = None self.make_callback('edit-event', self._edit_obj) self._edit_obj.make_callback('edited') return True def edit_motion(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False if (self._edit_obj is not None) and (self._cp_index is not None): self._edit_update(data_x, data_y, viewer) return True return False def edit_poly_add(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False obj = self._edit_obj if (obj is not None) and self.is_selected(obj) and \ (obj.kind in ('polygon', 'path')): self.logger.debug("checking points") # determine which line we are adding a point to points = list(obj.get_data_points()) if obj.kind == 'polygon': points = points + [points[0]] x0, y0 = points[0] insert = None for i in range(1, len(points[1:])+1): x1, y1 = points[i] self.logger.debug("checking line %d" % (i)) if obj.within_line(viewer, data_x, data_y, x0, y0, x1, y1, 8): insert = i break x0, y0 = x1, y1 if insert is not None: self.logger.debug("inserting point") # Point near a line pt = obj.crdmap.data_to(data_x, data_y) obj.insert_pt(insert, pt) self.process_drawing() else: self.logger.debug("cursor not near a line") return True def edit_poly_delete(self, canvas, event, data_x, data_y, viewer): if not self.canedit: return False obj = self._edit_obj if (obj is not None) and self.is_selected(obj) and \ (obj.kind in ('polygon', 'path')): self.logger.debug("checking points") # determine which point we are deleting points = list(obj.get_data_points()) delete = None for i in range(len(points)): x1, y1 = points[i] self.logger.debug("checking vertex %d" % (i)) if obj.within_radius(viewer, data_x, data_y, x1, y1, 8): delete = i break if delete is not None: self.logger.debug("deleting point") obj.delete_pt(delete) self.process_drawing() else: self.logger.debug("cursor not near a point") return True def edit_rotate(self, delta_deg, viewer): if self._edit_obj is None: return False self._edit_obj.rotate_by(delta_deg) self.process_drawing() self.make_callback('edit-event', self._edit_obj) return True def _edit_rotate_cb(self, canvas, event, viewer, msg=True): if not self.canedit or (viewer != event.viewer): return False bd = viewer.get_bindings() amount = event.amount if bd.get_direction(event.direction) == 'down': amount = - amount return self.edit_rotate(amount) def edit_scale(self, delta_x, delta_y, viewer): if self._edit_obj is None: return False self._edit_obj.scale_by(delta_x, delta_y) self.process_drawing() self.make_callback('edit-event', self._edit_obj) return True def _edit_scale_cb(self, canvas, event, viewer, msg=True): if not self.canedit or (viewer != event.viewer): return False bd = viewer.get_bindings() if bd.get_direction(event.direction) == 'down': amount = 0.9 else: amount = 1.1 return self.edit_scale(amount, amount) def edit_delete(self): if (self._edit_obj is not None) and self.is_selected(self._edit_obj): self.select_remove(self._edit_obj) obj, self._edit_obj = self._edit_obj, None self.delete_object(obj) self.make_callback('edit-event', self._edit_obj) return True def edit_delete_cb(self, canvas, event, data_x, data_y, viewer): if not self.canedit or (viewer != event.viewer): return False return self.edit_delete() def edit_select(self, newobj): if not self.canedit: return False if not self.multi_select_ok: self.clear_selected() # add new object to selection self.select_add(newobj) self._edit_obj = newobj return True ##### SELECTION LOGIC ##### def _is_selectable(self, obj, x, y, is_inside): return is_inside and obj.editable #return is_inside def is_selected(self, obj): return obj in self._selected def get_selected(self): return self._selected def num_selected(self): return len(self._selected) def clear_selected(self): self._selected = [] def select_remove(self, obj): try: self._selected.remove(obj) except: pass def select_add(self, obj): if obj not in self._selected: self._selected.append(obj) ##### PICK LOGIC ##### def _do_pick(self, canvas, event, data_x, data_y, cb_name, viewer): # check for objects at this location objs = canvas.select_items_at(viewer, data_x, data_y) if len(objs) == 0: # <-- no objects under cursor if self._pick_cur_obj is not None: # leaving an object that we were in--make pick-leave cb obj, self._pick_cur_obj = self._pick_cur_obj, None pt = obj.crdmap.data_to(data_x, data_y) obj.make_callback('pick-leave', canvas, event, pt) return False # pick top object obj = objs[-1] self.logger.debug("%s event in %s obj at x, y = %d, %d" % ( cb_name, obj.kind, data_x, data_y)) # get coordinates in native form for this object pt = obj.crdmap.data_to(data_x, data_y) if self._pick_cur_obj is None: # entering a new object--make pick-enter cb self._pick_cur_obj = obj obj.make_callback('pick-enter', canvas, event, pt) # make pick callback obj.make_callback(cb_name, canvas, event, pt) return True def pick_start(self, canvas, event, data_x, data_y, viewer): return self._do_pick(canvas, event, data_x, data_y, 'pick-down', viewer) def pick_motion(self, canvas, event, data_x, data_y, viewer): return self._do_pick(canvas, event, data_x, data_y, 'pick-move', viewer) def pick_hover(self, canvas, event, data_x, data_y, viewer): return self._do_pick(canvas, event, data_x, data_y, 'pick-hover', viewer) def pick_stop(self, canvas, event, data_x, data_y, viewer): return self._do_pick(canvas, event, data_x, data_y, 'pick-up', viewer) # The canvas drawing def draw(self, viewer): # Draw everything else as usual super(DrawingMixin, self).draw(viewer) # Draw our current drawing object, if any if self._draw_obj: self._draw_obj.draw(viewer) # Draw control points on edited objects selected = list(self.get_selected()) if len(selected) > 0: for obj in selected: cr = viewer.renderer.setup_cr(obj) obj.draw_edit(cr, viewer) ### NON-PEP8 EQUIVALENTS -- TO BE DEPRECATED ### setSurface = set_surface getDrawClass = get_draw_class
def main(self, options, args): """ Main routine for running the reference viewer. `options` is a OptionParser object that has been populated with values from parsing the command line. It should at least include the options from add_default_options() `args` is a list of arguments to the viewer after parsing out options. It should contain a list of files or URLs to load. """ # Create a logger logger = log.get_logger(name='ginga', options=options) # Get settings (preferences) basedir = paths.ginga_home if not os.path.exists(basedir): try: os.mkdir(basedir) except OSError as e: logger.warning("Couldn't create ginga settings area (%s): %s" % (basedir, str(e))) logger.warning("Preferences will not be able to be saved") # Set up preferences prefs = Settings.Preferences(basefolder=basedir, logger=logger) settings = prefs.create_category('general') settings.set_defaults(useMatplotlibColormaps=False, widgetSet='choose', WCSpkg='choose', FITSpkg='choose', recursion_limit=2000, icc_working_profile=None, font_scaling_factor=None, save_layout=True, channel_prefix="Image") settings.load(onError='silent') # default of 1000 is a little too small sys.setrecursionlimit(settings.get('recursion_limit')) # So we can find our plugins sys.path.insert(0, basedir) package_home = os.path.split(sys.modules['ginga.version'].__file__)[0] child_dir = os.path.join(package_home, 'rv', 'plugins') sys.path.insert(0, child_dir) plugin_dir = os.path.join(basedir, 'plugins') sys.path.insert(0, plugin_dir) gc = os.path.join(basedir, "ginga_config.py") have_ginga_config = os.path.exists(gc) # User configuration, earliest possible intervention if have_ginga_config: try: import ginga_config if hasattr(ginga_config, 'init_config'): ginga_config.init_config(self) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error processing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Choose a toolkit if options.toolkit: toolkit = options.toolkit else: toolkit = settings.get('widgetSet', 'choose') if toolkit == 'choose': try: ginga_toolkit.choose() except ImportError as e: print("UI toolkit choose error: %s" % str(e)) sys.exit(1) else: ginga_toolkit.use(toolkit) tkname = ginga_toolkit.get_family() logger.info("Chosen toolkit (%s) family is '%s'" % (ginga_toolkit.toolkit, tkname)) # these imports have to be here, otherwise they force the choice # of toolkit too early from ginga.rv.Control import GingaShell, GuiLogHandler if settings.get('useMatplotlibColormaps', False): # Add matplotlib color maps if matplotlib is installed try: from ginga import cmap cmap.add_matplotlib_cmaps(fail_on_import_error=False) except Exception as e: logger.warning("failed to load matplotlib colormaps: %s" % (str(e))) # Set a working RGB ICC profile if user has one working_profile = settings.get('icc_working_profile', None) rgb_cms.working_profile = working_profile # User wants to customize the WCS package? if options.wcspkg: wcspkg = options.wcspkg else: wcspkg = settings.get('WCSpkg', 'choose') try: from ginga.util import wcsmod if wcspkg != 'choose': assert wcsmod.use(wcspkg) is True except Exception as e: logger.warning("failed to set WCS package preference: %s" % (str(e))) # User wants to customize the FITS package? if options.fitspkg: fitspkg = options.fitspkg else: fitspkg = settings.get('FITSpkg', 'choose') try: from ginga.util import io_fits, loader if fitspkg != 'choose': assert io_fits.use(fitspkg) is True # opener name is not necessarily the same opener = loader.get_opener(io_fits.fitsLoaderClass.name) # set this opener as the priority one opener.priority = -99 except Exception as e: logger.warning("failed to set FITS package preference: %s" % (str(e))) # Check whether user wants to use OpenCv use_opencv = settings.get('use_opencv', False) if use_opencv or options.opencv: from ginga import trcalc try: trcalc.use('opencv') except Exception as e: logger.warning("failed to set OpenCv preference: %s" % (str(e))) # Check whether user wants to use OpenCL use_opencl = settings.get('use_opencl', False) if use_opencl or options.opencl: from ginga import trcalc try: trcalc.use('opencl') except Exception as e: logger.warning("failed to set OpenCL preference: %s" % (str(e))) # Create the dynamic module manager mm = ModuleManager.ModuleManager(logger) # Create and start thread pool ev_quit = threading.Event() thread_pool = Task.ThreadPool(options.numthreads, logger, ev_quit=ev_quit) thread_pool.startall() # Create the Ginga main object ginga_shell = GingaShell(logger, thread_pool, mm, prefs, ev_quit=ev_quit) # user wants to set font scaling. # NOTE: this happens *after* creation of shell object, since # Application object constructor will also set this font_scaling = settings.get('font_scaling_factor', None) if font_scaling is not None: logger.debug( "overriding font_scaling_factor to {}".format(font_scaling)) from ginga.fonts import font_asst font_asst.default_scaling_factor = font_scaling layout_file = None if not options.norestore and settings.get('save_layout', False): layout_file = os.path.join(basedir, 'layout') ginga_shell.set_layout(self.layout, layout_file=layout_file) # User configuration (custom star catalogs, etc.) if have_ginga_config: try: if hasattr(ginga_config, 'pre_gui_config'): ginga_config.pre_gui_config(ginga_shell) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error importing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Build desired layout ginga_shell.build_toplevel() # Did user specify a particular geometry? if options.geometry: ginga_shell.set_geometry(options.geometry) # make the list of disabled plugins if options.disable_plugins is not None: disabled_plugins = options.disable_plugins.lower().split(',') else: disabled_plugins = settings.get('disable_plugins', []) if not isinstance(disabled_plugins, list): disabled_plugins = disabled_plugins.lower().split(',') # Add GUI log handler (for "Log" global plugin) guiHdlr = GuiLogHandler(ginga_shell) guiHdlr.setLevel(options.loglevel) fmt = logging.Formatter(log.LOG_FORMAT) guiHdlr.setFormatter(fmt) logger.addHandler(guiHdlr) # Load any custom modules if options.modules is not None: modules = options.modules.split(',') else: modules = settings.get('global_plugins', []) if not isinstance(modules, list): modules = modules.split(',') for long_plugin_name in modules: if '.' in long_plugin_name: tmpstr = long_plugin_name.split('.') plugin_name = tmpstr[-1] pfx = '.'.join(tmpstr[:-1]) else: plugin_name = long_plugin_name pfx = None menu_name = "%s [G]" % (plugin_name) spec = Bunch(name=plugin_name, module=plugin_name, ptype='global', tab=plugin_name, menu=menu_name, category="Custom", workspace='right', pfx=pfx) self.add_plugin_spec(spec) # Load any custom local plugins if options.plugins is not None: plugins = options.plugins.split(',') else: plugins = settings.get('local_plugins', []) if not isinstance(plugins, list): plugins = plugins.split(',') for long_plugin_name in plugins: if '.' in long_plugin_name: tmpstr = long_plugin_name.split('.') plugin_name = tmpstr[-1] pfx = '.'.join(tmpstr[:-1]) else: plugin_name = long_plugin_name pfx = None spec = Bunch(module=plugin_name, workspace='dialogs', ptype='local', category="Custom", hidden=False, pfx=pfx) self.add_plugin_spec(spec) # Add non-disabled plugins enabled_plugins = [ spec for spec in self.plugins if spec.module.lower() not in disabled_plugins ] ginga_shell.set_plugins(enabled_plugins) # start any plugins that have start=True ginga_shell.boot_plugins() ginga_shell.update_pending() # TEMP? tab_names = [ name.lower() for name in ginga_shell.ds.get_tabnames(group=None) ] if 'info' in tab_names: ginga_shell.ds.raise_tab('Info') if 'synopsis' in tab_names: ginga_shell.ds.raise_tab('Synopsis') if 'thumbs' in tab_names: ginga_shell.ds.raise_tab('Thumbs') # Add custom channels if options.channels is not None: channels = options.channels.split(',') else: channels = settings.get('channels', self.channels) if not isinstance(channels, list): channels = channels.split(',') if len(channels) == 0: # should provide at least one default channel? channels = [settings.get('channel_prefix', "Image")] # populate the initial channel lineup for item in channels: if isinstance(item, str): chname, wsname = item, None else: chname, wsname = item ginga_shell.add_channel(chname, workspace=wsname) ginga_shell.change_channel(chname) # User configuration (custom star catalogs, etc.) if have_ginga_config: try: if hasattr(ginga_config, 'post_gui_config'): ginga_config.post_gui_config(ginga_shell) except Exception as e: try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) except Exception: tb_str = "Traceback information unavailable." logger.error("Error processing Ginga config file: %s" % (str(e))) logger.error("Traceback:\n%s" % (tb_str)) # Redirect warnings to logger for hdlr in logger.handlers: logging.getLogger('py.warnings').addHandler(hdlr) # Display banner the first time run, unless suppressed show_banner = True try: show_banner = settings.get('showBanner') except KeyError: # disable for subsequent runs settings.set(showBanner=False) if not os.path.exists(settings.preffile): settings.save() if (not options.nosplash) and (len(args) == 0) and show_banner: ginga_shell.banner(raiseTab=True) # Handle inputs like "*.fits[ext]" that sys cmd cannot auto expand. expanded_args = [] for imgfile in args: if '*' in imgfile: if '[' in imgfile and imgfile.endswith(']'): s = imgfile.split('[') ext = '[' + s[1] imgfile = s[0] else: ext = '' for fname in glob.iglob(imgfile): expanded_args.append(fname + ext) else: expanded_args.append(imgfile) # Assume remaining arguments are fits files and load them. if not options.separate_channels: chname = channels[0] ginga_shell.gui_do(ginga_shell.open_uris, expanded_args, chname=chname) else: i = 0 num_channels = len(channels) for imgfile in expanded_args: if i < num_channels: chname = channels[i] i = i + 1 else: channel = ginga_shell.add_channel_auto() chname = channel.name ginga_shell.gui_do(ginga_shell.open_uris, [imgfile], chname=chname) try: try: # if there is a network component, start it if hasattr(ginga_shell, 'start'): logger.info("starting network interface...") task = Task.FuncTask2(ginga_shell.start) thread_pool.addTask(task) # Main loop to handle GUI events logger.info("entering mainloop...") ginga_shell.mainloop(timeout=0.001) except KeyboardInterrupt: logger.error("Received keyboard interrupt!") finally: logger.info("Shutting down...") ev_quit.set() sys.exit(0)
def find_executable_obs_cb(self, widget): self.tree1.clear() self.view.update_pending() # get a handle to the control panel plugin cp = self.view.get_plugin('cp') use_db = cp.w.use_qdb.get_state() limit_filter = None if not self.w.fltr_exch.get_state(): limit_filter = self.w.filter.get_text().strip() cp.update_scheduler(use_db=use_db, limit_filter=limit_filter, allow_delay=self.w.allow_delay.get_state()) sdlr = self.model.get_scheduler() date_s = self.w.date.get_text().strip() time_b = self.w.start_time.get_text().strip() try: time_start = sdlr.site.get_date("%s %s" % (date_s, time_b)) except Exception as e: errmsg = 'Error parsing start date/time:: {}\n'.format(str(e)) errmsg += "\n".join([e.__class__.__name__, str(e)]) self.logger.error(errmsg) self.view.gui_do(self.view.show_error, errmsg, raisetab=True) return # find the record in the schedule table that matches our date try: data = self.get_schedule_data(time_start) except ValueError as e: errmsg = str(e) self.logger.error(errmsg) self.view.gui_do(self.view.show_error, errmsg, raisetab=True) return # should we get the actual installed list of filters instead from # Gen2 rather than reading it out of the Schedule filters = data.filters _filter = self.w.filter.get_text().strip() if not _filter in filters: errmsg = "filter '{}' not found in available filters: {}".format( _filter, str(filters)) self.logger.error(errmsg) self.view.gui_do(self.view.show_error, errmsg, raisetab=True) return len_s = self.w.len_time.get_text().strip() slot_length = max(0.0, float(len_s) * 60.0) # override some items from Schedule table data.cur_filter = self.w.filter.get_text().strip() data.cur_az = float(self.w.az.get_text().strip()) data.cur_el = float(self.w.el.get_text().strip()) data.seeing = float(self.w.seeing.get_text().strip()) data.transparency = float(self.w.trans.get_text().strip()) slot = entity.Slot(time_start, slot_length, data=data) self.slot = slot good, bad = sdlr.find_executable_obs(slot) tree_dict = OrderedDict() # Table header with units columns = [('Best', 'index'), ('Program', 'program'), ('OB Code', 'ob_code'), ('Priority', 'priority'), ('Grade', 'grade'), ('Prep', 'prep'), ('On Source', 'time'), ('Target', 'target'), ('Filter', 'filter'), ('Delay', 'delay'), ('Reason', 'reason')] self.tree1.setup_table(columns, 1, 'index') # This is to get around table widget not sorting numbers properly i_fmt = '{{0:0{0}d}}'.format(len(str(len(good)))) # Table contents i = 1 for rec in good: i_str = i_fmt.format(i) bnch = Bunch(index=i_str, program=rec.ob.program.proposal, ob_code=rec.ob.name, priority=rec.ob.priority, grade=rec.ob.program.grade, prep="%.2f" % (rec.prep_sec / 60.0), time="%.2f" % (rec.ob.total_time / 60.0), target=rec.ob.target.name, filter=rec.ob.inscfg.filter, delay=rec.delay_sec / 60.0, _group=good, _rec=rec, reason='OK') tree_dict[i_str] = bnch i += 1 if self.show_bad: for rec in bad: i_str = i_fmt.format(i) bnch = Bunch(index=i_str, program=rec.ob.program.proposal, ob_code=rec.ob.name, priority=rec.ob.priority, grade=rec.ob.program.grade, prep="%.2f" % (rec.prep_sec / 60.0), time="%.2f" % (rec.ob.total_time / 60.0), target=rec.ob.target.name, filter=rec.ob.inscfg.filter, delay=rec.delay_sec / 60.0, _group=bad, _rec=rec, reason='NG: ' + rec.reason) tree_dict[i_str] = bnch i += 1 self.tree1.set_tree(tree_dict) self.tree1.set_optimal_column_widths()