CraftLaunch APIリファレンス

clnch_consolewindow.py

00001 import os
00002 import sys
00003 import threading
00004 import Image
00005 
00006 import cterm
00007 from cterm.cterm_const import *
00008 
00009 import clnch_misc
00010 import clnch_plane3x3
00011 import clnch_ini
00012 import clnch_threadutil
00013 import clnch_resource
00014 
00015 #--------------------------------------------------------------------
00016 # ログ
00017 
00018 class Log:
00019 
00020     def __init__(self):
00021         self.lock = threading.Lock()
00022         self.log = [u""]
00023         self.last_line_terminated = False
00024 
00025     def write(self,s):
00026         self.lock.acquire()
00027         try:
00028             if type(s)!=type(u''):
00029                 s = unicode(s,'mbcs')
00030             while True:
00031                 return_pos = s.find("\n")
00032                 if return_pos < 0 : break
00033                 if self.last_line_terminated:
00034                     self.log.append(u"")
00035                 self.log[-1] += s[:return_pos]
00036                 s = s[return_pos+1:]
00037                 self.last_line_terminated = True
00038             if len(s)>0 :
00039                 if self.last_line_terminated:
00040                     self.log.append(u"")
00041                 self.log[-1] += s
00042                 self.last_line_terminated = False
00043             if len(self.log)>1000:
00044                 self.log = self.log[-1000:]
00045         finally:
00046             self.lock.release()
00047 
00048     def numLines(self):
00049         return len(self.log)
00050 
00051     def getLine(self,lineno):
00052         try:
00053             return self.log[lineno]
00054         except IndexError:
00055             return u""
00056 
00057 #--------------------------------------------------------------------
00058 # コンソールウインドウ
00059 
00060 class ConsoleWindow(cterm.Window):
00061     
00062     def __init__( self, parent_window, debug=False ):
00063     
00064         self.initialized = False
00065         
00066         self.loadState()
00067         
00068         self.parent_window = parent_window
00069         
00070         self.active = False
00071 
00072         cterm.Window.__init__(
00073             self,
00074             x = self.window_normal_x,
00075             y = self.window_normal_y,
00076             width = self.window_normal_width,
00077             height = self.window_normal_height,
00078             parent_window=parent_window,
00079             bg_color = (0,0,0),
00080             border_size = 2,
00081             title_bar = False,
00082             title = clnch_resource.clnch_appname + u" Console",
00083             show = False,
00084             icon=False,
00085             activate_handler = self._onActivate,
00086             close_handler = self._onClose,
00087             move_handler = self._onMove,
00088             size_handler = self._onSize,
00089             keydown_handler = self._onKeyDown,
00090             #char_handler = self._onChar,
00091 
00092             lbuttondown_handler = self._onLeftButtonDown,
00093             lbuttonup_handler = self._onLeftButtonUp,
00094             mbuttondown_handler = self._onMiddleButtonDown,
00095             mbuttonup_handler = self._onMiddleButtonUp,
00096             rbuttondown_handler = self._onRightButtonDown,
00097             rbuttonup_handler = self._onRightButtonUp,
00098             lbuttondoubleclick_handler = self._onLeftButtonDoubleClick,
00099             mousemove_handler = self._onMouseMove,
00100             mousewheel_handler= self._onMouseWheel,
00101             )
00102 
00103         self.plane_scrollbar0 = clnch_plane3x3.Plane3x3( self, os.path.join(os.path.split(sys.argv[0])[0],'skin/scrollbar0.png'), 2 )
00104         self.plane_scrollbar1 = clnch_plane3x3.Plane3x3( self, os.path.join(os.path.split(sys.argv[0])[0],'skin/scrollbar1.png'), 1 )
00105 
00106         self.debug = debug
00107 
00108         self.log = Log()
00109         self.scroll_info = clnch_misc.ScrollInfo()
00110         
00111         self.mouse_click_info = None
00112         self.selection = [ [ 0, 0 ], [ 0, 0 ] ]
00113         
00114         self.auto_show = False
00115 
00116         self.initialized = True
00117     
00118         self.paint()
00119 
00120     #--------------------------------------------------------------------------
00121     # 自動表示/非表示
00122     
00123     def show( self, show, activate=True ):
00124         clnch_misc.adjustWindowPosition( self.parent_window, self, default_up=True )
00125         cterm.Window.show( self, show, activate )
00126 
00127     def setAutoShow( self, auto_show ):
00128         self.auto_show = auto_show
00129 
00130     #--------------------------------------------------------------------------
00131     # 領域
00132     
00133     def rectText(self):
00134         return [ 0, 0, self.width()-2, self.height() ]
00135 
00136     def rectScrollbar(self):
00137         return [ self.width()-2, 0, 2, self.height() ]
00138 
00139     #--------------------------------------------------------------------------
00140     # イベントハンドラ
00141 
00142     def _onActivate( self, active ):
00143         self.active = active
00144 
00145     def _onClose(self):
00146         self.show(False)
00147 
00148     def _onMove( self, x, y ):
00149 
00150         if not self.isMaximized() and not self.isMinimized():
00151             self.window_normal_x = x
00152             self.window_normal_y = y
00153 
00154     def _onSize( self, width, height ):
00155 
00156         if not self.isMaximized() and not self.isMinimized():
00157             self.window_normal_width = width
00158             self.window_normal_height = height
00159 
00160         self.paint()
00161 
00162     def _onKeyDown( self, vk, mod ):
00163         
00164         if vk==VK_ESCAPE and mod==0:
00165             self.show(False)
00166 
00167         elif vk==VK_UP and mod==0:
00168             self._scroll(-1)
00169             self.paint()
00170 
00171         elif vk==VK_DOWN and mod==0:
00172             self._scroll(1)
00173             self.paint()
00174 
00175         elif ( vk==VK_PRIOR or vk==VK_LEFT ) and mod==0:
00176             rect = self.rectText()
00177             self._scroll( -(rect[3]-rect[1]) )
00178             self.paint()
00179 
00180         elif ( vk==VK_NEXT or vk==VK_RIGHT ) and mod==0:
00181             rect = self.rectText()
00182             self._scroll( rect[3]-rect[1] )
00183             self.paint()
00184 
00185         elif vk==VK_F1 and mod==0:
00186             def jobHelp(job_item):
00187                 help_path = os.path.join( os.path.split(sys.argv[0])[0], 'doc\\index.html' )
00188                 clnch_misc.shellExecute( None, None, help_path, u"", u"" )
00189 
00190             def jobHelpFinished(job_item):
00191                 print u"Helpを開きました"
00192                 print u""
00193             
00194             job_item = clnch_threadutil.JobItem( jobHelp, jobHelpFinished )
00195             clnch_threadutil.job_queue.enqueue(job_item)
00196 
00197     def _mousePosToCharPos( self, x, y ):
00198         client_rect = self.getClientRect()
00199         offset_x, offset_y = self.charToClient( 0, 0 )
00200         char_w, char_h = self.getCharSize()
00201         char_x = (x-offset_x) / char_w
00202         char_y = (y-offset_y) / char_h
00203         return char_x, char_y
00204 
00205     def _mousePosToLogPos( self, x, y ):
00206         char_x, char_y = self._mousePosToCharPos(x,y)
00207 
00208         char_x = max(char_x,0)
00209         char_x = min(char_x,self.width())
00210 
00211         if char_y < 0:
00212             char_x = 0
00213             char_y = 0
00214 
00215         if char_y > self.height():
00216             char_x = self.width()
00217             char_y = self.height()
00218 
00219         lineno = self.scroll_info.pos+char_y
00220 
00221         s = self.log.getLine(lineno)
00222         
00223         w = 0
00224         char_index = 0
00225         for char_index in xrange(len(s)):
00226             w += self.getStringWidth(s[char_index])
00227             if w > char_x : break
00228         else:
00229             char_index = len(s)
00230         
00231         return lineno, char_index
00232 
00233     def _copySelectedRegion(self):
00234         
00235         joint_text = u""
00236         
00237         selection_left, selection_right = self.selection 
00238         if selection_left > selection_right:
00239             selection_left, selection_right = selection_right, selection_left
00240 
00241         i = selection_left[0]
00242         while i<=selection_right[0] and i<self.log.numLines():
00243         
00244             s = self.log.getLine(i)
00245 
00246             if i==selection_left[0]:
00247                 left = selection_left[1]
00248             else:
00249                 left = 0
00250 
00251             if i==selection_right[0]:
00252                 right = selection_right[1]
00253             else:
00254                 right = len(s)
00255             
00256             joint_text += s[left:right]
00257             
00258             if i!=selection_right[0]:
00259                 joint_text += "\r\n"
00260             
00261             i += 1    
00262         
00263         if joint_text:
00264             clnch_misc.setClipboardText(joint_text)
00265 
00266     def _onLeftButtonDown( self, x, y, mod ):
00267 
00268         lineno, char_index = self._mousePosToLogPos(x,y)
00269         
00270         self.mouse_click_info = [ False, x, y, lineno, char_index ]
00271         self.setCapture()
00272 
00273         self.selection = [
00274             [ lineno, char_index ],
00275             [ lineno, char_index ]
00276             ]
00277         self.paint()    
00278 
00279     def _onLeftButtonUp( self, x, y, mod ):
00280         self.mouse_click_info = None
00281         self.releaseCapture()
00282         self._copySelectedRegion()
00283 
00284     def _onMiddleButtonDown( self, x, y, mod ):
00285         self.mouse_click_info = None
00286 
00287     def _onMiddleButtonUp( self, x, y, mod ):
00288         self.mouse_click_info = None
00289 
00290     def _onRightButtonDown( self, x, y, mod ):
00291         self.mouse_click_info = None
00292 
00293     def _onRightButtonUp( self, x, y, mod ):
00294         self.mouse_click_info = None
00295 
00296     def _wordbreak( self, s, pos, step ):
00297 
00298         word_break_chars1 = "\"!@#$%^&*()+|~-=\`[]{};:',./<>?"
00299         word_break_chars2 = " \t"
00300 
00301         while True:
00302             if pos<=0 : return 0
00303             if pos>=len(s) : return len(s)
00304 
00305             if s[pos-1] in word_break_chars1:
00306                 left_char_type = 1
00307             elif s[pos-1] in word_break_chars2:
00308                 left_char_type = 2
00309             else:
00310                 left_char_type = 0
00311 
00312             if s[pos] in word_break_chars1:
00313                 right_char_type = 1
00314             elif s[pos] in word_break_chars2:
00315                 right_char_type = 2
00316             else:
00317                 right_char_type = 0
00318 
00319             if left_char_type!=0:
00320                 if right_char_type==0:
00321                     return pos
00322 
00323             pos += step
00324 
00325     def _onLeftButtonDoubleClick( self, x, y, mod ):
00326 
00327         lineno, char_index = self._mousePosToLogPos(x,y)
00328         
00329         s = self.log.getLine(lineno)
00330 
00331         left = max( self._wordbreak( s, char_index, -1 ), 0 )
00332         right = min( self._wordbreak( s, char_index+1, +1 ), len(s) )
00333 
00334         self.mouse_click_info = [ True, x, y, lineno, left, lineno, right ]
00335         self.setCapture()
00336 
00337         self.selection = [
00338             [ lineno, left ],
00339             [ lineno, right ]
00340             ]
00341             
00342         self.paint()    
00343 
00344     def _onMouseMove( self, x, y, mod ):
00345     
00346         if self.mouse_click_info:
00347         
00348             char_x, char_y = self._mousePosToCharPos(x,y)
00349 
00350             if char_y < 0:
00351                 self._scroll(-1)
00352             elif char_y >= self.height():
00353                 self._scroll(1)
00354 
00355             lineno, char_index = self._mousePosToLogPos(x,y)
00356 
00357             double_click = self.mouse_click_info[0]
00358             if double_click:
00359                 
00360                 s = self.log.getLine(lineno)
00361                 
00362                 if [ lineno, char_index ] > self.selection[0]:
00363                     right = min( self._wordbreak( s, char_index+1, +1 ), len(s) )
00364                     self.selection[0] = self.mouse_click_info[3:5]
00365                     self.selection[1] = [ lineno, right ]
00366                 else:    
00367                     left = max( self._wordbreak( s, char_index, -1 ), 0 )
00368                     self.selection[0] = self.mouse_click_info[5:7]
00369                     self.selection[1] = [ lineno, left ]
00370             
00371             else:
00372                 self.selection[1] = [ lineno, char_index ]
00373 
00374             self.paint()
00375 
00376     def _scroll( self, delta ):
00377         self.scroll_info.pos += delta
00378         self.scroll_info.pos = min( self.scroll_info.pos, self.log.numLines()-self.height() )
00379         self.scroll_info.pos = max( self.scroll_info.pos, 0 )
00380 
00381     def _onMouseWheel( self, x, y, wheel, mod ):
00382 
00383         while wheel>0:
00384             self._scroll(-1)
00385             wheel-=1
00386         while wheel<0:
00387             self._scroll(+1)
00388             wheel+=1
00389 
00390         self.paint()
00391 
00392     #--------------------------------------------------------------------------
00393     # 標準出力の置き換え
00394 
00395     def registerStdio(self):
00396     
00397         def writeCommon(s):
00398             make_visible = False
00399             if self.log.numLines()-1 < self.scroll_info.pos + self.height():
00400                 make_visible = True
00401         
00402             self.log.write(s)
00403 
00404             if make_visible:
00405                 self.scroll_info.makeVisible( self.log.numLines()-1, self.height() )
00406 
00407             self.paint()
00408             
00409         class Stdout:
00410             def write( writer_self, s ):
00411                 writeCommon(s)
00412                 if self.auto_show:
00413                     self.show(True,False)
00414                 
00415         class Stderr:
00416             def write( writer_self, s ):
00417                 writeCommon(s)
00418                 if self.auto_show:
00419                     self.show(True,False)
00420 
00421         class DebugStdout:
00422             def write( writer_self, s ):
00423                 if type(s)==type(u''):
00424                     s = s.encode("mbcs")
00425                 sys.__stdout__.write(s)
00426 
00427         class DebugStderr:
00428             def write( writer_self, s ):
00429                 if type(s)==type(u''):
00430                     s = s.encode("mbcs")
00431                 sys.__stdout__.write(s)
00432 
00433         if self.debug:
00434             sys.stdout = DebugStdout()
00435             sys.stderr = DebugStderr()
00436         else:
00437             sys.stdout = Stdout()
00438             sys.stderr = Stderr()
00439 
00440     def unregisterStdio(self):
00441         sys.stdout = sys.__stdout__
00442         sys.stderr = sys.__stderr__
00443 
00444     #--------------------------------------------------------------------------
00445     def updateFont(self):
00446         self.setFont( clnch_ini.get( "FONT", "name", "" ), clnch_ini.getint( "FONT", "size", 12 ) )
00447         window_rect = self.getWindowRect()
00448         self.setPosSize( window_rect[0], window_rect[1], self.width(), self.height(), 0 )
00449 
00450     #--------------------------------------------------------------------------
00451     # 描画
00452 
00453     def paint(self):
00454     
00455         # テキスト
00456         if 1:
00457             x, y, width, height = self.rectText()
00458     
00459             attr = cterm.Attribute( fg=(255,255,255) )
00460             attr_selected = cterm.Attribute( fg=(255,255,255), bg=(30,100,150) )
00461         
00462             selection_left, selection_right = self.selection 
00463             if selection_left > selection_right:
00464                 selection_left, selection_right = selection_right, selection_left
00465         
00466             for i in xrange(height):
00467 
00468                 if self.scroll_info.pos+i < self.log.numLines():
00469             
00470                     if selection_left[0] <= self.scroll_info.pos+i <= selection_right[0]:
00471                     
00472                         s = self.log.getLine( self.scroll_info.pos + i )
00473                     
00474                         if selection_left[0]==self.scroll_info.pos+i:
00475                             left = selection_left[1]
00476                         else:
00477                             left = 0
00478 
00479                         if selection_right[0]==self.scroll_info.pos+i:
00480                             right = selection_right[1]
00481                         else:
00482                             right = len(s)
00483                     
00484                         s = [ s[0:left], s[left:right], s[right:len(s)] ]
00485                     
00486                         line_x = x
00487 
00488                         self.putString( line_x, y+i, width-line_x, 1, attr, s[0] )
00489                         line_x += self.getStringWidth(s[0])
00490 
00491                         self.putString( line_x, y+i, width-line_x, 1, attr_selected, s[1] )
00492                         line_x += self.getStringWidth(s[1])
00493                     
00494                         self.putString( line_x, y+i, width-line_x, 1, attr, s[2] )
00495                         line_x += self.getStringWidth(s[2])
00496 
00497                         self.putString( line_x, y+i, width-line_x, 1, attr, u" " * (width-line_x) )
00498                     
00499                     else:
00500                         s = self.log.getLine( self.scroll_info.pos + i )
00501                         self.putString( x, y+i, width, 1, attr, s )
00502                         w = self.getStringWidth(s)
00503                         space_x = x + w
00504                         space_width = width - w
00505                         self.putString( space_x, y+i, space_width, 1, attr, u" " * space_width )
00506                 else:
00507                     self.putString( x, y+i, width, 1, attr, u" " * width )
00508 
00509         # スクロールバー
00510         if 1:
00511             x, y, width, height = self.rectScrollbar()
00512 
00513             for i in xrange(height):
00514                 self.putString( x, y+i, width, 1, attr, u" " * width )
00515 
00516             client_rect = self.getClientRect()
00517             scrollbar_left, tmp = self.charToClient( self.width()-2, 0 )
00518             
00519             scrollbar0_rect = [ scrollbar_left, 0, client_rect[2], client_rect[3] ]
00520             
00521             scrollbar1_height = client_rect[3] * self.height() / self.log.numLines()
00522             scrollbar1_height = min( scrollbar1_height, client_rect[3] )
00523             scrollbar1_height = max( scrollbar1_height, 12 )
00524             
00525             scrollbar1_pos = (client_rect[3]-scrollbar1_height) * self.scroll_info.pos / max((self.log.numLines()-self.height()),1)
00526             
00527             scrollbar1_rect = [ scrollbar_left, scrollbar1_pos, client_rect[2], scrollbar1_pos+scrollbar1_height ]
00528 
00529             self.plane_scrollbar0.adjust( scrollbar0_rect )
00530             self.plane_scrollbar1.adjust( scrollbar1_rect )
00531 
00532     #--------------------------------------------------------------------------
00533     # 状態の保存と復帰
00534 
00535     def loadState(self):
00536         self.window_normal_x = clnch_ini.getint( "CONSOLE", "x", 0 )
00537         self.window_normal_y = clnch_ini.getint( "CONSOLE", "y", 0 )
00538         self.window_normal_width = clnch_ini.getint( "CONSOLE", "width", 80 )
00539         self.window_normal_height = clnch_ini.getint( "CONSOLE", "height", 32 )
00540     
00541     def saveState(self):
00542         clnch_ini.set( "CONSOLE", "x", str(self.window_normal_x) )
00543         clnch_ini.set( "CONSOLE", "y", str(self.window_normal_y) )
00544         clnch_ini.set( "CONSOLE", "width", str(self.window_normal_width) )
00545         clnch_ini.set( "CONSOLE", "height", str(self.window_normal_height) )
00546 
00547     #--------------------------------------------------------------------------
00548     # ログのクリア
00549 
00550     def clearLog(self):
00551         self.log = Log()
00552         self.scroll_info = clnch_misc.ScrollInfo()
00553         self.mouse_click_info = None
00554         self.selection = [ [ 0, 0 ], [ 0, 0 ] ]
00555         self.paint()
00556 
00557         

Copyright © 2009 craftware. All rights reserved.