Ignore:
Timestamp:
Aug 2, 2017 9:45:09 AM (5 years ago)
Author:
riza
Message:

Close #2034: Add support to Python3 using PJSUA2 API.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pygui/chatgui.py

    r4757 r5638  
    2121import sys 
    2222if sys.version_info[0] >= 3: # Python 3 
    23         import tkinter as tk 
    24         from tkinter import ttk 
    25         from tkinter import messagebox as msgbox 
     23    import tkinter as tk 
     24    from tkinter import ttk 
     25    from tkinter import messagebox as msgbox 
    2626else: 
    27         import Tkinter as tk 
    28         import ttk 
    29         import tkMessageBox as msgbox 
     27    import Tkinter as tk 
     28    import ttk 
     29    import tkMessageBox as msgbox 
    3030 
    3131 
    3232class TextObserver: 
    33         def onSendMessage(self, msg): 
    34                 pass 
    35         def onStartTyping(self): 
    36                 pass 
    37         def onStopTyping(self): 
    38                 pass 
    39                  
     33    def onSendMessage(self, msg): 
     34        pass 
     35    def onStartTyping(self): 
     36        pass 
     37    def onStopTyping(self): 
     38        pass 
     39 
    4040class TextFrame(ttk.Frame): 
    41         def __init__(self, master, observer): 
    42                 ttk.Frame.__init__(self, master) 
    43                 self._observer = observer 
    44                 self._isTyping = False 
    45                 self._createWidgets() 
    46  
    47         def _onSendMessage(self, event): 
    48                 send_text = self._typingBox.get("1.0", tk.END).strip() 
    49                 if send_text == '': 
    50                         return 
    51                  
    52                 self.addMessage('me: ' + send_text) 
    53                 self._typingBox.delete("0.0", tk.END) 
    54                 self._onTyping(None) 
    55                  
    56                 # notify app for sending message 
    57                 self._observer.onSendMessage(send_text) 
    58                  
    59         def _onTyping(self, event): 
    60                 # notify app for typing indication 
    61                 is_typing = self._typingBox.get("1.0", tk.END).strip() != '' 
    62                 if is_typing != self._isTyping: 
    63                         self._isTyping = is_typing 
    64                         if is_typing: 
    65                                 self._observer.onStartTyping() 
    66                         else: 
    67                                 self._observer.onStopTyping() 
    68                  
    69         def _createWidgets(self): 
    70                 self.rowconfigure(0, weight=1) 
    71                 self.rowconfigure(1, weight=0) 
    72                 self.rowconfigure(2, weight=0) 
    73                 self.columnconfigure(0, weight=1) 
    74                 self.columnconfigure(1, weight=0) 
    75                  
    76                 self._text = tk.Text(self, width=50, height=30, font=("Arial", "10")) 
    77                 self._text.grid(row=0, column=0, sticky='nswe') 
    78                 self._text.config(state=tk.DISABLED) 
    79                 self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic")) 
    80                  
    81                 scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview) 
    82                 self._text.config(yscrollcommand=scrl.set) 
    83                 scrl.grid(row=0, column=1, sticky='nsw') 
    84                  
    85                 self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10")) 
    86                 self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0) 
    87                  
    88                 self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic")) 
    89                 self._statusBar.grid(row=2, columnspan=2, sticky='we') 
    90                  
    91                 self._typingBox.bind('<Return>', self._onSendMessage) 
    92                 self._typingBox.bind("<Key>", self._onTyping) 
    93                 self._typingBox.focus_set() 
    94                  
    95         def addMessage(self, msg, is_chat = True): 
    96                 self._text.config(state=tk.NORMAL) 
    97                 if is_chat: 
    98                         self._text.insert(tk.END, msg+'\r\n') 
    99                 else: 
    100                         self._text.insert(tk.END, msg+'\r\n', 'info') 
    101                 self._text.config(state=tk.DISABLED) 
    102                 self._text.yview(tk.END) 
    103  
    104         def setTypingIndication(self, who, is_typing): 
    105                 if is_typing: 
    106                         self._statusBar['text'] = "'%s' is typing.." % (who) 
    107                 else: 
    108                         self._statusBar['text'] = '' 
     41    def __init__(self, master, observer): 
     42        ttk.Frame.__init__(self, master) 
     43        self._observer = observer 
     44        self._isTyping = False 
     45        self._createWidgets() 
     46 
     47    def _onSendMessage(self, event): 
     48        send_text = self._typingBox.get("1.0", tk.END).strip() 
     49        if send_text == '': 
     50            return 
     51 
     52        self.addMessage('me: ' + send_text) 
     53        self._typingBox.delete("0.0", tk.END) 
     54        self._onTyping(None) 
     55 
     56        # notify app for sending message 
     57        self._observer.onSendMessage(send_text) 
     58 
     59    def _onTyping(self, event): 
     60        # notify app for typing indication 
     61        is_typing = self._typingBox.get("1.0", tk.END).strip() != '' 
     62        if is_typing != self._isTyping: 
     63            self._isTyping = is_typing 
     64            if is_typing: 
     65                self._observer.onStartTyping() 
     66            else: 
     67                self._observer.onStopTyping() 
     68 
     69    def _createWidgets(self): 
     70        self.rowconfigure(0, weight=1) 
     71        self.rowconfigure(1, weight=0) 
     72        self.rowconfigure(2, weight=0) 
     73        self.columnconfigure(0, weight=1) 
     74        self.columnconfigure(1, weight=0) 
     75 
     76        self._text = tk.Text(self, width=50, height=30, font=("Arial", "10")) 
     77        self._text.grid(row=0, column=0, sticky='nswe') 
     78        self._text.config(state=tk.DISABLED) 
     79        self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic")) 
     80 
     81        scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview) 
     82        self._text.config(yscrollcommand=scrl.set) 
     83        scrl.grid(row=0, column=1, sticky='nsw') 
     84 
     85        self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10")) 
     86        self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0) 
     87 
     88        self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic")) 
     89        self._statusBar.grid(row=2, columnspan=2, sticky='we') 
     90 
     91        self._typingBox.bind('<Return>', self._onSendMessage) 
     92        self._typingBox.bind("<Key>", self._onTyping) 
     93        self._typingBox.focus_set() 
     94 
     95    def addMessage(self, msg, is_chat = True): 
     96        self._text.config(state=tk.NORMAL) 
     97        if is_chat: 
     98            self._text.insert(tk.END, msg+'\r\n') 
     99        else: 
     100            self._text.insert(tk.END, msg+'\r\n', 'info') 
     101        self._text.config(state=tk.DISABLED) 
     102        self._text.yview(tk.END) 
     103 
     104    def setTypingIndication(self, who, is_typing): 
     105        if is_typing: 
     106            self._statusBar['text'] = "'%s' is typing.." % (who) 
     107        else: 
     108            self._statusBar['text'] = '' 
    109109 
    110110class AudioState: 
    111         NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5) 
    112                          
     111    NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5) 
     112 
    113113class AudioObserver: 
    114         def onHangup(self, peer_uri): 
    115                 pass 
    116         def onHold(self, peer_uri): 
    117                 pass 
    118         def onUnhold(self, peer_uri): 
    119                 pass 
    120         def onRxMute(self, peer_uri, is_muted): 
    121                 pass 
    122         def onRxVol(self, peer_uri, vol_pct): 
    123                 pass 
    124         def onTxMute(self, peer_uri, is_muted): 
    125                 pass 
    126                          
     114    def onHangup(self, peer_uri): 
     115        pass 
     116    def onHold(self, peer_uri): 
     117        pass 
     118    def onUnhold(self, peer_uri): 
     119        pass 
     120    def onRxMute(self, peer_uri, is_muted): 
     121        pass 
     122    def onRxVol(self, peer_uri, vol_pct): 
     123        pass 
     124    def onTxMute(self, peer_uri, is_muted): 
     125        pass 
     126 
    127127 
    128128class AudioFrame(ttk.Labelframe): 
    129         def __init__(self, master, peer_uri, observer): 
    130                 ttk.Labelframe.__init__(self, master, text=peer_uri) 
    131                 self.peerUri = peer_uri 
    132                 self._observer = observer 
    133                 self._initFrame = None 
    134                 self._callFrame = None 
    135                 self._rxMute = False 
    136                 self._txMute = False 
    137                 self._state = AudioState.NULL 
    138                  
    139                 self._createInitWidgets() 
    140                 self._createWidgets() 
    141                  
    142         def updateState(self, state): 
    143                 if self._state == state: 
    144                         return 
    145  
    146                 if state == AudioState.INITIALIZING: 
    147                         self._callFrame.pack_forget() 
    148                         self._initFrame.pack(fill=tk.BOTH) 
    149                         self._btnCancel.pack(side=tk.TOP) 
    150                         self._lblInitState['text'] = 'Intializing..' 
    151  
    152                 elif state == AudioState.CONNECTED: 
    153                         self._initFrame.pack_forget() 
    154                         self._callFrame.pack(fill=tk.BOTH)                       
    155                 else: 
    156                         self._callFrame.pack_forget() 
    157                         self._initFrame.pack(fill=tk.BOTH) 
    158                         if state == AudioState.FAILED: 
    159                                 self._lblInitState['text'] = 'Failed' 
    160                         else: 
    161                                 self._lblInitState['text'] = 'Normal cleared' 
    162                                 self._btnCancel.pack_forget() 
    163                          
    164                         self._btnHold['text'] = 'Hold' 
    165                         self._btnHold.config(state=tk.NORMAL) 
    166                         self._rxMute = False 
    167                         self._txMute = False 
    168                         self.btnRxMute['text'] = 'Mute' 
    169                         self.btnTxMute['text'] = 'Mute' 
    170                         self.rxVol.set(5.0) 
    171                  
    172                 # save last state 
    173                 self._state = state 
    174                  
    175         def setStatsText(self, stats_str): 
    176                 self.stat.config(state=tk.NORMAL) 
    177                 self.stat.delete("0.0", tk.END) 
    178                 self.stat.insert(tk.END, stats_str) 
    179                 self.stat.config(state=tk.DISABLED) 
    180                  
    181         def _onHold(self): 
    182                 self._btnHold.config(state=tk.DISABLED) 
    183                 # notify app 
    184                 if self._btnHold['text'] == 'Hold': 
    185                         self._observer.onHold(self.peerUri) 
    186                         self._btnHold['text'] = 'Unhold' 
    187                 else: 
    188                         self._observer.onUnhold(self.peerUri) 
    189                         self._btnHold['text'] = 'Hold' 
    190                 self._btnHold.config(state=tk.NORMAL) 
    191  
    192         def _onHangup(self): 
    193                 # notify app 
    194                 self._observer.onHangup(self.peerUri) 
    195  
    196         def _onRxMute(self): 
    197                 # notify app 
    198                 self._rxMute = not self._rxMute 
    199                 self._observer.onRxMute(self.peerUri, self._rxMute) 
    200                 self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute' 
    201                  
    202         def _onRxVol(self, event): 
    203                 # notify app 
    204                 vol = self.rxVol.get() 
    205                 self._observer.onRxVol(self.peerUri, vol*10.0) 
    206  
    207         def _onTxMute(self): 
    208                 # notify app 
    209                 self._txMute = not self._txMute 
    210                 self._observer.onTxMute(self.peerUri, self._txMute) 
    211                 self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute' 
    212  
    213         def _createInitWidgets(self): 
    214                 self._initFrame = ttk.Frame(self) 
    215                 #self._initFrame.pack(fill=tk.BOTH) 
    216  
    217          
    218                 self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='') 
    219                 self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1) 
    220                  
    221                 # Operation: cancel/kick 
    222                 self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup) 
    223                 self._btnCancel.pack(side=tk.TOP) 
    224                                  
    225         def _createWidgets(self): 
    226                 self._callFrame = ttk.Frame(self) 
    227                 #self._callFrame.pack(fill=tk.BOTH) 
    228                  
    229                 # toolbar 
    230                 toolbar = ttk.Frame(self._callFrame) 
    231                 toolbar.pack(side=tk.TOP, fill=tk.X) 
    232                 self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold) 
    233                 self._btnHold.pack(side=tk.LEFT, fill=tk.Y) 
    234                 #self._btnXfer = ttk.Button(toolbar, text='Transfer..') 
    235                 #self._btnXfer.pack(side=tk.LEFT, fill=tk.Y) 
    236                 self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup) 
    237                 self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y) 
    238  
    239                 # volume tool 
    240                 vol_frm = ttk.Frame(self._callFrame) 
    241                 vol_frm.pack(side=tk.TOP, fill=tk.X) 
    242                  
    243                 self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume') 
    244                 self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y) 
    245                  
    246                 self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute) 
    247                 self.btnRxMute.pack(side=tk.LEFT) 
    248                 self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1) 
    249                 self.rxVol.set(5.0) 
    250                 self.rxVol.bind("<ButtonRelease-1>", self._onRxVol) 
    251                 self.rxVol.pack(side=tk.LEFT) 
    252                  
    253                 self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume') 
    254                 self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y) 
    255                  
    256                 self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute) 
    257                 self.btnTxMute.pack(side=tk.LEFT) 
    258                  
    259                 # stat 
    260                 self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Courier", "9")) 
    261                 self.stat.insert(tk.END, 'stat here') 
    262                 self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1) 
     129    def __init__(self, master, peer_uri, observer): 
     130        ttk.Labelframe.__init__(self, master, text=peer_uri) 
     131        self.peerUri = peer_uri 
     132        self._observer = observer 
     133        self._initFrame = None 
     134        self._callFrame = None 
     135        self._rxMute = False 
     136        self._txMute = False 
     137        self._state = AudioState.NULL 
     138 
     139        self._createInitWidgets() 
     140        self._createWidgets() 
     141 
     142    def updateState(self, state): 
     143        if self._state == state: 
     144            return 
     145 
     146        if state == AudioState.INITIALIZING: 
     147            self._callFrame.pack_forget() 
     148            self._initFrame.pack(fill=tk.BOTH) 
     149            self._btnCancel.pack(side=tk.TOP) 
     150            self._lblInitState['text'] = 'Intializing..' 
     151 
     152        elif state == AudioState.CONNECTED: 
     153            self._initFrame.pack_forget() 
     154            self._callFrame.pack(fill=tk.BOTH) 
     155        else: 
     156            self._callFrame.pack_forget() 
     157            self._initFrame.pack(fill=tk.BOTH) 
     158            if state == AudioState.FAILED: 
     159                self._lblInitState['text'] = 'Failed' 
     160            else: 
     161                self._lblInitState['text'] = 'Normal cleared' 
     162                self._btnCancel.pack_forget() 
     163 
     164            self._btnHold['text'] = 'Hold' 
     165            self._btnHold.config(state=tk.NORMAL) 
     166            self._rxMute = False 
     167            self._txMute = False 
     168            self.btnRxMute['text'] = 'Mute' 
     169            self.btnTxMute['text'] = 'Mute' 
     170            self.rxVol.set(5.0) 
     171 
     172        # save last state 
     173        self._state = state 
     174 
     175    def setStatsText(self, stats_str): 
     176        self.stat.config(state=tk.NORMAL) 
     177        self.stat.delete("0.0", tk.END) 
     178        self.stat.insert(tk.END, stats_str) 
     179        self.stat.config(state=tk.DISABLED) 
     180 
     181    def _onHold(self): 
     182        self._btnHold.config(state=tk.DISABLED) 
     183        # notify app 
     184        if self._btnHold['text'] == 'Hold': 
     185            self._observer.onHold(self.peerUri) 
     186            self._btnHold['text'] = 'Unhold' 
     187        else: 
     188            self._observer.onUnhold(self.peerUri) 
     189            self._btnHold['text'] = 'Hold' 
     190        self._btnHold.config(state=tk.NORMAL) 
     191 
     192    def _onHangup(self): 
     193        # notify app 
     194        self._observer.onHangup(self.peerUri) 
     195 
     196    def _onRxMute(self): 
     197        # notify app 
     198        self._rxMute = not self._rxMute 
     199        self._observer.onRxMute(self.peerUri, self._rxMute) 
     200        self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute' 
     201 
     202    def _onRxVol(self, event): 
     203        # notify app 
     204        vol = self.rxVol.get() 
     205        self._observer.onRxVol(self.peerUri, vol*10.0) 
     206 
     207    def _onTxMute(self): 
     208        # notify app 
     209        self._txMute = not self._txMute 
     210        self._observer.onTxMute(self.peerUri, self._txMute) 
     211        self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute' 
     212 
     213    def _createInitWidgets(self): 
     214        self._initFrame = ttk.Frame(self) 
     215        #self._initFrame.pack(fill=tk.BOTH) 
     216 
     217 
     218        self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='') 
     219        self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1) 
     220 
     221        # Operation: cancel/kick 
     222        self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup) 
     223        self._btnCancel.pack(side=tk.TOP) 
     224 
     225    def _createWidgets(self): 
     226        self._callFrame = ttk.Frame(self) 
     227        #self._callFrame.pack(fill=tk.BOTH) 
     228 
     229        # toolbar 
     230        toolbar = ttk.Frame(self._callFrame) 
     231        toolbar.pack(side=tk.TOP, fill=tk.X) 
     232        self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold) 
     233        self._btnHold.pack(side=tk.LEFT, fill=tk.Y) 
     234        #self._btnXfer = ttk.Button(toolbar, text='Transfer..') 
     235        #self._btnXfer.pack(side=tk.LEFT, fill=tk.Y) 
     236        self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup) 
     237        self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y) 
     238 
     239        # volume tool 
     240        vol_frm = ttk.Frame(self._callFrame) 
     241        vol_frm.pack(side=tk.TOP, fill=tk.X) 
     242 
     243        self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume') 
     244        self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y) 
     245 
     246        self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute) 
     247        self.btnRxMute.pack(side=tk.LEFT) 
     248        self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1) 
     249        self.rxVol.set(5.0) 
     250        self.rxVol.bind("<ButtonRelease-1>", self._onRxVol) 
     251        self.rxVol.pack(side=tk.LEFT) 
     252 
     253        self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume') 
     254        self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y) 
     255 
     256        self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute) 
     257        self.btnTxMute.pack(side=tk.LEFT) 
     258 
     259        # stat 
     260        self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Courier", "9")) 
     261        self.stat.insert(tk.END, 'stat here') 
     262        self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1) 
    263263 
    264264 
    265265class ChatObserver(TextObserver, AudioObserver): 
    266         def onAddParticipant(self): 
    267                 pass 
    268         def onStartAudio(self): 
    269                 pass 
    270         def onStopAudio(self): 
    271                 pass 
    272         def onCloseWindow(self): 
    273                 pass 
    274                  
     266    def onAddParticipant(self): 
     267        pass 
     268    def onStartAudio(self): 
     269        pass 
     270    def onStopAudio(self): 
     271        pass 
     272    def onCloseWindow(self): 
     273        pass 
     274 
    275275class ChatFrame(tk.Toplevel): 
    276         """ 
    277         Room 
    278         """ 
    279         def __init__(self, observer): 
    280                 tk.Toplevel.__init__(self) 
    281                 self.protocol("WM_DELETE_WINDOW", self._onClose) 
    282                 self._observer = observer 
    283  
    284                 self._text = None 
    285                 self._text_shown = True 
    286                  
    287                 self._audioEnabled = False 
    288                 self._audioFrames = [] 
    289                 self._createWidgets() 
    290          
    291         def _createWidgets(self): 
    292                 # toolbar 
    293                 self.toolbar = ttk.Frame(self) 
    294                 self.toolbar.pack(side=tk.TOP, fill=tk.BOTH) 
    295                  
    296                 btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText) 
    297                 btnText.pack(side=tk.LEFT, fill=tk.Y) 
    298                 btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio) 
    299                 btnAudio.pack(side=tk.LEFT, fill=tk.Y) 
    300                  
    301                 ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4) 
    302  
    303                 btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant) 
    304                 btnAdd.pack(side=tk.LEFT, fill=tk.Y) 
    305  
    306                 # media frame 
    307                 self.media = ttk.Frame(self) 
    308                 self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1) 
    309                  
    310                 # create Text Chat frame 
    311                 self.media_left = ttk.Frame(self.media) 
    312                 self._text = TextFrame(self.media_left, self._observer) 
    313                 self._text.pack(fill=tk.BOTH, expand=1) 
    314                 self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 
    315                  
    316                 # create other media frame 
    317                 self.media_right = ttk.Frame(self.media) 
    318                  
    319         def _arrangeMediaFrames(self): 
    320                 if len(self._audioFrames) == 0: 
    321                         self.media_right.pack_forget() 
    322                         return 
    323                  
    324                 self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1) 
    325                 MAX_ROWS = 3 
    326                 row_num = 0 
    327                 col_num = 1 
    328                 for frm in self._audioFrames: 
    329                         frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5) 
    330                         row_num += 1 
    331                         if row_num >= MAX_ROWS: 
    332                                 row_num  = 0 
    333                                 col_num += 1 
    334          
    335         def _onShowHideText(self): 
    336                 self.textShowHide(not self._text_shown) 
    337                  
    338         def _onAddParticipant(self): 
    339                 self._observer.onAddParticipant() 
    340          
    341         def _onStartStopAudio(self): 
    342                 self._audioEnabled = not self._audioEnabled 
    343                 if self._audioEnabled: 
    344                         self._observer.onStartAudio() 
    345                 else: 
    346                         self._observer.onStopAudio() 
    347                 self.enableAudio(self._audioEnabled) 
    348                  
    349         def _onClose(self): 
    350                 self._observer.onCloseWindow() 
    351                          
    352         # APIs 
    353          
    354         def bringToFront(self): 
    355                 self.deiconify() 
    356                 self.lift() 
    357                 self._text._typingBox.focus_set() 
    358                  
    359         def textAddMessage(self, msg, is_chat = True): 
    360                 self._text.addMessage(msg, is_chat) 
    361                  
    362         def textSetTypingIndication(self, who, is_typing = True): 
    363                 self._text.setTypingIndication(who, is_typing) 
    364                  
    365         def addParticipant(self, participant_uri): 
    366                 aud_frm = AudioFrame(self.media_right, participant_uri, self._observer) 
    367                 self._audioFrames.append(aud_frm) 
    368          
    369         def delParticipant(self, participant_uri): 
    370                 for aud_frm in self._audioFrames: 
    371                         if participant_uri == aud_frm.peerUri: 
    372                                 self._audioFrames.remove(aud_frm) 
    373                                 # need to delete aud_frm manually? 
    374                                 aud_frm.destroy() 
    375                                 return 
    376  
    377         def textShowHide(self, show = True): 
    378                 if show: 
    379                         self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 
    380                         self._text._typingBox.focus_set() 
    381                 else: 
    382                         self.media_left.pack_forget() 
    383                 self._text_shown = show 
    384          
    385         def enableAudio(self, is_enabled = True): 
    386                 if is_enabled: 
    387                         self._arrangeMediaFrames() 
    388                 else: 
    389                         self.media_right.pack_forget() 
    390                 self._audioEnabled = is_enabled 
    391                          
    392         def audioUpdateState(self, participant_uri, state): 
    393                 for aud_frm in self._audioFrames: 
    394                         if participant_uri == aud_frm.peerUri: 
    395                                 aud_frm.updateState(state) 
    396                                 break 
    397                 if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1: 
    398                         self.enableAudio(False) 
    399                 else: 
    400                         self.enableAudio(True) 
    401                          
    402         def audioSetStatsText(self, participant_uri, stats_str): 
    403                 for aud_frm in self._audioFrames: 
    404                         if participant_uri == aud_frm.peerUri: 
    405                                 aud_frm.setStatsText(stats_str) 
    406                                 break 
    407                                  
     276    """ 
     277    Room 
     278    """ 
     279    def __init__(self, observer): 
     280        tk.Toplevel.__init__(self) 
     281        self.protocol("WM_DELETE_WINDOW", self._onClose) 
     282        self._observer = observer 
     283 
     284        self._text = None 
     285        self._text_shown = True 
     286 
     287        self._audioEnabled = False 
     288        self._audioFrames = [] 
     289        self._createWidgets() 
     290 
     291    def _createWidgets(self): 
     292        # toolbar 
     293        self.toolbar = ttk.Frame(self) 
     294        self.toolbar.pack(side=tk.TOP, fill=tk.BOTH) 
     295 
     296        btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText) 
     297        btnText.pack(side=tk.LEFT, fill=tk.Y) 
     298        btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio) 
     299        btnAudio.pack(side=tk.LEFT, fill=tk.Y) 
     300 
     301        ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4) 
     302 
     303        btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant) 
     304        btnAdd.pack(side=tk.LEFT, fill=tk.Y) 
     305 
     306        # media frame 
     307        self.media = ttk.Frame(self) 
     308        self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1) 
     309 
     310        # create Text Chat frame 
     311        self.media_left = ttk.Frame(self.media) 
     312        self._text = TextFrame(self.media_left, self._observer) 
     313        self._text.pack(fill=tk.BOTH, expand=1) 
     314        self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 
     315 
     316        # create other media frame 
     317        self.media_right = ttk.Frame(self.media) 
     318 
     319    def _arrangeMediaFrames(self): 
     320        if len(self._audioFrames) == 0: 
     321            self.media_right.pack_forget() 
     322            return 
     323 
     324        self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1) 
     325        MAX_ROWS = 3 
     326        row_num = 0 
     327        col_num = 1 
     328        for frm in self._audioFrames: 
     329            frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5) 
     330            row_num += 1 
     331            if row_num >= MAX_ROWS: 
     332                row_num  = 0 
     333                col_num += 1 
     334 
     335    def _onShowHideText(self): 
     336        self.textShowHide(not self._text_shown) 
     337 
     338    def _onAddParticipant(self): 
     339        self._observer.onAddParticipant() 
     340 
     341    def _onStartStopAudio(self): 
     342        self._audioEnabled = not self._audioEnabled 
     343        if self._audioEnabled: 
     344            self._observer.onStartAudio() 
     345        else: 
     346            self._observer.onStopAudio() 
     347        self.enableAudio(self._audioEnabled) 
     348 
     349    def _onClose(self): 
     350        self._observer.onCloseWindow() 
     351 
     352    # APIs 
     353 
     354    def bringToFront(self): 
     355        self.deiconify() 
     356        self.lift() 
     357        self._text._typingBox.focus_set() 
     358 
     359    def textAddMessage(self, msg, is_chat = True): 
     360        self._text.addMessage(msg, is_chat) 
     361 
     362    def textSetTypingIndication(self, who, is_typing = True): 
     363        self._text.setTypingIndication(who, is_typing) 
     364 
     365    def addParticipant(self, participant_uri): 
     366        aud_frm = AudioFrame(self.media_right, participant_uri, self._observer) 
     367        self._audioFrames.append(aud_frm) 
     368 
     369    def delParticipant(self, participant_uri): 
     370        for aud_frm in self._audioFrames: 
     371            if participant_uri == aud_frm.peerUri: 
     372                self._audioFrames.remove(aud_frm) 
     373                # need to delete aud_frm manually? 
     374                aud_frm.destroy() 
     375                return 
     376 
     377    def textShowHide(self, show = True): 
     378        if show: 
     379            self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 
     380            self._text._typingBox.focus_set() 
     381        else: 
     382            self.media_left.pack_forget() 
     383        self._text_shown = show 
     384 
     385    def enableAudio(self, is_enabled = True): 
     386        if is_enabled: 
     387            self._arrangeMediaFrames() 
     388        else: 
     389            self.media_right.pack_forget() 
     390        self._audioEnabled = is_enabled 
     391 
     392    def audioUpdateState(self, participant_uri, state): 
     393        for aud_frm in self._audioFrames: 
     394            if participant_uri == aud_frm.peerUri: 
     395                aud_frm.updateState(state) 
     396                break 
     397        if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1: 
     398            self.enableAudio(False) 
     399        else: 
     400            self.enableAudio(True) 
     401 
     402    def audioSetStatsText(self, participant_uri, stats_str): 
     403        for aud_frm in self._audioFrames: 
     404            if participant_uri == aud_frm.peerUri: 
     405                aud_frm.setStatsText(stats_str) 
     406                break 
     407 
    408408if __name__ == '__main__': 
    409         root = tk.Tk() 
    410         root.title("Chat") 
    411         root.columnconfigure(0, weight=1) 
    412         root.rowconfigure(0, weight=1) 
    413          
    414         obs = ChatObserver() 
    415         dlg = ChatFrame(obs) 
    416         #dlg = TextFrame(root) 
    417         #dlg = AudioFrame(root) 
    418  
    419         #dlg.pack(fill=tk.BOTH, expand=1) 
    420         root.mainloop() 
     409    root = tk.Tk() 
     410    root.title("Chat") 
     411    root.columnconfigure(0, weight=1) 
     412    root.rowconfigure(0, weight=1) 
     413 
     414    obs = ChatObserver() 
     415    dlg = ChatFrame(obs) 
     416    #dlg = TextFrame(root) 
     417    #dlg = AudioFrame(root) 
     418 
     419    #dlg.pack(fill=tk.BOTH, expand=1) 
     420    root.mainloop() 
Note: See TracChangeset for help on using the changeset viewer.