ó ur™Vc@sçdZddlZddlmZddlmZddlZddljZddlmZddl m Z m Z m Z m Z dZeedƒƒZeed ƒƒZeed ƒƒZd „Zd „Zd efd„ƒYZdS(s¦ Generic UI pieces representing a portion of the window. Provides support for handling input, writing text to the screen, and managing sub-windows within the window. iÿÿÿÿN(tctrl(tcopy(tLOG_LEVEL_INPUT(tfit_text_truncatetconvert_paragrapht get_encodingt textwidthithtitjcCs|S(sdSupports defining actions which have no effect and allow parent windows to handle the key. ((t input_key((sinner_window.pyt no_action2scCsdS(svSupports defining an action which has no effect, and consume the keystroke so that parents do not handle it. N(tNone(tdummy((sinner_window.pytconsume_action:st InnerWindowc Bs§eZdZejƒZeZeZie j e 6e j e 6e j e6e j e6ZedƒZeedƒƒZddd„Zd„Zd„Zd„Zd„Zd„Zd „Zdddddeddd „Zd „Zd „Z d eed„Z!d d ded„Z"d d ddd„Z#ded„Z$d„Z%d„Z&d„Z'd„Z(d„Z)d„Z*d„Z+d„Z,e-d„ƒZ.d„Z/d„Z0d„Z1RS( sÙWrapper around curses.windows objects providing common functions An InnerWindow wraps around a curses window, and represents an area of the screen. Each InnerWindow requires a parent window. The 'ultimate' parent of all InnerWindows is the sole instance of MainWindow. By default, InnerWindows have functions for adding text, processing input, and managing children InnerWindows. The following class variables are used to indicate the status of ESC key navigations. ESCAPE_SEQ accumulates escape sequences USE_ESC indicates that, at some point during program execution, ESC has been pressed, and the footer should, for the remainder of program execution, print Esc-#_ for navigation descriptions. Once set to True, it should never be set back to False. UPDATE_FOOTER is a flag that indicates that Esc was just hit for the first time, and the managing window should immediately update the footer text. t tLcCs=|jr,|jjƒ|jj||ƒn |jjƒdS(sfCall noutrefresh on the curses window, and synchronize the cursor location as needed N(tis_padtwindowt cursyncuptpadt no_ut_refresht noutrefresh(tselftabs_ytabs_x((sinner_window.pyRes  cCs|jƒtjƒdS(s@Like curses.refresh(), call no_ut_refresh followed by doupdate()N(Rtcursestdoupdate(R((sinner_window.pytrefreshps cCsW|jjƒx|jD]}|jƒqW|jƒx|jD]}|jƒq?WdS(svMark the window and its children so that it will be completely redrawn on the next call to do_update N(Rt redrawwint more_windowsRt all_objects(Rtwintobj((sinner_window.pyRus   cCse|dkrdS|jjtj|ƒ|jƒx.|jD]#}|jtj|ƒ|jƒq:WdS(s§Sets the color attributes to 'color' This private method immediately updates the background color. Note that it doesn't reference self.color N(R RtbkgdRt BKGD_CHARRRR(RtcolorR!((sinner_window.pyt set_colors  cCs]|jsYt|tƒr7|jj|jd|jƒqY|dk rY|jj|ƒqYndS(s\Create a copy of area, and adjust its coordinates to be absolute if needed tborderN(Rt isinstanceRtareatrelative_to_absoluteRt border_sizeR (RR((sinner_window.pyt _adjust_area’s    cCsK||f|_x5|jD]*}|j|jj||jj|ƒqWdS(sjRefresh the actual physical location on the screen of the part of the pad that's visible N(t latest_yxtobjectst deep_refreshR)ty_loctx_loc(RR0R1R"((sinner_window.pyR/žscCsÙ|jr‚tjjd|jj|jj|jj|jjƒ|j j |jj|jj|jj|jjƒ|_ |j |_ n3t j |jj|jj|jj|jjƒ|_ |j jdƒ|j jdƒdS(sCreate the curses windows(lines=%d, columns=%d, y_loc=%d, x_loc=%diiN(Rt terminaluitLOGGERtdebugR)tlinestcolumnsR0R1RtsubwinRRtnewwintkeypadtleaveok(Rtparent((sinner_window.pyt _init_win§s     ic Csž||_t|_| |_d|_d|_i|_i|_t |dt ƒp`t |dt ƒ|_ d|_ g|_ g|_g|_d|_d|_|jƒt|ƒ|_|j|ƒ||_t|tƒr |j|_|j|d|d|ƒ|jdkr)|j|_q)n d|_d|_|j|ƒ|dk rW||_n|jj|_|dk r~||_n |j|_|j |jƒdS(s^Build an InnerWindow area (required): Describes the area to use when building this window. Coordinates should be relative to window, if window is given. If window is not given, these must be absolute coordinates on the terminal window (optional): The parent window. If given, area is assumed to indicate a location within the parent. Additionally, if window is an InnerWindow, window.add_object(self) is called to register this new window with its parent color_theme (required if curses window): The color theme for this window. This property gets propagated to subwindows. If None, the parent window's color_theme is used. Unless this window requires unique coloring, the parent theme should be used. color (optional): The color attributes for this window. If None, color_theme.default is used. In general, this parameter is reserved for subclasses of InnerWindow. Other consumers should pass in an appropriate color_theme. highlight_color (optional): Color attributes for this window when 'selected' or 'highlighted.' Defaults to color (meaning no highlighting is used. In general, this parameter is reserved for subclasses of InnerWindow. Other consumers should pass in an appropriate color_theme Rtat_indext selectableiN(ii(!R+tTrueR>tdata_objR ton_make_activeton_make_inactiveton_make_active_kwargston_make_inactive_kwargstgetattrtFalseRRR.R Rt active_objecttkey_dictt_init_key_dictRR)R,t color_themeR(RR-t add_objectRR<R%tdefaultthighlight_colorR&( RR)RRJR%RMR=tadd_objR+R@((sinner_window.pyt__init__¹sD                         cCsq|j|jƒ|jrK|jdkr4d|_n|j|jjƒnt|jƒrm|j|jndS(sXHighlight this window and activate the active_object, if there is one. iN( R&RMR.RGR t make_activetcallableRARC(R((sinner_window.pyRPs  cCs\|j|jƒ|jdk r6|j|jjƒnt|jƒrX|j|jndS(suMark this window inactive, setting its color back to 'normal' Also make_inactive its active_object. N( R&R%RGR R.t make_inactiveRQRBRD(R((sinner_window.pyRRs cCst|tƒs$|jj|ƒ}n“|r@|t|jƒ}nw|rntt|jƒdtd|ƒƒ}nI|dks|t|jƒkr·d|t|jƒf}t|ƒ‚n|jdk rÝ|j|jj ƒn|j|j ƒ||_t j jtd|jƒ|jƒdS(srSet a specific object to be the active object. This function accepts either an integer index, or an object reference. If an object reference is passed in, it must be an object in this InnerWindow.objects list. if loop == True, integers that are out of bounds of the size of the objects list are shifted to be in bounds. This allows looping from the last item in the list to the first (and vice versa), similar to the syntax for accessing list items. if jump is True, out of bounds integers are rounded to the nearest acceptable value (the first or last object). (Note: loop takes priority over jump; the jump parameter is ignored if loop is True) if both loop and jump are False, and index is an integer < 0 or > len(self.objects), an IndexError is raised. iisIndex (%i) out of range (0-%i)sObject at index %s now activeN(R(tintR.tindextlentmintmaxt IndexErrorRGR RRRPR2R3tlogRR(RRTtlooptjumpterr_msg((sinner_window.pytactivate_objects"(!  c Cs+|jjƒ\}}tjjtd||||||ƒ|jjƒd|jd}||jd7}||} |dkrˆ| }nt|| ƒ}t ||ƒ}|rÇ|t |ƒd|}nt |t ƒrë|j tƒƒ}ntjjtd|||ƒ|jj|||ƒ|jƒdS(s~Add a single line of text to the window 'text' must fit within the specified space, or it will be truncated sMstart_y=%d, start_x=%d, max_chars=%s, centered=%s, win_max_x=%s, win_max_y=%siis9calling addstr with params start_y=%s,start_x=%s, text=%sN(RtgetmaxyxR2R3RYRR+R RVRRR(tunicodetencodeRtaddstrR( Rttexttstart_ytstart_xt max_charstcenteredtwin_ytwin_xtmax_xt abs_max_chars((sinner_window.pytadd_textGs(       c Cs7tjjtd||||ƒ|jjƒ\}}||jd7}|dkri|||jd}n|dkr~|}n|||jdd}|} t|t ƒr¾t ||ƒ}nxn|D]f} tjjtd| | ƒ|j | | ||ƒ| d7} | ||krÅtjj d| ƒPqÅqÅW| |S(s’Add a block of text to the window Add a paragraph to the screen. If a string is passed in, it is converted using convert_paragraph. If a list of strings is passed in, each string will fit in the space alloted (long lines will be truncated). Any lines that would be printed past max_y will not be printed. The number of lines used is returned. s9add_paragraph: start_y=%d, start_x=%d, max_y=%s, max_x=%siiis,add_paragraph:add_text: y_index=%d, line=%s s@Could not fit all text in space for the paragraph. Last line: %sN( R2R3RYRRR^R+R R(t basestringRRktwarn( RRbRcRdtmax_yRit win_size_yt win_size_xRety_indextline((sinner_window.pyt add_paragraphjs.         cCsN|dkrt|jƒ}n|r:|jj||ƒn|jj|ƒdS(s0Add an InnerWindow) to this window's object listN(R RUR.tinsertR tappend(RR"R=R>((sinner_window.pyRK‘s  cCs‡||jkr_|jj|ƒ}||jkrLtd|jdƒ|_n|jj|ƒn|jj|ƒ|jƒ|jƒdS(sgConvenience method for removing an object from both self.objects and self.all_objects iiN(R.RTRGRWtremoveR tclearR(RR"t obj_index((sinner_window.pyt remove_object™s cCsdx|jD]}|jƒq Wg|_g|_d|_|jjƒ|j|jƒ|j ƒdS(sRemove all objects from this window's list and clear the screen Also resets the key_dictionary to a default state The background of this window will still be displayed; clear the parent if the window should be removed in entirety N( R RwR.R RGRteraseR&R%RI(RR"((sinner_window.pyRw¨s    cCsgtjjtdt|ƒƒ|jdk r_y|j|jdƒdSWqctk r[|SXn|SdS(sÂOn curses.KEY_DOWN: Move to the previous active_object, if this window is handling objects. If already at the last object, let the parent handle the keystroke. sInnerWindow.on_key_down %siN( R2R3RYRttypeRGR R]RX(RR ((sinner_window.pyt on_key_down¹s  cCs^tjjtdƒ|jdk rVy|j|jdƒdSWqZtk rR|SXn|SdS(s¸On curses.KEY_UP: Move to the previous active_object, if this window is handling objects. If already at the first object, let the parent handle the keystroke. sInnerWindow.on_key_upiN(R2R3RYRRGR R]RX(RR ((sinner_window.pyt on_key_upÌs cCs5|jdk r-|j|j|dtƒdS|SdS(sIHome -> Jump to first object End -> Jump to last object R[N(RGR R]R.R?(RRTR ((sinner_window.pyt on_home_endÜscCsa|jdkr|S||jj}|j}|j|j|dtƒ|j|krY|SdSdS(sScroll up/down one pageR[N(RGR R)R5R]R?(Rt directionR tpage_lent old_active((sinner_window.pyton_pageçs cCs^|jdk r+|j|jj|ƒ}n|dkr;|S|jj|tƒ}||ƒSdS(sEProcess keyboard input Keyboard input is handled in a "bottom-up" manner. If this window has an active object, the input is passed down to it. If the input isn't handled by the object, this object tries to handle it. If it can't handle it, the keystroke is passed back up the chain. N(RGR R.tprocessRHtgetR (RR thandler((sinner_window.pyRƒõs  cCsßi|_|j|jtj<|j|jtjs  "