"""dialog~~~~~~A dialog for terminal applications."""fromtypingimportOptional,Sequencefromblessed.keyboardimportKeystrokefromthurible.menuimportOptionfromthurible.panelimportContent,Title# Common dialog options.cont=(Option('Continue',''),)yes_no=(Option('Yes','y'),Option('No','n'),)# Classes.
[docs]classDialog(Content,Title):"""Create a new :class:`thurible.Dialog` object. This class displays a message to the user and offers pre-defined options for the user to chose from. As a subclass of :class:`thurible.panel.Content` and :class:`thurible.panel.Title`, it can also take those parameters and has those public methods and properties. :param message_text: The text of the prompt to be displayed to the user. :param options: The options the user can chose from. This is a sequence of :class:`thurible.Option` objects. :return: A :class:`Dialog` object. :rtype: thurible.Dialog :usage: To create a new :class:`thurible.Dialog` object with the message text `spam` and default yes/no options: .. testcode:: import thurible dialog = thurible.Dialog('spam') Information on the sizing of :class:`thurible.Dialog` objects can be found in the :ref:`sizing` section below. :active keys: This class defines the following :ref:`active keys<active>`: * KEY_ENTER: Select current option. * KEY_LEFT: Move to next option. * KEY_RIGHT: Move to previous option. * <hotkey>: Move to the defined option. """def__init__(self,message_text:str,options:Sequence[Option]=yes_no,*args,**kwargs)->None:super().__init__(*args,**kwargs)self.message_text=message_textself.options=options# Defined action keys.self.register_key('KEY_ENTER',self._select)self.register_key('KEY_LEFT',self._select_left)self.register_key('KEY_RIGHT',self._select_right)foroptioninself.options:hotkey=f"'{option.hotkey}'"self.register_key(hotkey,self._hotkey)self._selected=len(self.options)-1def__str__(self)->str:result=super().__str__()result+=self.messageheight=self.inner_heightwidth=self.inner_widthy=self._align_v('bottom',1,height)+self.inner_yfori,optioninenumerate(self.options[::-1]):opt_text=''ifi==len(self.options)-1-self._selected:opt_text+=self.term.reversename=option.namelength=len(name)+2x=self._align_h('right',length,width)+self.inner_xopt_text+=f'{self.term.move(y,x)}[{name}]'ifi==len(self.options)-1-self._selected:opt_text+=self.term.normalresult+=opt_textwidth-=length+1returnresult# Properties@propertydefmessage(self)->str:""" The message as a string that could be used to update the terminal. :return: A :class:`str` object. :rtype: str """wrapped=self.term.wrap(self.message_text,width=self.inner_width)length=len(wrapped)y=self._align_v('middle',length,self.inner_height)+self.inner_yx=self.inner_xresult=''fori,lineinenumerate(wrapped):result+=f'{self.term.move(y+i,x)}{line}'returnresult# Public methods.
[docs]defaction(self,key:Keystroke)->tuple[str,str]:"""Act on a keystroke typed by the user. :param key: A :class:`blessed.keyboard.Keystroke` object representing the key pressed by the user. :return: A :class:`tuple` object containing two :class:`str` objects. The first string is any data that needs to be sent to the application. The second string contains any updates needed to be made to the terminal display. :rtype: tuple """# These are the results that are returned.data=''update=''ifrepr(key)inself._active_keys:handler=self._active_keys[repr(key)]data=handler(key)else:data=str(key)ifnotdata:height=self.inner_heightwidth=self.inner_widthy=self._align_v('bottom',1,height)fori,optioninenumerate(self.options[::-1]):opt_text=''ifi==len(self.options)-1-self._selected:opt_text+=self.term.reversename=option.namelength=len(name)+2x=self._align_h('right',length,width)opt_text+=f'{self.term.move(y,x)}[{name}]'ifi==len(self.options)-1-self._selected:opt_text+=self.term.normalupdate+=opt_textwidth-=length+1returndata,update
# Private action handlers.def_hotkey(self,key:Optional[Keystroke]=None)->str:"""Select the option assigned to the hot key."""hotkeys=[option.hotkeyforoptioninself.options]self._selected=hotkeys.index(str(key))return''def_select(self,key:Optional[Keystroke]=None)->str:"""Return the name of the selected option."""returnself.options[self._selected].namedef_select_left(self,key:Optional[Keystroke]=None)->str:"""Select the next option to the left."""ifself._selected>0:self._selected-=1return''def_select_right(self,key:Optional[Keystroke]=None)->str:"""Select the next option to the right."""ifself._selected<len(self.options)-1:self._selected+=1return''