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
00013
00014 KeyEvent = clnch_misc.KeyEvent
00015 ChrEvent = clnch_misc.ChrEvent
00016 KeyMapCondition = clnch_misc.KeyMapCondition
00017
00018
00019
00020
00021
00022
00023
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
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
00132
00133
00134
00135
00136
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
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
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
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
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
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
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