📄 gui.py
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.0 (the License). You may not copy or use this file, in either# source code or executable form, except in compliance with the License. You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License# for the specific language governing rights and limitations under the# License.# written by Matt Chisholmfrom __future__ import divisionimport gtkimport pangoimport gobjectimport os.pathimport threadingfrom __init__ import image_root, app_name, FAQ_URLSPACING = 8WINDOW_TITLE_LENGTH = 128 # do we need this?WINDOW_WIDTH = 600MAX_WINDOW_HEIGHT = 600 # BUG: can we get this from the user's screen size?MAX_WINDOW_WIDTH = 600 # BUG: can we get this from the user's screen size?MIN_MULTI_PANE_HEIGHT = 160BT_TARGET_TYPE = 0EXTERNAL_TARGET_TYPE = 1BT_TARGET = ("application/x-bittorrent", gtk.TARGET_SAME_APP, BT_TARGET_TYPE )EXTERNAL_TARGET = ("text/uri-list" , 0 , EXTERNAL_TARGET_TYPE)# a slightly hackish but very reliable way to get OS scrollbar widthsw = gtk.ScrolledWindow()SCROLLBAR_WIDTH = sw.size_request()[0] - 48del swdef align(obj,x,y): a = gtk.Alignment(x,y,0,0) a.add(obj) return a def halign(obj, amt): return align(obj,amt,0.5)def lalign(obj): return halign(obj,0)def ralign(obj): return halign(obj,1)def valign(obj, amt): return align(obj,0.5,amt)factory = gtk.IconFactory()# these don't seem to be documented anywhere:# ICON_SIZE_BUTTON = 20x20# ICON_SIZE_LARGE_TOOLBAR = 24x24for n in 'broken finished info pause paused play queued running remove'.split(): fn = os.path.join(image_root, ("%s.png"%n)) pixbuf = gtk.gdk.pixbuf_new_from_file(fn) set = gtk.IconSet(pixbuf) factory.add('bt-%s'%n, set)factory.add_default()def get_logo(size=32): fn = os.path.join(image_root, 'logo', 'bittorrent_%d.png'%size) logo = gtk.Image() logo.set_from_file(fn) return logoclass Size(long): """displays size in human-readable format""" size_labels = ['','K','M','G','T','P','E','Z','Y'] radix = 2**10 def __new__(cls, value, precision=None): self = long.__new__(cls, value) return self def __init__(self, value, precision=0): long.__init__(self, value) self.precision = precision def __str__(self, precision=None): if precision is None: precision = self.precision value = self for unitname in self.size_labels: if value < self.radix and precision < self.radix: break value /= self.radix precision /= self.radix if unitname and value < 10 and precision < 1: return '%.1f %sB' % (value, unitname) else: return '%.0f %sB' % (value, unitname)class Rate(Size): """displays rate in human-readable format""" def __init__(self, value, precision=2**10): Size.__init__(self, value, precision) def __str__(self, precision=None): return '%s/s'% Size.__str__(self, precision=None)class Duration(float): """displays duration in human-readable format""" def __str__(value): if value > 365 * 24 * 60 * 60: return '?' elif value >= 172800: return '%d days' % (value//86400) # 2 days or longer elif value >= 86400: return '1 day %d hours' % ((value-86400)//3600) # 1-2 days elif value >= 3600: return '%d:%02d hours' % (value//3600, (value%3600)//60) # 1 h - 1 day elif value >= 60: return '%d:%02d minutes' % (value//60, value%60) # 1 minute to 1 hour elif value >= 0: return '%d seconds' % int(value) else: return '0 seconds'class IconButton(gtk.Button): def __init__(self, label, iconpath=None, stock=None): gtk.Button.__init__(self) self.hbox = gtk.HBox(spacing=5) self.icon = gtk.Image() if stock is not None: self.icon.set_from_stock(stock, gtk.ICON_SIZE_BUTTON) elif iconpath is not None: self.icon.set_from_file(iconpath) else: raise TypeError, "IconButton needs iconpath or stock" self.hbox.pack_start(self.icon) self.label = gtk.Label(label) self.hbox.pack_start(self.label) self.add(halign(self.hbox, 0.5))class Window(gtk.Window): def __init__(self, *args): apply(gtk.Window.__init__, (self,)+args) self.set_icon_from_file(os.path.join(image_root,'bittorrent.ico'))class HelpWindow(Window): def __init__(self, main, helptext): Window.__init__(self) self.set_title('%s Help'%app_name) self.main = main self.set_border_width(SPACING) self.vbox = gtk.VBox(spacing=SPACING) self.faq_box = gtk.HBox(spacing=SPACING) self.faq_box.pack_start(gtk.Label("Frequently Asked Questions:"), expand=False, fill=False) self.faq_url = gtk.Entry() self.faq_url.set_text(FAQ_URL) self.faq_url.set_editable(False) self.faq_box.pack_start(self.faq_url, expand=True, fill=True) self.faq_button = gtk.Button('Go') self.faq_button.connect('clicked', lambda w: self.main.visit_url(FAQ_URL) ) self.faq_box.pack_start(self.faq_button, expand=False, fill=False) self.vbox.pack_start(self.faq_box, expand=False, fill=False) self.cmdline_args = gtk.Label(helptext) self.cmdline_sw = ScrolledWindow() self.cmdline_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) self.cmdline_sw.add_with_viewport(self.cmdline_args) self.cmdline_sw.set_size_request(self.cmdline_args.size_request()[0]+SCROLLBAR_WIDTH, 200) self.vbox.pack_start(self.cmdline_sw) self.add(self.vbox) self.show_all() if self.main is not None: self.connect('destroy', lambda w: self.main.window_closed('help')) else: self.connect('destroy', lambda w: gtk.main_quit()) gtk.main() def close(self, widget=None): self.destroy() class ScrolledWindow(gtk.ScrolledWindow): def scroll_to_bottom(self): child_height = self.child.child.size_request()[1] self.scroll_to(0, child_height) def scroll_by(self, dx=0, dy=0): v = self.get_vadjustment() new_y = min(v.upper, v.value + dy) self.scroll_to(0, new_y) def scroll_to(self, x=0, y=0): v = self.get_vadjustment() child_height = self.child.child.size_request()[1] new_adj = gtk.Adjustment(y, 0, child_height) self.set_vadjustment(new_adj)class AutoScrollingWindow(ScrolledWindow): def __init__(self): ScrolledWindow.__init__(self) self.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP, [( "application/x-bittorrent", gtk.TARGET_SAME_APP, BT_TARGET_TYPE )], gtk.gdk.ACTION_MOVE) self.connect('drag_motion' , self.drag_motion )# self.connect('drag_data_received', self.drag_data_received) self.vscrolltimeout = None# def drag_data_received(self, widget, context, x, y, selection, targetType, time):# print 'AutoScrollingWindow.drag_data_received(', widget def drag_motion(self, widget, context, x, y, time): v = self.get_vadjustment() if v.page_size - y <= 10: amount = (10 - int(v.page_size - y)) * 2 self.start_scrolling(amount) elif y <= 10: amount = (y - 10) * 2 self.start_scrolling(amount) else: self.stop_scrolling() def scroll_and_wait(self, amount, lock_held): if not lock_held: gtk.threads_enter() self.scroll_by(0, amount) if not lock_held: gtk.threads_leave()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -