Changeset 2168 for trunk/python


Ignore:
Timestamp:
05/17/11 14:37:34 (14 years ago)
Author:
Kana Sugimoto
Message:

New Development: Yes

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: Interactive test with PyQt4 backend

Put in Release Notes: Yes

Module(s): asapplotter, asaplotbase, and sdplot

Description: Enabled additional toolbar, casabar, in asapplotter for Qt4Agg bacend


Location:
trunk/python
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/python/asapplotter.py

    r2155 r2168  
    9090    def _newcasabar(self):
    9191        backend=matplotlib.get_backend()
    92         if self._visible and backend == "TkAgg":
     92        if not self._visible:
     93            return None
     94        elif backend == "TkAgg":
    9395            from asap.customgui_tkagg import CustomToolbarTkAgg
    9496            return CustomToolbarTkAgg(self)
    9597            #from asap.casatoolbar import CustomFlagToolbarTkAgg
    9698            #return CustomFlagToolbarTkAgg(self)
     99        elif backend == "Qt4Agg":
     100            from asap.customgui_qt4agg import CustomToolbarQT4Agg
     101            return CustomToolbarQT4Agg(self)
    97102        return None
    98103
  • trunk/python/customgui_qt4agg.py

    r2155 r2168  
    99import PyQt4 as qt
    1010
     11######################################
     12##    Add CASA custom toolbar       ##
     13######################################
    1114class CustomToolbarQT4Agg(CustomToolbarCommon,  qt.QtGui.QToolBar):
    1215    def __init__(self,parent):
     
    2326        self.pagecount = None
    2427        CustomToolbarCommon.__init__(self,parent)
    25 #         self.notewin = NotationWindowQT4Agg(master=self.canvas)
     28        self.notewin = NotationWindowQT4Agg(master=self.canvas)
    2629        self._add_custom_toolbar()
    2730
     
    3134        self.bNote = self._NewButton(master=self,
    3235                                     text='notation',
    33                                      command=self.modify_note)
     36                                     command=self.modify_note,
     37                                     balloon="Add note")
    3438        self.bNote.setCheckable(True)
    3539
    3640        self.bStat = self._NewButton(master=self,
    3741                                     text='statistics',
    38                                      command=self.stat_cal)
     42                                     command=self.stat_cal,
     43                                     balloon="Calculate statistics")
    3944        self.bStat.setCheckable(True)
    4045
     
    5459        self.bNext = self._NewButton(master=frPage,
    5560                                     text=' + ',
    56                                      command=self.next_page,addparent=False)
     61                                     command=self.next_page,
     62                                     addit=False)
    5763        loPage.addWidget(self.bNext)
    5864        self.bPrev = self._NewButton(master=frPage,
    5965                                     text=' - ',
    60                                      command=self.prev_page,addparent=False)
     66                                     command=self.prev_page,addit=False)
    6167        loPage.addWidget(self.bPrev)
    6268        frPage.setLayout(loPage)
     
    6571        self.bQuit = self._NewButton(master=self,
    6672                                     text='Quit',
    67                                      command=self.quit)
    68 
    69 #         if os.uname()[0] != 'Darwin':
    70 #             self.bPrev.config(padx=5)
    71 #             self.bNext.config(padx=5)
     73                                     command=self.quit,
     74                                     balloon="Close window")
    7275
    7376        self.pagecount.setText(' '*4)
     
    7679        return
    7780
    78     def _NewButton(self, master, text, command,addparent=True):
     81    def _NewButton(self, master, text, command, balloon=None,addit=True):
    7982        b = qt.QtGui.QPushButton(text,parent=master)
    80         if addparent: master.addWidget(b)
     83        if balloon: b.setToolTip(balloon)
     84        if addit: master.addWidget(b)
    8185        master.connect(b,qt.QtCore.SIGNAL('clicked()'),command)
    82 #         if os.uname()[0] == 'Darwin':
    83 #             b = Tk.Button(master=master, text=text, command=command)
    84 #         else:
    85 #             b = Tk.Button(master=master, text=text, padx=2, pady=2,
    86 #                           command=command)
    8786        return b
    8887
     
    9594        if self.mode == 'spec': return
    9695        self.mode = 'spec'
    97 #         self.notewin.close_widgets()
     96        self.notewin.close_widgets()
    9897        self.__disconnect_event()
    9998        self._p.register('button_press',self._select_spectrum)
     
    107106            # go back to spec mode
    108107            self.bStat.setChecked(False)
     108            self.bStat.setToolTip("Calculate statistics")
    109109            self.spec_show()
    110110            return
    111111        self.figmgr.toolbar.set_message('statistics: select a region')
    112112        self.bStat.setChecked(True)
     113        self.bStat.setToolTip("Back to spec value mode")
    113114        self.bNote.setChecked(False)
    114115        self.mode = 'stat'
    115 #         self.notewin.close_widgets()
     116        self.notewin.close_widgets()
    116117        self.__disconnect_event()
    117118        self._p.register('button_press',self._single_mask)
     
    125126        if self.mode == 'note':
    126127            self.bNote.setChecked(False)
     128            self.bNote.setToolTip("Add note")
    127129            self.mode = 'none'
    128130            self.spec_show()
     
    130132        self.bStat.setChecked(False)
    131133        self.bNote.setChecked(True)
     134        self.bNote.setToolTip("Back to spec value mode")
    132135        self.mode = 'note'
    133136        self.__disconnect_event()
     
    185188
    186189
     190
     191
     192######################################
     193##    Notation box window           ##
     194######################################
     195class NotationWindowQT4Agg(NotationWindowCommon):
     196    """
     197    Backend based class to create widgets to add, modify, or delete
     198    note on the plot.
     199
     200    Note:
     201    Press LEFT-mouse button on the plot to ADD a note on the canvas.
     202    A notation window will be loaded for specifying note string and
     203    anchor. The note will be anchored on a position in whether figure-
     204    (0-1 relative in a figure), panel- (0-1 relative in a plot axes),
     205    or data-coordinate (data value in a plot axes).
     206    Press RIGHT-mouse button on a note to MODIFY/DELETE it. A cascade
     207    menu will be displayed and you can select an operation.
     208    """
     209    def __init__(self,master=None):
     210        self.parent = master
     211        NotationWindowCommon.__init__(self,master=master)
     212        self.anchval = None
     213        self.textwin = self._create_textwindow(master=None)
     214        self.menu = self._create_modmenu(master=self.parent)
     215
     216    ### Notation window widget
     217    def _create_textwindow(self,master=None):
     218        """Create notation window widget and iconfy it"""
     219        #twin = qt.QtGui.QWidget(parent=master, flags=qt.QtCore.Qt.Popup)
     220        twin = qt.QtGui.QWidget(parent=master, flags=qt.QtCore.Qt.Dialog)
     221        twin.setWindowTitle("Notation")
     222        self.textbox = self._NotationBox(parent=twin)
     223        radiobox = self._AnchorRadio(parent=twin)
     224        self.actionbs = self._ActionButtons(parent=twin)
     225        vbox = qt.QtGui.QVBoxLayout(twin)
     226        vbox.addWidget(self.textbox)
     227        vbox.addWidget(radiobox)
     228        vbox.addLayout(self.actionbs)
     229        twin.setLayout(vbox)
     230        #twin.setCentralWidget(self.textbox)
     231        twin.hide()
     232        return twin
     233
     234    def _NotationBox(self,parent=None):
     235        textbox = qt.QtGui.QPlainTextEdit(parent=parent)
     236        textbox.setStyleSheet("background-color: white")
     237        fmetric = qt.QtGui.QFontMetrics(textbox.currentCharFormat().font())
     238        textbox.resize(fmetric.width("A")*20+fmetric.leading()*2,
     239                       fmetric.height()*2+fmetric.ascent()+fmetric.descent())
     240        del fmetric
     241        textbox.setMinimumSize(textbox.size())
     242        textbox.setUndoRedoEnabled(True)
     243        textbox.setMidLineWidth(3)
     244        textbox.setFrameShadow(qt.QtGui.QFrame.Sunken)
     245        textbox.setCursor(qt.QtCore.Qt.IBeamCursor)
     246        textbox.setFocus()
     247        return textbox
     248
     249    def _AnchorRadio(self,parent=None):
     250        # Returns a QGoupBox object which includes radio butons to
     251        # select an anchor
     252        anchbox = qt.QtGui.QGroupBox("anchor",parent=parent)
     253        self.radio = qt.QtGui.QButtonGroup(parent=anchbox)
     254        self.rFig = self._NewRadioButton(anchbox,"figure",\
     255                                         bgr=self.radio,value=0,\
     256                                         balloon="a fixed position in figure")
     257        self.rAxis = self._NewRadioButton(anchbox,"panel",\
     258                                          bgr=self.radio,value=1,\
     259                                          balloon="a fixed realtive position in subplot")
     260        self.rData = self._NewRadioButton(anchbox,"data",\
     261                                          bgr=self.radio,value=2,\
     262                                          balloon="a fixed data position in subplot")
     263        hbox = qt.QtGui.QHBoxLayout(anchbox)
     264        hbox.addWidget(self.rFig)
     265        hbox.addWidget(self.rAxis)
     266        hbox.addWidget(self.rData)
     267        anchbox.setLayout(hbox)
     268        # set initial selection "figure"
     269        self.rFig.setChecked(True)
     270        self.radio.setExclusive(True)
     271        self.anchval = self.radio.checkedId()
     272        return anchbox
     273
     274    def _NewRadioButton(self,parent,text,balloon=None,bgr=None,value=None):
     275        rb= qt.QtGui.QRadioButton(text,parent=parent)
     276        if bgr:
     277            if value is not None:
     278                bgr.addButton(rb,value)
     279            else:
     280                bgr.addButton(rb)
     281        if balloon: rb.setToolTip(balloon)
     282        return rb
     283
     284    def _enable_radio(self):
     285        """Enable 'panel' and 'data' radio button"""
     286        self.rAxis.setEnabled(True)
     287        self.rData.setEnabled(True)
     288        # select Figure as the default value
     289        self.rFig.setChecked(True)
     290        self.anchval = self.radio.checkedId()
     291
     292    def _reset_radio(self):
     293        """Disable 'panel' and 'data' radio button"""
     294        self.rAxis.setDisabled(True)
     295        self.rData.setDisabled(True)
     296        self.rFig.setEnabled(True)
     297        # select Figure as the default value
     298        self.rFig.setChecked(True)
     299        self.anchval = self.radio.checkedId()
     300
     301    def _select_radio(self,selection):
     302        """Select a specified radio button"""
     303        if not selection in self.anchors:
     304            return
     305        if selection == "data":
     306            self.rData.setChecked(True)
     307        elif selection == "axes":
     308            self.rAxis.setChecked(True)
     309        else:
     310            self.rFig.setChecked(True)
     311        self.anchval = self.radio.checkedId()
     312
     313    def _get_anchval(self):
     314        """Returns a integer of a selected radio button"""
     315        self.anchval = self.radio.checkedId()
     316        return self.anchval
     317
     318    def _get_note(self):
     319        """Returns a note string specified in the text box"""
     320        return str(self.textbox.toPlainText())
     321
     322    def _clear_textbox(self):
     323        """Clear the text box"""
     324        self.textbox.clear()
     325
     326    def _set_note(self,note=None):
     327        """Set a note string to the text box"""
     328        self._clear_textbox()
     329        if len(note) >0:
     330            self.textbox.setPlainText(note)
     331
     332    def _ActionButtons(self,parent=None):
     333        # Returns a layout object which includes "cancel" and "print" buttons
     334        actbuts = qt.QtGui.QHBoxLayout()
     335        bCancel = self._NewButton(parent,"cancel",self._cancel_text,\
     336                                  addit=False,\
     337                                  balloon="cancel printing/modifying")
     338        bPrint = self._NewButton(parent,"print", self._print_text,\
     339                                 addit=False,\
     340                                 balloon="print text on plot")
     341        actbuts.addWidget(bCancel)
     342        actbuts.addWidget(bPrint)
     343        return actbuts
     344
     345    def _NewButton(self, parent, text, command, balloon=None, addit=True):
     346        b = qt.QtGui.QPushButton(text,parent=parent)
     347        if balloon: b.setToolTip(balloon)
     348        if addit: parent.addWidget(b)
     349        parent.connect(b,qt.QtCore.SIGNAL('clicked()'),command)
     350        return b
     351
     352    def _cancel_text(self):
     353        """
     354        Cancel adding/modifying a note and close notaion window.
     355        called when 'cancel' is selected.
     356        """
     357        self.close_textwindow()
     358
     359    def _print_text(self):
     360        """
     361        Add/Modify a note. Called when 'print' is selected on the
     362        notation window.
     363        """
     364        self.print_text()
     365        self.close_textwindow()
     366
     367    def load_textwindow(self,event):
     368        """
     369        Load text window at a event position to add a note on a plot.
     370        Parameter:
     371            event:   an even object to specify the position to load
     372                     text window.
     373        """
     374        self.close_modmenu()
     375        if event.canvas != self.parent:
     376            raise RuntimeError, "Got invalid event!"
     377
     378        self.event = event
     379        is_ax = (event.inaxes != None)
     380        (xpix, ypix) = self._disppix2screen(event.x, event.y)
     381        offset = 5
     382        self.show_textwindow(xpix+offset,ypix+offset,enableaxes=is_ax)
     383
     384    def show_textwindow(self,xpix,ypix,basetext=None,enableaxes=False):
     385        """
     386        Load text window at a position of screen to add a note on a plot.
     387        Parameters:
     388            xpix, ypix:   a pixel position from Upper-left corner
     389                          of the screen.
     390            basetext:     None (default) or any string.
     391                          A string to be printed on text box when loaded.
     392            enableaxes:   False (default) or True.
     393                          If True, 'panel' & 'data' radio button is enabled.
     394        """
     395        if not self.textwin: return
     396        self._reset_radio()
     397        if enableaxes:
     398            self._enable_radio()
     399        self.textwin.activateWindow()
     400        h = self.textwin.minimumHeight()
     401        w = self.textwin.minimumWidth()
     402        self.textwin.resize(w,h)
     403        self.textwin.move(xpix,ypix)
     404        self.textbox.setFocus()
     405        self.textwin.raise_()
     406        self.textwin.show()
     407        if w*h <= 1: # Initial load
     408            self.textwin.setMinimumSize(self.textwin.size())
     409
     410    def close_textwindow(self):
     411        """Close text window."""
     412        self.seltext = {}
     413        self._reset_radio()
     414        self._clear_textbox()
     415        self.textwin.hide()
     416
     417
     418    ### Modify/Delete menu widget
     419    def _create_modmenu(self,master=None):
     420        """Create modify/delete menu widget"""
     421        if master:
     422            self.parent = master
     423        if not self.parent:
     424            return False
     425        menu = qt.QtGui.QMenu(parent=self.parent)
     426        menu.setTearOffEnabled(False)
     427        menu.addAction("Modify",self._modify_note)
     428        menu.addAction("Delete",self._delnote_dialog)
     429        return menu
     430
     431    def load_modmenu(self,event):
     432        """
     433        Load cascade menu at a event position to modify or delete
     434        selected text.
     435        Parameter:
     436            event:  an even object to specify the position to load
     437                    text window.
     438        """
     439        self.close_textwindow()
     440        self.seltext = self._get_selected_text(event)
     441        if len(self.seltext) == 3:
     442            canvas = event.canvas
     443            corig = canvas.mapToGlobal(qt.QtCore.QPoint(0,0))
     444            xpixs = corig.x() + int(event.x)
     445            ypixs = corig.y() + canvas.height() - int(event.y)
     446            self.menu.activateWindow()
     447            self.menu.move(xpixs,ypixs)
     448            self.menu.show()
     449
     450    def close_modmenu(self):
     451        """Close cascade menu."""
     452        self.seltext = {}
     453        self.menu.hide()
     454
     455    ### load text window for modification
     456    def _modify_note(self):
     457        """helper function to load text window to modify selected note"""
     458        textobj = self.seltext['textobj']
     459        (xtx, ytx) = textobj._get_xy_display()
     460        is_ax = (self.seltext['anchor'] != 'figure')
     461        if not is_ax:
     462            # previous anchor is figure
     463            pos = textobj.get_position()
     464            is_ax = (self._get_axes_from_pos(pos,self.canvas) != None)
     465
     466        (xpix, ypix) = self._disppix2screen(xtx,ytx)
     467        offset = int(textobj.get_size())*2
     468        self.show_textwindow(xpix,ypix+offset,basetext=textobj.get_text(),\
     469                             enableaxes=is_ax)
     470        self._select_radio(self.seltext['anchor'])
     471        self._set_note(textobj.get_text())
     472
     473    ### close all widgets
     474    def close_widgets(self):
     475        """Close note window and menu"""
     476        self.close_textwindow()
     477        self.close_modmenu()
     478
     479    ### dialog to confirm deleting note
     480    def _delnote_dialog(self):
     481        """Load dialog to confirm deletion of the text"""
     482        remind = "Delete text?\n '"+self.seltext['textobj'].get_text()+"'"
     483        from PyQt4.QtGui import QMessageBox as mbox
     484        answer = mbox.question(self.parent,"Delete?",remind,
     485                               buttons = mbox.Ok | mbox.Cancel,
     486                               defaultButton=mbox.Cancel)
     487        if answer == mbox.Ok:
     488            self.delete_note()
     489        else:
     490            self.cancel_delete()
     491
     492    ### helper functions
     493    def _disppix2screen(self,xpixd,ypixd):
     494        """
     495        helper function to calculate a pixel position form Upper-left
     496        corner of the SCREEN from a pixel position (xpixd, ypixd)
     497        from Lower-left of the CANVAS (which, e.g., event.x/y returns)
     498
     499        Returns:
     500            (x, y):  pixel position from Upper-left corner of the SCREEN.
     501        """
     502        corig = self.parent.mapToGlobal(qt.QtCore.QPoint(0,0))
     503        xpixs = corig.x() + xpixd
     504        ypixs = corig.y() + self.parent.height() - ypixd
     505        return (int(xpixs), int(ypixs))
     506       
     507
     508
     509
     510
     511
     512###########################################
     513##    Add CASA custom Flag toolbar       ##
     514###########################################
Note: See TracChangeset for help on using the changeset viewer.