# HG changeset patch # User Goffi # Date 1393892655 -3600 # Node ID dc0db078ed19561403b734aad72164507113c474 # Parent 0199a17f4d92ce086cf4d057a06bce92442cdfed removed deprecated and really old Sortilege frontend, today Primitivus is the console frontend diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/__init__.py diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/boxsizer.py --- a/frontends/sortilege_old/boxsizer.py Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# sortilege: a SAT frontend -# Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -from window import Window -import os,pdb - -class BoxSizer(object): - """This class manage the position of the window like boxes.""" - - - - def __init__(self, parent): - self.__parent=parent - self.boxes=[] - - - - def appendRow(self, win): - self.boxes.append([win]) - - def appendColum(self, index, win): - if len(self.boxes)<=index: - #TODO: throw an error here - return - self.boxes[index].append(win) - - def update(self): - """Resize boxes""" - oriY=0 - visible_row=[] - for row in self.boxes: - current_row=[] - oriX=0 - for win in row: - x=win.getOriX() - y=win.getOriY() - w=win.getOriWidth() - h=win.getOriHeight() - if win.isHidden(): - if len(current_row)>1 and win is row[-1]: - #if the last win is hidden, we expand previous visible one - current_row[-1][2] = current_row[-1][2] + (win.getX() - oriX)+win.getWidth() - else: - current_row.append([win, h+y-oriY, w+x-oriX, oriY, oriX]) - oriX=oriX+w - - if oriX!=0: - oriY=oriY+h - visible_row.append(current_row) - elif visible_row: - #if all the row is empty, we take the space - for box in visible_row[-1]: - box[1]=box[1]+h - oriY=oriY+h #this only happen if it's not the first visible row - - for row in visible_row: - for win in row: - win[0].resize(win[1], win[2], win[3], win[4]) diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/chat.py --- a/frontends/sortilege_old/chat.py Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# sortilege: a SAT frontend -# Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - - -import os.path -import pdb -from logging import debug, info, error -from window import Window -import os -from time import time, localtime, strftime -import curses -import curses.ascii as ascii -from tools.jid import JID -from quick_frontend.quick_chat import QuickChat - - -def C(k): - """return the value of Ctrl+key""" - return ord(ascii.ctrl(k)) - -class Chat(Window, QuickChat): - - def __init__(self, to_id, host): - QuickChat.__init__(self, to_id, host) - self.__parent=host.stdscr - self.to_id=JID(to_id) - self.content=[] - self.__scollIdx=0 - Window.__init__(self, self.__parent, self.__parent.getmaxyx()[0]-2, self.__parent.getmaxyx()[1]-30, 0,30, code=host.code) - - #history - self.historyPrint(50, True, profile=self.host.profile) - - self.hide() - - def resize(self, height, width, y, x): - Window.resize(self, height, width, y, x) - self.update() - - def resizeAdapt(self): - """Adapt window size to self.__parent size. - Must be called when self.__parent is resized.""" - self.resize(self.__parent.getmaxyx()[0]-2, self.__parent.getmaxyx()[1]-30, 0,30) - self.update() - - def __getHeader(self, line): - """Return the header of a line (eg: "[12:34] ").""" - header='' - if self.host.chatParams["timestamp"]: - header = header + '[%s] ' % strftime("%H:%M", localtime(float(line[0]))) - if self.host.chatParams['short_nick']: - header = header + ('> ' if line[1]==self.host.profiles[self.host.profile]['whoami'] else '** ') - else: - header = header + '<%s> ' % line[1] - return header - - def update(self): - if self.isHidden(): - return - Window.update(self) - content=[] #what is really printed - irange=range(len(self.content)) - irange.reverse() #we print the text upward - for idx in irange: - header=self.__getHeader(self.content[idx]) - msg=self.content[idx][2] - part=0 #part of the text - if JID(self.content[idx][1]).bare==self.host.profiles[self.host.profile]['whoami'].bare: - att_header=curses.color_pair(1) - else: - att_header=curses.color_pair(2) - - while (msg): - if part==0: - hd=header - att=att_header - max=self.rWidth-len(header) - else: - hd="" - att=0 - max=self.rWidth - - LF = msg.find('\n') #we look for Line Feed - if LF != -1 and LF < max: - max = LF - next = max + 1 #we skip the LF - else: - next = max - - content.insert(part,[att,hd, msg[:max]]) - msg=msg[next:] #we erase treated part - part=part+1 - - if len(content)>=self.rHeight+self.__scollIdx: - #all the screen is filled, we can continue - break - - if self.__scollIdx>0 and len(content) 0: - self.__scollIdx = self.__scollIdx - 1 - self.update() - - def printMessage(self, jid, msg, profile, timestamp=""): - if timestamp=="": - current_time=time() - timestamp=str(current_time) - if self.last_history and current_time - float(self.last_history) < 5: #FIXME: Q&D fix to avoid double print on new chat window - return - self.content.append([timestamp,jid.bare,msg]) - self.update() - - def handleKey(self, k): - if k == C('p'): - self.scrollIdxUp() - elif k == C('n'): - self.scrollIdxDown() - diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/editbox.py --- a/frontends/sortilege_old/editbox.py Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# sortilege: a SAT frontend -# Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -import curses -from curses import ascii -from window import Window - -def C(k): - """return the value of Ctrl+key""" - return ord(ascii.ctrl(k)) - -def A(k): - """return the value of Alt+key""" - return ord(ascii.alt(k)) - -class EditBox(Window): - """This class manage the edition of text""" - - def __init__(self, parent, header, code="utf-8"): - self.__header=header - self.__text = unicode() - self.__curs_pos=0 - self.__buffer=str() - self.__replace_mode=False - self.__parent=parent - self.__code=code - - Window.__init__(self, self.__parent, 1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-1,0, code=code) - self.update() - - def registerEnterCB(self, CB): - self.__enterCB=CB - - def resizeAdapt(self): - """Adapt window size to self.__parent size. - Must be called when self.__parent is resized.""" - self.resize(1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-1,0) - self.update() - - def __getTextToPrint(self): - """return the text printed on the edit line""" - width = self.rWidth - len(self.__header) -1 - if self.__curs_pos0: - self.__curs_pos = self.__curs_pos - 1 - - def __inc_cur(self): - """move cursor on the right""" - if self.__curs_pos=self.rWidth: - pos=self.rWidth-1 - self.move(0, pos) - - def clear_text(self): - """Clear the text of the edit box""" - self.__text="" - self.__curs_pos=0 - - def replace_cur(self): - """must be called earch time the cursor is moved""" - self.move_cur(self.__curs_pos) - self.noutrefresh() - - def activate(self, state=True): - cursor_mode = 1 if state else 0 - curses.curs_set(cursor_mode) - Window.activate(self,state) - - def handleKey(self, k): - if ascii.isgraph(k) or ascii.isblank(k): - pacman = 0 if not self.__replace_mode else 1 - self.__text = self.__text[:self.__curs_pos] + chr(k) + self.__text[self.__curs_pos + pacman:] - self.__curs_pos = self.__curs_pos + 1 - - elif k==ascii.NL: - try: - self.__enterCB(self.__text) - except NameError: - pass # TODO: thrown an error here - self.clear_text() - - elif k==curses.KEY_BACKSPACE: - self.__text = self.__text[:self.__curs_pos-1]+self.__text[self.__curs_pos:] - self.__dec_cur() - - elif k==curses.KEY_DC: - self.__text = self.__text[:self.__curs_pos]+self.__text[self.__curs_pos+1:] - - elif k==curses.KEY_IC: - self.__replace_mode = not self.__replace_mode - - elif k==curses.KEY_LEFT: - self.__dec_cur() - - elif k==curses.KEY_RIGHT: - self.__inc_cur() - - elif k==curses.KEY_HOME or k==C('a'): - self.__curs_pos=0 - - elif k==curses.KEY_END or k==C('e'): - self.__curs_pos=len(self.__text) - - elif k==C('k'): - self.__text = self.__text[:self.__curs_pos] - - elif k==C('w'): - before = self.__text[:self.__curs_pos] - pos = before.rstrip().rfind(" ")+1 - self.__text = before[:pos] + self.__text[self.__curs_pos:] - self.__curs_pos = pos - - elif k>255: - self.__buffer="" - - else: ## FIXME: dangerous code, must be checked ! (specialy buffer overflow) ## - #We now manage unicode - self.__buffer = self.__buffer+chr(k) - decoded=unicode() - if len(self.__buffer)>4: - self.__buffer="" - return - try: - decoded = self.__buffer.decode(self.__code) - except UnicodeDecodeError, e: - if e.reason!="unexpected end of data": - self.__buffer="" - return - if len(self.__buffer)==1: ## FIXME: awful ! only for test ! - self.__buffer="" - return - self.__text = self.__text + decoded - self.__curs_pos = self.__curs_pos + 1 - self.__buffer="" - - self.update() - diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/sortilege --- a/frontends/sortilege_old/sortilege Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,400 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -sortilege: a SAT frontend -Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -""" - - -from quick_frontend.quick_app import QuickApp -from quick_frontend.quick_chat_list import QuickChatList -from quick_frontend.quick_contact_list import QuickContactList -from quick_frontend.quick_contact_management import QuickContactManagement -import curses -import pdb -from window import Window -from editbox import EditBox -from statusbar import StatusBar -from chat import Chat -from tools.jid import JID -import logging -from logging import debug, info, error -import locale -import sys, os -import gobject -import time -from curses import ascii -import locale -from signal import signal, SIGWINCH -import fcntl -import struct -import termios -from boxsizer import BoxSizer - - -### logging configuration FIXME: put this elsewhere ### -logging.basicConfig(level=logging.CRITICAL, #TODO: configure it top put messages in a log file - format='%(message)s') -### - -const_APP_NAME = "Sortilège" -const_CONTACT_WIDTH = 30 - -def ttysize(): - """This function return term size. - Comes from Donn Cave from python list mailing list""" - buf = 'abcdefgh' - buf = fcntl.ioctl(0, termios.TIOCGWINSZ, buf) - row, col, rpx, cpx = struct.unpack('hhhh', buf) - return row, col - -def C(k): - """return the value of Ctrl+key""" - return ord(ascii.ctrl(k)) - -class ChatList(QuickChatList): - """This class manage the list of chat windows""" - - def __init__(self, host): - QuickChatList.__init__(self, host) - self.sizer=host.sizer - - def createChat(self, name): - chat = Chat(name, self.host) - self.sizer.appendColum(0,chat) - self.sizer.update() - return chat - -class ContactList(Window, QuickContactList): - - def __init__(self, host, CM): - QuickContactList.__init__(self, CM) - self.host = host - self.jid_list = [] - self.__index=0 #indicate which contact is selected (ie: where we are) - Window.__init__(self, stdscr, stdscr.getmaxyx()[0]-2,const_CONTACT_WIDTH,0,0, True, _("Contact List"), code=code) - - def resize(self, height, width, y, x): - Window.resize(self, height, width, y, x) - self.update() - - def resizeAdapt(self): - """Adapt window size to stdscr size. - Must be called when stdscr is resized.""" - self.resize(stdscr.getmaxyx()[0]-2,const_CONTACT_WIDTH,0,0) - self.update() - - def registerEnterCB(self, CB): - self.__enterCB=CB - - def clear_contacts(self): - """clear all the contact list""" - del self.jid_list[:] - self.__index = 0 - self.update() #FIXME: window is not updated correctly (contacts are still here until C-L) - - def replace(self, jid, groups=None): - """add a contact to the list""" - name = self.CM.getAttr(jid,'name') - self.jid_list.append(jid.bare) - self.update() - - def indexUp(self): - """increment select contact index""" - if self.__index < len(self.jid_list)-1: #we dont want to select a missing contact - self.__index = self.__index + 1 - self.update() - - def indexDown(self): - """decrement select contact index""" - if self.__index > 0: - self.__index = self.__index - 1 - self.update() - - def disconnect(self, jid): - """for now, we just remove the contact""" - self.remove(jid) - - def remove(self, jid): - """remove a contact from the list""" - self.jid_list.remove(jid.bare) - if self.__index >= len(self.jid_list) and self.__index > 0: #if select index is out of border, we put it on the last contact - self.__index = len(self.jid_list)-1 - self.update() - - def update(self): - """redraw all the window""" - if self.isHidden(): - return - Window.update(self) - self.jid_list.sort() - begin=0 if self.__index ", self.code) - self.editBar.activate(False) - self.statusBar = StatusBar(stdscr, self.code) - self.statusBar.hide(True) - self.addWin(self.contactList) - self.addWin(self.editBar) - self.addWin(self.statusBar) - self.sizer=BoxSizer(stdscr) - self.sizer.appendRow(self.contactList) - self.sizer.appendRow(self.statusBar) - self.sizer.appendRow(self.editBar) - self.currentChat=None - - self.contactList.registerEnterCB(self.onContactChoosed) - self.editBar.registerEnterCB(self.onTextEntered) - - self.chat_wins=ChatList(self) - - QuickApp.__init__(self) #XXX: yes it's an unusual place for the constructor of a parent class, but the init order is important - self.plug_profile() - - signal (SIGWINCH, self.onResize) #we manage SIGWINCH ourselves, because the loop is not called otherwise - - #last but not least, we adapt windows' sizes - self.sizer.update() - self.editBar.replace_cur() - curses.doupdate() - - self.loop.run() - - def addWin(self, win): - self.listWins.append(win) - - def color(self, activate=True): - if activate: - debug (_("Activating colors")) - curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK) - curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) - else: - debug (_("Deactivating colors")) - curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) - curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK) - - - def showChat(self, chat): - debug (_("show chat")) - if self.currentChat: - debug (_("hiding %s"), self.currentChat) - self.chat_wins[self.currentChat].hide() - self.currentChat=chat - debug (_("showing %s"), self.currentChat) - self.chat_wins[self.currentChat].show() - self.chat_wins[self.currentChat].update() - - - ### EVENTS ### - - def onContactChoosed(self, jid_txt): - """Called when a contact is selected in contact list.""" - jid=JID(jid_txt) - debug (_("contact choosed: %s"), jid) - self.showChat(jid.bare) - self.statusBar.remove_item(jid.bare) - if len(self.statusBar)==0: - self.statusBar.hide() - self.sizer.update() - - - def onTextEntered(self, text): - jid=JID(self.profiles[self.profile]['whoami']) - self.bridge.sendMessage(self.currentChat, text, profile_key=self.profile) - - def showDialog(self, message, title, type="info"): - if type==question: - raise NotImplementedError - pass - - - def presenceUpdate(self, jabber_id, show, priority, statuses, profile): - QuickApp.presenceUpdate(self, jabber_id, show, priority, statuses, profile) - self.editBar.replace_cur() - curses.doupdate() - - def askConfirmation(self, type, id, data): - #FIXME - info (_("FIXME: askConfirmation not implemented")) - - def actionResult(self, type, id, data): - #FIXME - info (_("FIXME: actionResult not implemented")) - - def newMessage(self, from_jid, msg, type, to_jid, profile): - QuickApp.newMessage(self, from_jid, msg, type, to_jid, profile) - sender=JID(from_jid) - addr=JID(to_jid) - win = addr if sender.bare == self.whoami.bare else sender #FIXME: duplicate code with QuickApp - if (self.currentChat==None): - self.currentChat=win.bare - self.showChat(win.bare) - - # we show the window in the status bar - if not self.currentChat == win.bare: - self.statusBar.add_item(win.bare) - self.statusBar.show() - self.sizer.update() - self.statusBar.update() - - self.editBar.replace_cur() - curses.doupdate() - - def onResize(self, sig, stack): - """Called on SIGWINCH. - resize the screen and launch the loop""" - height, width = ttysize() - curses.resizeterm(height, width) - gobject.idle_add(self.callOnceLoop) - - def callOnceLoop(self): - """Call the loop and return false (for not being called again by gobject mainloop). - Usefull for calling loop when there is no input in stdin""" - self.loopCB() - return False - - def __key_handling(self, k): - """Handle key and transmit to active window.""" - - ### General keys, handled _everytime_ ### - if k == C('x'): - if os.getenv('TERM')=='screen': - os.system('screen -X remove') - else: - self.loop.quit() - - ## windows navigation - elif k == C('l') and not self.contactList.isHidden(): - """We go to the contact list""" - self.contactList.activate(not self.contactList.isActive()) - if self.currentChat: - self.editBar.activate(not self.contactList.isActive()) - - elif k == curses.KEY_F2: - self.contactList.hide(not self.contactList.isHidden()) - if self.contactList.isHidden(): - self.contactList.activate(False) #TODO: auto deactivation when hiding ? - if self.currentChat: - self.editBar.activate(True) - self.sizer.update() - - ## Chat Params ## - elif k == C('c'): - self.chatParams["color"] = not self.chatParams["color"] - self.color(self.chatParams["color"]) - elif k == C('t'): - self.chatParams["timestamp"] = not self.chatParams["timestamp"] - self.chat_wins[self.currentChat].update() - elif k == C('s'): - self.chatParams["short_nick"] = not self.chatParams["short_nick"] - self.chat_wins[self.currentChat].update() - - ## misc ## - elif k == curses.KEY_RESIZE: - stdscr.erase() - height, width = stdscr.getmaxyx() - if height<5 and width<35: - stdscr.addstr(_("Pleeeeasse, I can't even breathe !")) - else: - for win in self.listWins: - win.resizeAdapt() - for win in self.chat_wins.keys(): - self.chat_wins[win].resizeAdapt() - self.sizer.update() # FIXME: everything need to be managed by the sizer - - ## we now throw the key to win handlers ## - else: - for win in self.listWins: - if win.isActive(): - win.handleKey(k) - if self.currentChat: - self.chat_wins[self.currentChat].handleKey(k) - - def loopCB(self, source="", cb_condition=""): - """This callback is called by the main loop""" - #pressed = self.contactList.window.getch() - pressed = stdscr.getch() - if pressed != curses.ERR: - self.__key_handling(pressed) - self.editBar.replace_cur() - curses.doupdate() - - - return True - - -sat = SortilegeApp() -sat.start() diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/statusbar.py --- a/frontends/sortilege_old/statusbar.py Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# sortilege: a SAT frontend -# Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -import curses -from window import Window -import os - -class StatusBar(Window): - """This class manage the edition of text""" - - def __init__(self, parent, code="utf-8"): - self.__parent=parent - self.__code=code - self.__items=set() - - Window.__init__(self, self.__parent, 1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-2,0, code=code) - - def __len__(self): - return len(self.__items) - - def resizeAdapt(self): - """Adapt window size to self.__parent size. - Must be called when self.__parent is resized.""" - self.resize(1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-2,0) - self.update() - - def update(self): - if self.isHidden(): - return - Window.update(self) - x=0 - for item in self.__items: - pitem="[%s] " % item - self.addYXStr(0, x, pitem, curses.A_REVERSE) - x = x + len(pitem) - if x>=self.rWidth: - break - self.addYXStr(0, x, (self.rWidth-x)*" ", curses.A_REVERSE) - self.noutrefresh() - - def clear_text(self): - """Clear the text of the edit box""" - del(self.__items[:]) - - def add_item(self, item): - self.__items.add(item) - self.update() - - def remove_item(self, item): - if item in self.__items: - self.__items.remove(item) - self.update() diff -r 0199a17f4d92 -r dc0db078ed19 frontends/sortilege_old/window.py --- a/frontends/sortilege_old/window.py Tue Mar 04 00:29:10 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# sortilege: a SAT frontend -# Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -import curses -import os -import pdb - - -class Window(object): - def __init__(self, parent, height, width, y, x, border=False, title="", code="utf-8"): - self.__border=border - self.__title=title - self.__active=False - self.__parent=parent - self.__code=code - self.__hide=False - - self.resize(height, width, y, x) - self.oriCoords=self.__coords #FIXME: tres moche, a faire en mieux - - def hide(self, hide=True): - self.__hide=hide - - def show(self): - self.__hide=False - - def isHidden(self): - return self.__hide - - def getY(self): - return self.__coords[2] - - def getX(self): - return self.__coords[3] - - def getHeight(self): - return self.__coords[0] - - def getWidth(self): - return self.__coords[1] - - - #FIXME: tres moche, a faire en plus joli - def getOriY(self): - return self.oriCoords[2] - - def getOriX(self): - return self.oriCoords[3] - - def getOriHeight(self): - return self.oriCoords[0] - - def getOriWidth(self): - return self.oriCoords[1] - - def defInsideCoord(self): - """define the inside coordinates (win coordinates minus decorations)""" - height,width,y,x=self.__coords - self.oriX = x if not self.__border else x+1 - self.oriY = y if not self.__border else y+1 - self.endX = x+width if not self.__border else x+width-2 - self.endY = y+height if not self.__border else y+height-2 - self.rWidth = width if not self.__border else width-2 - self.rHeight = height if not self.__border else height-2 - - def resize(self, height, width, y, x): - self.__coords=[height, width, y, x] - - # we check that coordinates are under limits - self.__coordAdjust(self.__coords) - height,width,y,x=self.__coords - - self.window = self.__parent.subwin(height, width, y, x) - self.defInsideCoord() - - def __coordAdjust(self, coords): - """Check that coordinates are under limits, adjust them else otherwise""" - height,width,y,x=coords - parentY, parentX = self.__parent.getbegyx() - parentHeight, parentWidth = self.__parent.getmaxyx() - - if y < parentY: - y = parentY - if x < parentX: - x = parentX - if height > parentHeight - y: - height = parentHeight - y - if width > parentWidth - x: - width = parentWidth - x - coords[0], coords[1], coords[2], coords[3] = [height, width, y, x] - - - def activate(self,state=True): - """Declare this window as current active one""" - self.__active=state - self.update() - - def isActive(self): - return self.__active - - def addYXStr(self, y, x, text, attr = 0, limit=0): - if self.__border: - x=x+1 - y=y+1 - n = self.rWidth-x if not limit else limit - encoded = text.encode(self.__code) - adjust = len(encoded) - len(text) # hack because addnstr doesn't manage unicode - try: - self.window.addnstr(y, x, encoded, n + adjust, attr) - except: - #We have to catch error to write on last line last col FIXME: is there a better way ? - pass - - def move(self, y, x): - self.window.move(y,x) - - def noutrefresh(self): - self.window.noutrefresh() - - def update(self): - """redraw all the window""" - if self.__hide: - return - self.clear() - - def border(self): - """redraw the border and title""" - y,x = self.window.getbegyx() - width = self.window.getmaxyx()[1] - if self.__border: - self.window.border() - if self.__title: - if len(self.__title)>width: - self.__title="" - else: - self.window.addstr(y,x+(width-len(self.__title))/2, self.__title) - - def clear(self): - self.window.clear() - self.border()