Source code for GLXCurses.StatusBar

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# It script it publish under GNU GENERAL PUBLIC LICENSE
# http://www.gnu.org/licenses/gpl-3.0.en.html
# Author: the Galaxie Curses Team, all rights reserved

import GLXCurses
import curses
import logging
import locale

locale.setlocale(locale.LC_ALL, "")
code = locale.getpreferredencoding()


[docs]class StatusBar(GLXCurses.Widget): """ A StatusBar is usually placed along the bottom of an Application. It may provide a regular commentary of the application's status (as is usually the case in a web browser, for example), or may be used to simply output a message when the status changes, (when an upload is complete in an FTP client, for example). Status bars in GLXCurses maintain a stack of messages. The message at the top of the each bar’s stack is the one that will currently be displayed. Any messages added to a StatusBar’s stack must specify a context id that is used to uniquely identify the source of a message. This context id can be generated by :func:`GLXCurses.StatusBar.get_context_id() <GLXCurses.StatusBar.StatusBar.get_context_id>`, given a message and the StatusBar that it will be added to. Note that messages are stored in a stack, and when choosing which message to display, the stack structure is adhered to, regardless of the context identifier of a message. One could say that a StatusBar maintains one stack of messages for display purposes, but allows multiple message producers to maintain sub-stacks of the messages they produced (via context ids). Status bars are created using :func:`GLXCurses.StatusBar.new() <GLXCurses.StatusBar.StatusBar.new>`. Messages are added to the bar’s stack with :func:`GLXCurses.StatusBar.push() <GLXCurses.StatusBar.StatusBar.push>`. The message at the top of the stack can be removed using :func:`GLXCurses.StatusBar.pop() <GLXCurses.StatusBar.StatusBar.pop>`. A message can be removed from anywhere in the stack if its message id was recorded at the time it was added. This is done using :func:`GLXCurses.StatusBar.remove() <GLXCurses.StatusBar.StatusBar.remove>`. """ def __init__(self): # Load heritage GLXCurses.Widget.__init__(self) # It's a GLXCurse Type self.glxc_type = "GLXCurses.StatusBar" self.name = "{0}{1}".format(self.__class__.__name__, self.id) # Widget Setting self.statusbar_stack = list() self.context_id_dict = dict() self.debug = False
[docs] def new(self): """ Creates a new :func:`GLXCurses.StatusBar <GLXCurses.StatusBar.StatusBar>` ready for messages. :return: the new StatusBar :rtype: GLXCurses.StatusBar """ self.__init__() return self
[docs] def get_context_id(self, context_description="Default"): """ Returns a new context identifier, given a description of the actual context. .. note: the description is not shown in the UI. :param context_description: textual description of what context the new message is being used in. \ Default if none :type context_description: str :return: an context_id generate by Utils.new_id() :rtype: str :raises TypeError: When context_description is not a str """ # Try to exit as soon of possible if type(context_description) != str: raise TypeError('"context_description" must be a str type') # If we are here everything look ok if context_description not in self._get_context_id_list(): self._get_context_id_list()[context_description] = GLXCurses.new_id() if self.debug: logging.debug( "StatusBar CONTEXT CREATION: context_id={0} context_description={1}".format( self._get_context_id_list()[context_description], str(context_description), ) ) return self._get_context_id_list()[context_description]
[docs] def push(self, context_id, text): """ Push a new message onto the StatusBar's stack. :param context_id: a context identifier, as returned by StatusBar.get_context_id() :type context_id: str :param text: the message to add to the StatusBar :type text: str :return: a message identifier that can be used with StatusBar.remove(). :rtype: str """ # Try to exit as soon of possible if not GLXCurses.is_valid_id(context_id): raise TypeError( '"context_id" must be a unicode type as returned by StatusBar.get_context_id()' ) if type(text) != str: raise TypeError('"text" must be a str or unicode type') # If we are here everything look ok message_id = GLXCurses.new_id() message_info = dict() message_info["context_id"] = context_id message_info["message_id"] = message_id message_info["text"] = text self._get_statusbar_stack().append(message_info) self._emit_text_pushed(context_id, text) return message_id
[docs] def pop(self, context_id): """ Removes the first message in the StatusBar’s stack with the given context id. Note that this may not change the displayed message, if the message at the top of the stack has a different context id. :param context_id: a context identifier, as returned by StatusBar.get_context_id() :type context_id: str """ # Try to exit as soon of possible if not GLXCurses.is_valid_id(context_id): raise TypeError( '"context_id" must be a unicode type as returned by StatusBar.get_context_id()' ) # If we are here everything look ok count = 0 last_found = None last_element = None for element in self._get_statusbar_stack(): if context_id == element["context_id"]: last_found = count last_element = element count += 1 if last_found is not None: self._get_statusbar_stack().pop(last_found) self._emit_text_popped(last_element["context_id"], last_element["text"])
[docs] def remove(self, context_id, message_id): """ Forces the removal of a message from a StatusBar’s stack. The exact **context_id** and **message_id** must be specified. :param context_id: a context identifier, as returned by StatusBar.get_context_id() :type context_id: str :param message_id: a message identifier, as returned by StatusBar.push() :type message_id: str """ # Try to exit as soon of possible if not GLXCurses.is_valid_id(context_id): raise TypeError( '"context_id" arguments must be unicode type as returned by StatusBar.get_context_id()' ) if not GLXCurses.is_valid_id(message_id): raise TypeError( '"message_id" arguments must be unicode type as returned by StatusBar.push()' ) # If we are here everything look ok count = 0 last_found = None last_element = None for element in self._get_statusbar_stack(): if ( context_id == element["context_id"] and message_id == element["message_id"] ): last_found = count last_element = element count += 1 if last_found is not None: if self.debug: logging.debug( "StatusBar REMOVE: index={0} context_id={1} message_id={2} text={3}".format( str(last_found), str(last_element["context_id"]), str(last_element["message_id"]), str(last_element["text"]), ) ) self._get_statusbar_stack().pop(last_found)
[docs] def remove_all(self, context_id): """ Forces the removal of all messages from a StatusBar's stack with the exact context_id . :param context_id: a context identifier, as returned by StatusBar.get_context_id() :type context_id: str """ # Try to exit as soon of possible if not GLXCurses.is_valid_id(context_id): raise TypeError( '"context_id" arguments must be unicode type as returned by MessageBar.get_context_id()' ) # If we are here everything look ok for element in self._get_statusbar_stack(): if context_id == element["context_id"]: self.remove(element["context_id"], element["message_id"])
[docs] def draw(self): """ Place the status bar from the end of the stdscr by look if it have a toolbar and a statusbar before """ # Background for x_inc in range(self.x, self.width): try: self.stdscr.addstr( self.y, x_inc, str.encode(" ", encoding=code, errors="strict"), self.style.curses_color_pair_number(0, 0), ) except curses.error: # pragma: no cover pass # Text if len(self._get_statusbar_stack()): for x_inc in range(0, len(str(self._get_statusbar_stack()[-1]["text"]))): try: self.stdscr.addstr( self.y, self.x + x_inc, str.encode( self._get_statusbar_stack()[-1]["text"][x_inc], encoding=code, errors="strict", ), self.style.curses_color_pair_number(0, 0), ) except curses.error: # pragma: no cover pass
# signals def _emit_text_popped(self, context_id, text, user_data=None): """ Is emitted whenever a new message is popped off a StatusBar's stack. :param context_id: the context id of the relevant message/StatusBar :type context_id: str :param text: the message that was just popped :type text: str :param user_data: user __area_data set when the signal handler was connected. :type user_data: list or None """ if user_data is None: user_data = list() # Create a Dict with everything instance = { "class": self.__class__.__name__, "type": "text-popped", "id": self.id, "context_id": context_id, "text": text, "user_data": user_data, } # EVENT EMIT self.emit("SIGNALS", instance) def _emit_text_pushed(self, context_id, text, user_data=None): """ Is emitted whenever a new message is popped off a StatusBar's stack. :param context_id: the context id of the relevant message/StatusBar :type context_id: str :param text: the message that was just popped :type text: str :param user_data: user __area_data set when the signal handler was connected. :type user_data: list """ if user_data is None: user_data = list() # Create a Dict with everything instance = { "class": self.__class__.__name__, "type": "text-pushed", "id": self.id, "context_id": context_id, "text": text, "user_data": user_data, } # EVENT EMIT self.emit("SIGNALS", instance) self.emit("text-pushed", {"class": self.__class__.__name__, "id": self.id, "statusbar": self, "context_id": context_id, "text": text, "user_data": user_data, }) # Internal Method's def _get_context_id_list(self): """ Return context_id_dict attribute :return: context_id_dict attribute :rtype: dict """ return self.context_id_dict def _get_statusbar_stack(self): """ Return statusbar_stack attribute :return: statusbar_stack attribute :rtype: list """ return self.statusbar_stack
[docs] def update_preferred_sizes(self): self.preferred_height = 1 self.preferred_width = self.width