tooltip positioning... base tooltip class...
custom tooltip in notif. area
This commit is contained in:
parent
f51c2b0f95
commit
f4bacf0989
186
src/dialogs.py
186
src/dialogs.py
|
@ -516,32 +516,33 @@ class InformationDialog(HigDialog):
|
|||
self, None, pritext, sectext, gtk.STOCK_DIALOG_INFO,
|
||||
[ [ gtk.STOCK_OK, gtk.RESPONSE_OK ] ]
|
||||
)
|
||||
|
||||
class RosterTooltip:
|
||||
def __init__(self, plugin):
|
||||
self.plugin = plugin
|
||||
|
||||
self.image = gtk.Image()
|
||||
self.image.set_alignment(0.5, 0.025)
|
||||
self.account = None
|
||||
self.table = None
|
||||
|
||||
self.current_row = 1
|
||||
class BaseTooltip:
|
||||
''' Base Tooltip . Usage:
|
||||
tooltip = BaseTooltip()
|
||||
....
|
||||
tooltip.show_tooltip('', window_postions, widget_postions)
|
||||
....
|
||||
if tooltip.timeout != 0:
|
||||
tooltip.hide_tooltip()
|
||||
'''
|
||||
def __init__(self):
|
||||
self.timeout = 0
|
||||
self.prefered_position = [0, 0]
|
||||
self.path = None
|
||||
self.win = None
|
||||
self.id = None
|
||||
|
||||
def populate(self, data):
|
||||
''' this method must be overridenby all extenders '''
|
||||
self.create_window()
|
||||
self.win.add(gtk.Label(data))
|
||||
|
||||
def create_window(self):
|
||||
''' create a popup window each time tooltip is requested '''
|
||||
self.win = gtk.Window(gtk.WINDOW_POPUP)
|
||||
self.win.set_border_width(3)
|
||||
self.win.set_resizable(False)
|
||||
self.win.set_name('gtk-tooltips')
|
||||
self.hbox = gtk.HBox()
|
||||
self.hbox.set_border_width(6)
|
||||
self.hbox.set_homogeneous(False)
|
||||
self.win.add(self.hbox)
|
||||
self.hbox.pack_start(self.image, False, False)
|
||||
|
||||
|
||||
self.win.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||
self.win.connect_after('expose_event', self.expose)
|
||||
|
@ -561,8 +562,10 @@ class RosterTooltip:
|
|||
self.prefered_position[0] = screen.get_width() - requisition.width
|
||||
else:
|
||||
self.prefered_position[0] -= half_width
|
||||
screen.get_height()
|
||||
if self.prefered_position[1] + requisition.height > screen.get_height():
|
||||
self.prefered_position[1] -= requisition.height + 25
|
||||
# flip tooltip up
|
||||
self.prefered_position[1] -= requisition.height + self.widget_height + 8
|
||||
if self.prefered_position[1] < 0:
|
||||
self.prefered_position[1] = 0
|
||||
self.win.move(self.prefered_position[0], self.prefered_position[1])
|
||||
|
@ -580,11 +583,12 @@ class RosterTooltip:
|
|||
self.win, 'tooltip', size[0] - 1, 0, 1, -1)
|
||||
return True
|
||||
|
||||
def show_tooltip(self, contact, pointer_position, win_size):
|
||||
self.populate(contact)
|
||||
new_x = win_size[0] + pointer_position[0]
|
||||
new_y = win_size[1] + pointer_position[1] + 35
|
||||
def show_tooltip(self, data, widget_pos, win_size):
|
||||
self.populate(data)
|
||||
new_x = win_size[0] + widget_pos[0]
|
||||
new_y = win_size[1] + widget_pos[1] + 4
|
||||
self.prefered_position = [new_x, new_y]
|
||||
self.widget_height = widget_pos[1]
|
||||
self.win.ensure_style()
|
||||
self.win.show_all()
|
||||
|
||||
|
@ -592,11 +596,37 @@ class RosterTooltip:
|
|||
if(self.timeout > 0):
|
||||
gobject.source_remove(self.timeout)
|
||||
self.timeout = 0
|
||||
self.win.destroy()
|
||||
self.path = None
|
||||
if self.win:
|
||||
self.win.destroy()
|
||||
self.win = None
|
||||
self.id = None
|
||||
|
||||
|
||||
def add_status(self, file_path, resource, priority, show, status):
|
||||
class StatusTable:
|
||||
''' Contains methods for creating status table. This
|
||||
is used in Roster and NotificationArea tooltips '''
|
||||
def __init__(self):
|
||||
self.current_row = 1
|
||||
self.table = None
|
||||
self.text_lable = None
|
||||
|
||||
def create_table(self):
|
||||
self.table = gtk.Table(3, 1)
|
||||
self.table.set_property('column-spacing', 6)
|
||||
self.text_lable = gtk.Label()
|
||||
self.text_lable.set_line_wrap(True)
|
||||
self.text_lable.set_alignment(0, 0)
|
||||
self.text_lable.set_selectable(False)
|
||||
self.table.attach(self.text_lable, 1, 4, 1, 2)
|
||||
|
||||
def get_status_info(self, resource, priority, show, status):
|
||||
str_status = resource + ' ('+str(priority)+')'
|
||||
if status:
|
||||
status = status.strip()
|
||||
if status != '':
|
||||
str_status += ' - ' + status
|
||||
return gtkgui_helpers.escape_for_pango_markup(str_status)
|
||||
|
||||
def add_status_row(self, file_path, show, str_status):
|
||||
''' appends a new row with status icon to the table '''
|
||||
self.current_row += 1
|
||||
state_file = show.replace(' ', '_')
|
||||
|
@ -605,7 +635,7 @@ class RosterTooltip:
|
|||
files.append(os.path.join(file_path, state_file + '.gif'))
|
||||
image = gtk.Image()
|
||||
image.set_from_pixbuf(None)
|
||||
spacer = gtk.Label(' ')
|
||||
spacer = gtk.Label(' ')
|
||||
for file in files:
|
||||
if os.path.exists(file):
|
||||
image.set_from_file(file)
|
||||
|
@ -616,29 +646,91 @@ class RosterTooltip:
|
|||
self.table.attach(image,2,3,self.current_row,
|
||||
self.current_row + 1, 0, 0, 3, 0)
|
||||
image.set_alignment(0.01, 1)
|
||||
str_status = resource + ' ('+str(priority)+')'
|
||||
if status:
|
||||
status = status.strip()
|
||||
if status != '':
|
||||
str_status += ' - ' + status
|
||||
status_label = gtk.Label(str_status)
|
||||
status_label = gtk.Label()
|
||||
status_label.set_markup(str_status)
|
||||
status_label.set_alignment(00, 0)
|
||||
self.table.attach(status_label, 3, 4, self.current_row,
|
||||
self.current_row + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0)
|
||||
|
||||
class NotificationAreaTooltip(BaseTooltip, StatusTable):
|
||||
''' Tooltip that is shown in the notification area '''
|
||||
def __init__(self, plugin):
|
||||
self.plugin = plugin
|
||||
BaseTooltip.__init__(self)
|
||||
StatusTable.__init__(self)
|
||||
|
||||
|
||||
def populate(self, data):
|
||||
self.create_window()
|
||||
self.create_table()
|
||||
self.hbox = gtk.HBox()
|
||||
self.table.set_property('column-spacing', 1)
|
||||
text, single_line, accounts = '', '', []
|
||||
if gajim.contacts:
|
||||
for account in gajim.contacts.keys():
|
||||
status_idx = gajim.connections[account].connected
|
||||
# uncomment the following to hide offline accounts
|
||||
# if status_idx == 0: continue
|
||||
from common.connection import STATUS_LIST
|
||||
status = STATUS_LIST[status_idx]
|
||||
message = gajim.connections[account].status
|
||||
single_line = helpers.get_uf_show(status)
|
||||
if message is None:
|
||||
message = ''
|
||||
else:
|
||||
message = message.strip()
|
||||
if message != '':
|
||||
single_line += ': ' + message
|
||||
else:
|
||||
message = helpers.get_uf_show(status)
|
||||
|
||||
accounts.append({'name':account, 'status_line':single_line,
|
||||
'show':status, 'message':message})
|
||||
unread_messages_no = self.plugin.roster.nb_unread
|
||||
if unread_messages_no > 1:
|
||||
text = _('Gajim - %s unread messages') % unread_messages_no
|
||||
elif unread_messages_no == 1:
|
||||
text = _('Gajim - 1 unread message')
|
||||
elif len(accounts) > 1:
|
||||
text = _('Gajim')
|
||||
self.current_row = 1
|
||||
self.table.resize(2,1)
|
||||
iconset = gajim.config.get('iconset')
|
||||
if not iconset:
|
||||
iconset = 'sun'
|
||||
file_path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16')
|
||||
for acct in accounts:
|
||||
self.add_status_row(file_path, acct['show'], '<span weight="bold">' +
|
||||
gtkgui_helpers.escape_for_pango_markup(acct['name']) + '</span>'
|
||||
+ ' - ' + gtkgui_helpers.escape_for_pango_markup(acct['message']))
|
||||
|
||||
elif len(accounts) == 1:
|
||||
text = _('Gajim - %s') % accounts[0]['status_line']
|
||||
else:
|
||||
text = _('Gajim - %s') % helpers.get_uf_show('offline')
|
||||
self.text_lable.set_markup(text)
|
||||
self.hbox.add(self.table)
|
||||
self.win.add(self.hbox)
|
||||
|
||||
class RosterTooltip(BaseTooltip, StatusTable):
|
||||
''' Tooltip that is shown in the roster treeview '''
|
||||
def __init__(self, plugin):
|
||||
self.account = None
|
||||
self.plugin = plugin
|
||||
|
||||
self.image = gtk.Image()
|
||||
self.image.set_alignment(0.5, 0.025)
|
||||
BaseTooltip.__init__(self)
|
||||
StatusTable.__init__(self)
|
||||
|
||||
def populate(self, contacts):
|
||||
if not contacts or len(contacts) == 0:
|
||||
return
|
||||
self.create_window()
|
||||
self.table = gtk.Table(3, 1)
|
||||
self.table.set_property('column-spacing', 6)
|
||||
self.account = gtk.Label()
|
||||
self.account.set_line_wrap(True)
|
||||
self.account.set_alignment(0, 0)
|
||||
self.account.set_selectable(False)
|
||||
self.table.attach(self.account, 1, 4, 1, 2)
|
||||
self.hbox.pack_start(self.table, True, True)
|
||||
# default resource of the contact
|
||||
self.hbox = gtk.HBox()
|
||||
#~ self.hbox.set_border_width(6)
|
||||
self.hbox.set_homogeneous(False)
|
||||
self.create_table()
|
||||
prim_contact = None # primary contact
|
||||
for contact in contacts:
|
||||
if prim_contact == None or contact.priority > prim_contact.priority:
|
||||
|
@ -665,7 +757,7 @@ class RosterTooltip:
|
|||
if os.path.exists(file):
|
||||
self.image.set_from_file(file)
|
||||
break
|
||||
|
||||
|
||||
info = '<span size="large" weight="bold">' + prim_contact.jid + '</span>'
|
||||
info += '\n<span weight="bold">' + _('Name: ') + '</span>' + \
|
||||
gtkgui_helpers.escape_for_pango_markup(prim_contact.name)
|
||||
|
@ -693,8 +785,9 @@ class RosterTooltip:
|
|||
info += '\n<span weight="bold">' + _('Status: ') + '</span>'
|
||||
for contact in contacts:
|
||||
if contact.resource:
|
||||
self.add_status(file_path, contact.resource, contact.priority,
|
||||
status_line = self.get_status_info(contact.resource, contact.priority,
|
||||
contact.show, contact.status)
|
||||
self.add_status_row(file_path, contact.show, status_line)
|
||||
|
||||
else: # only one resource
|
||||
if contact.resource:
|
||||
|
@ -710,7 +803,10 @@ class RosterTooltip:
|
|||
# escape markup entities. Is it posible to have markup in status?
|
||||
info += ' - ' + gtkgui_helpers.escape_for_pango_markup(status)
|
||||
|
||||
self.account.set_markup(info)
|
||||
self.text_lable.set_markup(info)
|
||||
self.hbox.pack_start(self.image, False, False)
|
||||
self.hbox.pack_start(self.table, True, True)
|
||||
self.win.add(self.hbox)
|
||||
|
||||
class InputDialog:
|
||||
'''Class for Input dialog'''
|
||||
|
|
|
@ -642,11 +642,14 @@ class RosterWindow:
|
|||
def show_tooltip(self, contact):
|
||||
pointer = self.tree.get_pointer()
|
||||
props = self.tree.get_path_at_pos(pointer[0], pointer[1])
|
||||
if props and self.tooltip.path == props[0]:
|
||||
if props and self.tooltip.id == props[0]:
|
||||
# check if the current pointer is at the same path
|
||||
# as it was before setting the timeout
|
||||
self.tooltip.show_tooltip(contact, self.window.get_pointer(),
|
||||
self.window.get_position())
|
||||
rect = self.tree.get_cell_area(props[0],props[1])
|
||||
position = self.tree.window.get_origin()
|
||||
pointer = self.window.get_pointer()
|
||||
self.tooltip.show_tooltip(contact, (pointer[0], rect.height ),
|
||||
(position[0], position[1] + rect.y))
|
||||
else:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
||||
|
@ -654,14 +657,14 @@ class RosterWindow:
|
|||
model = widget.get_model()
|
||||
props = widget.get_path_at_pos(int(event.x), int(event.y))
|
||||
if self.tooltip.timeout > 0:
|
||||
if not props or self.tooltip.path == props[0]:
|
||||
if not props or self.tooltip.id == props[0]:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
||||
def on_roster_treeview_motion_notify_event(self, widget, event):
|
||||
model = widget.get_model()
|
||||
props = widget.get_path_at_pos(int(event.x), int(event.y))
|
||||
if self.tooltip.timeout > 0:
|
||||
if not props or self.tooltip.path != props[0]:
|
||||
if not props or self.tooltip.id != props[0]:
|
||||
self.tooltip.hide_tooltip()
|
||||
if props:
|
||||
[row, col, x, y] = props
|
||||
|
@ -670,8 +673,8 @@ class RosterWindow:
|
|||
account = model[iter][4]
|
||||
jid = model[iter][3]
|
||||
img = model[iter][0]
|
||||
if self.tooltip.timeout == 0 or self.tooltip.path != props[0]:
|
||||
self.tooltip.path = row
|
||||
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
|
||||
self.tooltip.id = row
|
||||
self.tooltip.timeout = gobject.timeout_add(500,
|
||||
self.show_tooltip, gajim.contacts[account][jid])
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
## - Yann Le Boulanger <asterix@lagaule.org>
|
||||
## - Vincent Hanquez <tab@snarc.org>
|
||||
## - Nikos Kouremenos <kourem@gmail.com>
|
||||
## - Dimitur Kirov <dkirov@gmail.com>
|
||||
##
|
||||
## Copyright (C) 2003-2005 Gajim Team
|
||||
##
|
||||
|
@ -19,6 +20,7 @@
|
|||
|
||||
import gtk
|
||||
import gtk.glade
|
||||
import gobject
|
||||
import dialogs
|
||||
import os
|
||||
|
||||
|
@ -50,7 +52,7 @@ class Systray:
|
|||
self.jids = []
|
||||
self.new_message_handler_id = None
|
||||
self.t = None
|
||||
self.tip = gtk.Tooltips()
|
||||
#~ self.tip = gtk.Tooltips()
|
||||
self.img_tray = gtk.Image()
|
||||
self.status = 'offline'
|
||||
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'systray_context_menu', APP)
|
||||
|
@ -132,7 +134,7 @@ class Systray:
|
|||
if global_status is not None and self.status != global_status:
|
||||
self.status = global_status
|
||||
self.set_img()
|
||||
self.tip.set_tip(self.t, text)
|
||||
#~ self.tip.set_tip(self.t, text)
|
||||
|
||||
def start_chat(self, widget, account, jid):
|
||||
if self.plugin.windows[account]['chats'].has_key(jid):
|
||||
|
@ -270,8 +272,8 @@ class Systray:
|
|||
|
||||
def on_clicked(self, widget, event):
|
||||
# hide the tooltip
|
||||
self.tip.disable()
|
||||
self.tip.enable()
|
||||
#~ self.tip.disable()
|
||||
#~ self.tip.enable()
|
||||
win = self.plugin.roster.window
|
||||
if event.button == 1: # Left click
|
||||
if len(self.jids) == 0:
|
||||
|
@ -310,15 +312,44 @@ class Systray:
|
|||
l = ['online', 'chat', 'away', 'xa', 'dnd', 'invisible', 'offline']
|
||||
index = l.index(show)
|
||||
self.plugin.roster.status_combobox.set_active(index)
|
||||
|
||||
|
||||
def show_tooltip(self, widget):
|
||||
position = widget.window.get_origin()
|
||||
if self.tooltip.id == position:
|
||||
size = widget.window.get_size()
|
||||
self.tooltip.show_tooltip('',
|
||||
(widget.window.get_pointer()[0], size[1]), position)
|
||||
|
||||
def on_tray_motion_notify_event(self, widget, event):
|
||||
wireq=widget.size_request()
|
||||
position = widget.window.get_origin()
|
||||
if self.tooltip.timeout > 0:
|
||||
if self.tooltip.id != position:
|
||||
self.tooltip.hide_tooltip()
|
||||
if self.tooltip.timeout == 0 and \
|
||||
self.tooltip.id != position:
|
||||
self.tooltip.id = position
|
||||
self.tooltip.timeout = gobject.timeout_add(500,
|
||||
self.show_tooltip, widget)
|
||||
|
||||
def on_tray_leave_notify_event(self, widget, event):
|
||||
position = widget.window.get_origin()
|
||||
if self.tooltip.timeout > 0 and \
|
||||
self.tooltip.id == position:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
||||
def show_icon(self):
|
||||
if not self.t:
|
||||
self.t = trayicon.TrayIcon('Gajim')
|
||||
eb = gtk.EventBox()
|
||||
# avoid draw seperate bg color in some gtk themes
|
||||
eb.set_visible_window(False)
|
||||
eb.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||
eb.connect('button-press-event', self.on_clicked)
|
||||
self.set_tooltip()
|
||||
eb.connect('motion-notify-event', self.on_tray_motion_notify_event)
|
||||
eb.connect('leave-notify-event', self.on_tray_leave_notify_event)
|
||||
self.tooltip = dialogs.NotificationAreaTooltip(self.plugin)
|
||||
#~ self.set_tooltip()
|
||||
self.img_tray = gtk.Image()
|
||||
eb.add(self.img_tray)
|
||||
self.t.add(eb)
|
||||
|
@ -326,14 +357,10 @@ class Systray:
|
|||
self.t.show_all()
|
||||
|
||||
def set_tooltip(self, unread_messages_no=None):
|
||||
# we look for the number of unread messages
|
||||
# and we set the appropriate tooltip
|
||||
if unread_messages_no > 1:
|
||||
text = _('Gajim - %s unread messages') % unread_messages_no
|
||||
self.tip.set_tip(self.t, text)
|
||||
elif unread_messages_no == 1:
|
||||
text = _('Gajim - 1 unread message')
|
||||
self.tip.set_tip(self.t, text)
|
||||
else: # it's None or 0
|
||||
self.change_status()
|
||||
|
||||
|
|
Loading…
Reference in New Issue