CraftLaunch APIリファレンス

clnch_listwindow.py

00001 import sys
00002 import os
00003 
00004 import cterm
00005 from cterm.cterm_const import *
00006 
00007 import clnch_isearch
00008 import clnch_statusbar
00009 import clnch_misc
00010 import clnch_skin
00011 import clnch_colortable
00012 #import clnch_usernamespace
00013 
00014 KeyEvent = clnch_misc.KeyEvent
00015 ChrEvent = clnch_misc.ChrEvent
00016 KeyMapCondition = clnch_misc.KeyMapCondition
00017 
00018 #--------------------------------------------------------------------
00019 
00020 ## リストウインドウ
00021 #
00022 #  各種のリスト形式ウインドウを実現しているクラスです。\n\n
00023 #  設定ファイル config.py の configure_ListWindow に渡される window 引数は、ListWindow クラスのオブジェクトです。
00024 #
00025 class ListWindow( cterm.Window ):
00026 
00027     def __init__( self, x, y, min_width, min_height, max_width, max_height, parent_window, show=True, title=u"", items=[], initial_select=0, onekey_search=True, onekey_decide=False, return_modkey=False, keydown_hook=None, statusbar_handler=None ):
00028 
00029         cterm.Window.__init__(
00030             self,
00031             x=x,
00032             y=y,
00033             width=5,
00034             height=5,
00035             origin= ORIGIN_X_CENTER | ORIGIN_Y_CENTER,
00036             parent_window=parent_window,
00037             bg_color = clnch_colortable.bg,
00038             show = False,
00039             resizable = False,
00040             title = title,
00041             minimizebox = False,
00042             maximizebox = False,
00043             close_handler = self.onClose,
00044             keydown_handler = self.onKeyDown,
00045             char_handler = self.onChar,
00046             )
00047 
00048         max_item_width = 0
00049         for item in items:
00050             if isinstance(item,list) or isinstance(item,tuple):
00051                 item = item[0]
00052             item_width = self.getStringWidth(item)
00053             if item_width>max_item_width:
00054                 max_item_width=item_width
00055 
00056         window_width = max_item_width
00057         window_height = len(items)
00058         
00059         if statusbar_handler:
00060             window_height += 1
00061         
00062         window_width = min(window_width,max_width)
00063         window_height = min(window_height,max_height)
00064 
00065         window_width = max(window_width,min_width)
00066         window_height = max(window_height,min_height)
00067 
00068         self.setPosSize(
00069             x=x,
00070             y=y,
00071             width=window_width,
00072             height=window_height,
00073             origin= ORIGIN_X_CENTER | ORIGIN_Y_CENTER
00074             )
00075         self.show(show)
00076 
00077         self.title = title
00078         self.items = items
00079         self.scroll_info = clnch_misc.ScrollInfo()
00080         self.select = initial_select
00081         self.result_mod = 0
00082         self.onekey_search = onekey_search
00083         self.onekey_decide = onekey_decide
00084         self.return_modkey = return_modkey
00085         self.keydown_hook = keydown_hook
00086         self.statusbar_handler = statusbar_handler
00087 
00088         self.status_bar = None
00089         self.status_bar_layer = None
00090         self.skin_statusbar = None
00091 
00092         self.isearch = None
00093         self.skin_isearch = None
00094         
00095         if statusbar_handler:
00096             self.status_bar = clnch_statusbar.StatusBar()
00097             self.status_bar_layer = clnch_statusbar.SimpleStatusBarLayer()
00098             self.status_bar.registerLayer(self.status_bar_layer)
00099 
00100             self.skin_statusbar = clnch_skin.SkinPlane( self, os.path.join( os.path.split(sys.argv[0])[0], 'skin/statusbar.png' ) )
00101             client_rect = self.getClientRect()
00102             pos1 = self.charToClient( 0, self.height()-1 )
00103             char_w, char_h = self.getCharSize()
00104             self.skin_statusbar.adjust( ( pos1[0]-char_w/2, pos1[1], self.width()*char_w+char_w, client_rect[3]-pos1[1] ) )
00105             self.skin_statusbar.show(True)
00106 
00107             self.skin_isearch = clnch_skin.SkinPlane( self, os.path.join( os.path.split(sys.argv[0])[0], 'skin/isearch.png' ), 1 )
00108             self.skin_isearch.adjust( ( pos1[0]-char_w/2, pos1[1], self.width()*char_w+char_w, client_rect[3]-pos1[1] ) )
00109             self.skin_isearch.show(False)
00110 
00111         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00112         
00113         self.configure()
00114         
00115         self.paint()
00116 
00117     ## 設定を読み込む
00118     #
00119     #  キーマップなどをリセットした上で、config,py の configure_ListWindow() を呼び出します。
00120     #
00121     def configure(self):
00122         self.keymap = clnch_misc.KeyMap()
00123         self.keymap[ KeyEvent( VK_UP, 0 ) ] = self.command_CursorUp
00124         self.keymap[ KeyEvent( VK_DOWN, 0 ) ] = self.command_CursorDown
00125         self.keymap[ KeyEvent( VK_PRIOR, 0 ) ] = self.command_CursorPageUp
00126         self.keymap[ KeyEvent( VK_NEXT, 0 ) ] = self.command_CursorPageDown
00127         self.keymap[ KeyEvent( VK_RETURN, 0 ) ] = self.command_Enter
00128         self.keymap[ KeyEvent( VK_ESCAPE, 0 ) ] = self.command_Cancel
00129         if not self.onekey_search:
00130             self.keymap[ KeyEvent( ord('F'), 0 ) ] = self.command_IncrementalSearch
00131         #clnch_usernamespace.call("configure_ListWindow",self)
00132 
00133     ## リストの項目を1つ削除する
00134     #
00135     #  @param self  -
00136     #  @param index 削除する項目のインデックス
00137     #
00138     def remove( self, index ):
00139         
00140         del self.items[index]
00141         
00142         if self.select > index:
00143             self.select -= 1
00144         
00145         if not len(self.items):
00146             self.select = -1
00147             self.quit()
00148             return
00149 
00150         if self.select<0 : self.select=0
00151         if self.select>len(self.items)-1 : self.select=len(self.items)-1
00152 
00153         self.paint()
00154 
00155     def onClose(self):
00156         self.quit()
00157 
00158     def onKeyDown( self, vk, mod ):
00159 
00160         if self.keydown_hook:
00161             if self.keydown_hook( vk, mod ):
00162                 return True
00163 
00164         try:
00165             func = self.keymap[ KeyMapCondition( KeyEvent(vk,mod) ) ]
00166         except KeyError:
00167             return
00168 
00169         self.result_mod = mod
00170         func()
00171 
00172         return True
00173 
00174     def onChar( self, ch, mod ):
00175 
00176         try:
00177             func = self.keymap[ KeyMapCondition( ChrEvent(ch) ) ]
00178         except KeyError:
00179             func = None
00180 
00181         if func:
00182             self.result_mod = mod
00183             func()
00184             return True
00185 
00186         if self.onekey_search:
00187         
00188             if 0x20<=ch<0x100:
00189                 if not len(self.items): return
00190 
00191                 found = []
00192                 
00193                 for i in xrange( self.select+1, len(self.items) ):
00194 
00195                     item = self.items[i]
00196                     if isinstance(item,list) or isinstance(item,tuple):
00197                         item = item[0]
00198 
00199                     if item[0].upper()==chr(ch).upper():
00200                         found.append(i)
00201                         if len(found)>=2 : break
00202 
00203                 if len(found)<2 :
00204                     for i in xrange( self.select+1 ):
00205 
00206                         item = self.items[i]
00207                         if isinstance(item,list) or isinstance(item,tuple):
00208                             item = item[0]
00209 
00210                         if item[0].upper()==chr(ch).upper():
00211                             found.append(i)
00212                             if len(found)>=2 : break
00213 
00214                 if found:
00215                     if self.onekey_decide and len(found)==1:
00216                         self.select = found[0]
00217                         self.result_mod = mod
00218                         self.quit()
00219                     else:
00220                         self.select = found[0]
00221                         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00222                         self.paint()
00223 
00224         else:
00225             
00226             if self.isearch:
00227 
00228                 if ch==ord('\b'):
00229                     isearch_newvalue = self.isearch.isearch_value[:-1]
00230                 elif ch==ord(' '):
00231                     return
00232                 else:
00233                     isearch_newvalue = self.isearch.isearch_value + unichr(ch)
00234 
00235                 accept = False
00236 
00237                 item = self.items[self.select]
00238                 if isinstance(item,list) or isinstance(item,tuple):
00239                     item = item[0]
00240             
00241                 if self.isearch.fnmatch( item, isearch_newvalue ):
00242                     accept = True
00243                 else:
00244                 
00245                     if self.isearch.isearch_type=="inaccurate":
00246                         isearch_type_list = [ "strict", "partial", "inaccurate" ]
00247                     else:
00248                         isearch_type_list = [ "strict", "partial", "migemo" ]
00249                 
00250                     last_type_index = isearch_type_list.index(self.isearch.isearch_type)
00251                     for isearch_type_index in xrange(last_type_index+1):
00252                         for i in xrange( len(self.items) ):
00253                         
00254                             item = self.items[i]
00255                             if isinstance(item,list) or isinstance(item,tuple):
00256                                 item = item[0]
00257                         
00258                             if self.isearch.fnmatch( item, isearch_newvalue, isearch_type_list[isearch_type_index] ):
00259                                 self.select = i
00260                                 self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00261                                 accept = True
00262                                 break
00263                         if accept: break
00264         
00265                 if accept:
00266                     self.isearch.isearch_value = isearch_newvalue
00267                     self.paint()
00268 
00269 
00270     def itemsHeight(self):
00271         if self.status_bar:
00272             return self.height()-1
00273         else:
00274             return self.height()
00275 
00276     def paint(self):
00277 
00278         x=0
00279         y=0
00280         width=self.width()
00281         height=self.itemsHeight()
00282 
00283         attribute_normal = cterm.Attribute( fg=clnch_colortable.fg )
00284         attribute_normal_selected = cterm.Attribute( fg=clnch_colortable.fg, bg=clnch_colortable.select_bg )
00285         
00286         for i in xrange(height):
00287             index = self.scroll_info.pos+i
00288             if index < len(self.items):
00289 
00290                 item = self.items[index]
00291                 if isinstance(item,list) or isinstance(item,tuple):
00292                     item = item[0]
00293 
00294                 if self.select==index:
00295                     attr=attribute_normal_selected
00296                 else:
00297                     attr=attribute_normal
00298                 self.putString( x, y+i, width, 1, attr, u" " * width )
00299                 self.putString( x, y+i, width, 1, attr, item )
00300             else:
00301                 self.putString( x, y+i, width, 1, attribute_normal, u" " * width )
00302 
00303         if self.status_bar:
00304             if self.isearch:
00305                 attr = cterm.Attribute( fg=clnch_colortable.edit_fg )
00306                 s = u" Search : %s_" % ( self.isearch.isearch_value )
00307                 s = clnch_misc.adjustStringWidth(self,s,width-1)
00308                 self.putString( 0, self.height()-1, width-1, 1, attr, s )
00309             else:
00310                 self.status_bar_layer.setMessage( self.statusbar_handler( width, self.select ) )
00311                 self.status_bar.paint( self, 0, self.height()-1, width, 1 )
00312         else:
00313             if self.isearch:
00314                 s = u" Search : %s_" % ( self.isearch.isearch_value )
00315                 self.setTitle(s)
00316             else:
00317                 self.setTitle(self.title)
00318 
00319     def getResult(self):
00320         if self.return_modkey:
00321             return self.select, self.result_mod
00322         else:
00323             return self.select
00324 
00325     ## リストウインドウをキャンセルして閉じる
00326     def cancel(self):
00327         self.select = -1
00328         self.quit()
00329 
00330     #--------------------------------------------------------
00331     # ここから下のメソッドはキーに割り当てることができる
00332     #--------------------------------------------------------
00333 
00334     ## カーソルを1つ上に移動させる
00335     def command_CursorUp(self):
00336         self.select -= 1
00337         if self.select<0 : self.select=0
00338         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00339         self.paint()
00340 
00341     ## カーソルを1つ下に移動させる
00342     def command_CursorDown(self):
00343         self.select += 1
00344         if self.select>len(self.items)-1 : self.select=len(self.items)-1
00345         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00346         self.paint()
00347 
00348     ## 1ページ上方向にカーソルを移動させる
00349     def command_CursorPageUp(self):
00350         if self.isearch:
00351             return
00352         if self.select>self.scroll_info.pos :
00353             self.select = self.scroll_info.pos
00354         else:
00355             self.select -= self.itemsHeight()
00356             if self.select<0 : self.select=0
00357             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00358         self.paint()
00359 
00360     ## 1ページ下方向にカーソルを移動させる
00361     def command_CursorPageDown(self):
00362         if self.isearch:
00363             return
00364         if self.select<self.scroll_info.pos+self.itemsHeight()-1:
00365             self.select = self.scroll_info.pos+self.itemsHeight()-1
00366         else:
00367             self.select += self.itemsHeight()
00368         if self.select>len(self.items)-1 : self.select=len(self.items)-1
00369         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00370         self.paint()
00371 
00372     ## 決定する
00373     def command_Enter(self):
00374         self.quit()
00375 
00376     ## キャンセルする
00377     def command_Cancel(self):
00378         self.cancel()
00379 
00380     ## インクリメンタルサーチを行う
00381     def command_IncrementalSearch(self):
00382         
00383         def finish():
00384             if self.skin_isearch:
00385                 self.skin_isearch.show(False)
00386             self.isearch = None
00387             self.keydown_hook = self.keydown_hook_old
00388             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00389             self.paint()
00390 
00391         def getString(i):
00392             item = self.items[i]
00393             if isinstance(item,list) or isinstance(item,tuple):
00394                 item = item[0]
00395             return item    
00396 
00397         def cursorUp():
00398             self.select = self.isearch.cursorUp( getString, len(self.items), self.select, self.scroll_info.pos, self.itemsHeight() )
00399             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00400             self.paint()
00401 
00402         def cursorDown():
00403             self.select = self.isearch.cursorDown( getString, len(self.items), self.select, self.scroll_info.pos, self.itemsHeight() )
00404             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00405             self.paint()
00406 
00407         def cursorPageUp():
00408             self.select = self.isearch.cursorPageUp( getString, len(self.items), self.select, self.scroll_info.pos, self.itemsHeight() )
00409             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00410             self.paint()
00411 
00412         def cursorPageDown():
00413             self.select = self.isearch.cursorPageDown( getString, len(self.items), self.select, self.scroll_info.pos, self.itemsHeight() )
00414             self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00415             self.paint()
00416 
00417         def onKeyDown( vk, mod ):
00418 
00419             if vk==VK_RETURN:
00420                 finish()
00421             elif vk==VK_ESCAPE:
00422                 finish()
00423             elif vk==VK_UP:
00424                 cursorUp()
00425             elif vk==VK_DOWN:
00426                 cursorDown()
00427             elif vk==VK_PRIOR:
00428                 cursorPageUp()
00429             elif vk==VK_NEXT:
00430                 cursorPageDown()
00431 
00432             return True
00433     
00434         self.removeKeyMessage()
00435 
00436         self.isearch = clnch_isearch.IncrementalSearch()
00437         self.keydown_hook_old = self.keydown_hook
00438         self.keydown_hook = onKeyDown
00439         if self.skin_isearch:
00440             self.skin_isearch.show(True)
00441         self.scroll_info.makeVisible( self.select, self.itemsHeight() )
00442         self.paint()
00443 
00444 
00445 ## @addtogroup global グローバル関数
00446 ## @{
00447 
00448 ## ポップアップメニューを表示する
00449 #
00450 #  @param main_window       MainWindowオブジェクト
00451 #  @param title             メニューウインドウのタイトルバーに表示する文字列
00452 #  @param items             メニューに表示するアイテムのリスト
00453 #  @param initial_select    初期選択位置
00454 #  @param onekey_search     文字入力で項目の先頭文字を検索するか
00455 #  @param onekey_decide     先頭文字の検索で候補が1つだけだったとき即時決定するか
00456 #  @param return_modkey     メニューが閉じたときに押されていたモディファイアキーを取得するか
00457 #  @param keydown_hook      キー入力イベントのフック
00458 #  @param statusbar_handler ステータスバーに表示する文字列を返すハンドラ
00459 #
00460 #  @return                  引数 return_modkey が False の場合は結果値 (選択されたアイテムのインデックスか、キャンセルされた場合は-1)、引数 return_modkey が True の場合は ( 結果値, モディファイアキーの状態 ) を返す。
00461 #
00462 #  引数 items には、( 表示名, ... ) 形式のアイテムをリストに格納して渡します。[ ... ] の部分には、どのようなデータが入ってもかまいません。\n\n
00463 #
00464 #  onekey_search に True を渡したときは、キー入力で項目の先頭文字を検索します。onekey_search に False を渡したときは、F キーでインクリメンタルサーチが開始します。\n\n
00465 #
00466 #  statusbar_handler にハンドラを渡したときは、ステータスバーが表示されます。\n\n
00467 #
00468 #  インクリメンタルサーチの検索パターンは、ステータスバーが有効な場合はステータスバーに表示され、ステータスバーが無効な場合はタイトルバーに表示されます。
00469 #
00470 def popMenu( main_window, max_width=None, max_height=None, title=u"", items=[], initial_select=0, onekey_search=True, onekey_decide=False, return_modkey=False, keydown_hook=None, statusbar_handler=None ):
00471     pos = main_window.centerOfWindowInPixel()
00472     list_window = ListWindow( pos[0], pos[1], 5, 1, max_width, max_height, main_window, False, title, items, initial_select=initial_select, onekey_search=onekey_search, onekey_decide=onekey_decide, return_modkey=return_modkey, keydown_hook=keydown_hook, statusbar_handler=statusbar_handler )
00473     clnch_misc.adjustWindowPosition( main_window, list_window, default_up=False )
00474     list_window.show(True)
00475     main_window.enable(False)
00476     list_window.messageLoop()
00477     result = list_window.getResult()
00478     main_window.enable(True)
00479     main_window.activate()
00480     list_window.destroy()
00481     return result
00482 
00483 ## @} global

Copyright © 2009 craftware. All rights reserved.