removed deprecated and really old Sortilege frontend, today Primitivus is the console frontend

This commit is contained in:
Goffi 2014-03-04 01:24:15 +01:00
commit 97b8554124
7 changed files with 0 additions and 1026 deletions

View file

@ -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 <http://www.gnu.org/licenses/>.
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])

View file

@ -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 <http://www.gnu.org/licenses/>.
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] <toto> ")."""
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)<self.rHeight+self.__scollIdx:
self.__scollIdx=abs(len(content)-self.rHeight) #all the log fit on the screen, we must stop here
idx=0
for line in content[-self.rHeight-self.__scollIdx : -self.__scollIdx or None]:
self.addYXStr(idx, 0, line[1], line[0])
self.addYXStr(idx, len(line[1]), line[2])
idx=idx+1
self.noutrefresh()
def scrollIdxUp(self):
"""increment scroll index"""
self.__scollIdx = self.__scollIdx + 1
self.update()
def scrollIdxDown(self):
"""decrement scroll index"""
if self.__scollIdx > 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()

View file

@ -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 <http://www.gnu.org/licenses/>.
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_pos<width:
begin = 0
end = width
else:
begin = self.__curs_pos-width
end = self.__curs_pos
return self.__header+self.__text[begin:end]
def update(self):
Window.update(self)
text = self.__getTextToPrint()
self.addYXStr(0, 0, text, limit=self.rWidth)
self.noutrefresh()
def __dec_cur(self):
"""move cursor on the left"""
if self.__curs_pos>0:
self.__curs_pos = self.__curs_pos - 1
def __inc_cur(self):
"""move cursor on the right"""
if self.__curs_pos<len(self.__text):
self.__curs_pos = self.__curs_pos + 1
def move_cur(self, x):
pos = x+len(self.__header)
if 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()

View file

@ -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 <http://www.gnu.org/licenses/>.
"""
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.rHeight else self.__index-self.rHeight+1
idx=0
for item in self.jid_list[begin:self.rHeight+begin]:
attr = curses.A_REVERSE if ( self.isActive() and (idx+begin) == self.__index ) else 0
centered = item.center(self.rWidth) ## it's nicer in the center :)
self.addYXStr(idx, 0, centered, attr)
idx = idx + 1
self.noutrefresh()
def handleKey(self, k):
if k == curses.KEY_UP:
self.indexDown()
elif k == curses.KEY_DOWN:
self.indexUp()
elif k == ascii.NL:
if not self.jid_list:
return
try:
self.__enterCB(self.jid_list[self.__index])
except NameError:
pass # TODO: thrown an error here
class SortilegeApp(QuickApp):
def __init__(self):
#debug(const_APP_NAME+" init...")
## unicode support ##
locale.setlocale(locale.LC_ALL, '')
global code
code = locale.getpreferredencoding()
self.code=code
## main loop setup ##
self.loop=gobject.MainLoop()
gobject.io_add_watch(0, gobject.IO_IN, self.loopCB)
## misc init stuff ##
self.CM = QuickContactManagement()
self.listWins=[]
self.chatParams={'timestamp':True,
'color':True,
'short_nick':False}
def start(self):
curses.wrapper(self.start_curses)
def start_curses(self, win):
global stdscr
stdscr = win
self.stdscr = stdscr
curses.raw() #we handle everything ourself
curses.curs_set(False)
stdscr.nodelay(True)
## colours ##
self.color(True)
## windows ##
self.contactList = ContactList(self, self.CM)
self.editBar = EditBox(stdscr, "> ", 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()

View file

@ -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 <http://www.gnu.org/licenses/>.
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()

View file

@ -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 <http://www.gnu.org/licenses/>.
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()