Attachment 'gtkmdi.py'

Download

   1 #!/usr/bin/python
   2 # -*- coding: UTF-8 -*-
   3 '''模块名
   4 @version: $Id$
   5 @author: U{Jiahua Huang <[email protected]>}
   6 @license: LGPL
   7 '''
   8 
   9 import gtk, gobject
  10 
  11 import sys
  12 _print = lambda *args: None
  13 _print = lambda *args: sys.stdout.write(' '.join([str(i) for i in args]) + '\n')
  14 
  15 try: import i18n
  16 except: from gettext import gettext as _
  17 
  18 class GtkMdiTabbar(gtk.Notebook):
  19     homogeneous_tabs = False
  20 
  21     def __init__(self):
  22         self.__gobject_init__()
  23         self.set_scrollable(True)
  24         self.popup_enable()
  25         self.set_homogeneous_tabs(self.homogeneous_tabs)
  26         self.unset_flags(gtk.CAN_FOCUS)
  27         ##
  28         self._is_action_jn = False
  29         ##
  30         #self.connect("grab-focus", self.on_focus)
  31         #self.connect("focus-tab", self.on_focus_tab)
  32         self.connect("create-window", self.on_create_window)
  33         self.connect("page-reordered", self.on_page_reordered)
  34         self.connect("change-current-page", self.on_change_current_page)
  35         self.connect("select-page", self.on_select_page)
  36         self.connect("switch-page", self.on_switch_page)
  37         pass
  38 
  39     def add(self, child):
  40         p = gtk.EventBox()
  41         child.tab = p
  42         p.p = child
  43         label = gtk.Label(child.title)
  44         self.append_page(p, label)
  45         self.set_tab_detachable(p, True)
  46         self.show_all()
  47         pass
  48 
  49     def action_tab(self, child):
  50         n = self.page_num(child.tab)
  51         self._is_action_jn = True
  52         self.set_current_page(n)
  53         pass
  54 
  55     def get_child_by_n(self, n):
  56         p = self.get_nth_page(n)
  57         if p:
  58             return p.p
  59         return
  60 
  61     def get_n_by_child(self, child):
  62         return  self.page_num(child.tab)
  63 
  64     def on_focus_tab(self, widget, *args):
  65         _print('on_focus_tab:', widget, args)
  66         pass
  67 
  68     def remove(self, child):
  69         p = self.page_num(child.tab)
  70         if p:
  71             self.remove_page(p)
  72             pass
  73         pass
  74 
  75     def on_focus(self, *args):
  76         _print('on_focus:', args)
  77         pass
  78 
  79     def on_create_window(self, page, x, y, *args):
  80         # when a detachable tab is dropped on the root window.
  81         _print('on_create_window:', page, x, y, args)
  82         pass
  83 
  84     def on_page_reordered(self, widget, child, page_num, *args):
  85         _print('on_page_reordered:', widget, child, page_num, args)
  86         pass
  87 
  88     def on_change_current_page(self, widget, offset, *args):
  89         _print('on_change_current_page:', widget, offset, args)
  90         pass
  91 
  92     def on_switch_page(self, widget, page, page_num, *args):
  93         if self._is_action_jn:
  94             self._is_action_jn = False
  95             return
  96         _print('on_switch_page:', widget, page, page_num, args)
  97         self.get_nth_page(page_num).p.action()
  98         pass
  99 
 100     def on_select_page(self, widget, move_focus, *args):
 101         _print('on_select_page:', widget, move_focus, args)
 102         pass
 103 
 104 class GtkMdiWindow(gtk.EventBox):
 105     __gtype_name__ = 'GtkMdiWindow'
 106     __gsignals__ = {
 107         'switch': (gobject.SIGNAL_RUN_LAST, None, ()),
 108     }    
 109     bg_title = gtk.gdk.Color('#377F0C')
 110     fg_title = gtk.gdk.Color('#ffffff')
 111     defalut_max = False
 112     def __init__(self, child=gtk.Alignment(), title="", icon=None, skiptaskbar=False):
 113         self.__gobject_init__()
 114         self.title = title
 115         self.icon = icon
 116         self._is_in_move = False
 117         self._is_in_resize_rb = False
 118         self._is_max = False
 119         self._is_min = False
 120         ##
 121         self._old_x = 0
 122         self._old_y = 0
 123         self.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 124         ##
 125         self._child = child
 126         self.child_focus = child.child_focus
 127         self.child_get = child.child_get
 128         self.child_get_property = child.child_get_property
 129         self.child_notify = child.child_notify
 130         self.children = child.children
 131         self.child_set = child.child_set
 132         self.child_set_property = child.child_set_property
 133         self.child_type = child.child_type
 134         ##
 135         self.unset_flags(gtk.CAN_FOCUS)
 136         self.connect("set_focus_child", self.on_focus)
 137         self.connect("grab_focus", self.on_focus)
 138         ## move, resize
 139         self.connect("event", self.on_title_event)
 140         ##
 141         self.vbox1 = gtk.VBox(False, 0)
 142         ## MDI Window Border
 143         self.vbox1.set_border_width(3)
 144         #self.vbox1.connect("set_focus_child", self.on_focus)
 145         #self.vbox1.connect("grab_focus", self.on_focus)
 146         #self.vbox1.connect("expose_event", self.on_focus)
 147         #self.vbox1.connect("focus", self.on_focus)
 148 
 149         ## simulate MDI Window Title
 150         self.titlebar = gtk.HBox(False, 0)
 151         self.titlebar.unset_flags(gtk.CAN_FOCUS)
 152         self.titlebar.show()
 153 
 154         self.icon_label = gtk.Label("")
 155         self.icon_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
 156         self.icon_label.set_padding(5, 0)
 157         self.icon_label.set_markup("v")
 158         self.icon_label.show()
 159         ##
 160         eventbox = gtk.EventBox()
 161         eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 162         eventbox.connect("button_release_event", self.on_icon)
 163         eventbox.add(self.icon_label)
 164         self.titlebar.pack_start(eventbox, False, False, 0)
 165 
 166         self.title_label = gtk.Label(title)
 167         self.title_label.set_padding(10, 0)
 168         self.title_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
 169         self.title_label.show()
 170         self.titlebar.pack_start(self.title_label)
 171 
 172 
 173         ## min, max, close button
 174         self.min_label = gtk.Label("")
 175         self.min_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
 176         self.min_label.set_padding(5, 0)
 177         self.min_label.set_tooltip_markup(_("Iconify Window"))
 178         self.min_label.set_markup("_")
 179         self.min_label.show()
 180         ##
 181         eventbox = gtk.EventBox()
 182         eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 183         eventbox.connect("button_press_event", self.on_min)
 184         eventbox.add(self.min_label)
 185         self.titlebar.pack_start(eventbox, False, False, 0)
 186 
 187         self.max_label = gtk.Label("")
 188         self.max_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
 189         self.max_label.set_padding(5, 0)
 190         self.max_label.set_tooltip_markup(_("Maximize Window"))
 191         self.max_label.set_markup("+")
 192         self.max_label.show()
 193         ##
 194         eventbox = gtk.EventBox()
 195         eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 196         eventbox.connect("button_release_event", self.on_max)
 197         eventbox.add(self.max_label)
 198         self.titlebar.pack_start(eventbox, False, False, 0)
 199 
 200         self.close_label = gtk.Label("")
 201         self.close_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
 202         self.close_label.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 203         self.close_label.set_padding(5, 0)
 204         self.close_label.set_tooltip_markup(_("Close Window"))
 205         self.close_label.set_markup("x")
 206         self.close_label.show()
 207         ##
 208         eventbox = gtk.EventBox()
 209         eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
 210         eventbox.connect("button_release_event", self.on_close)
 211         eventbox.add(self.close_label)
 212         self.titlebar.pack_start(eventbox, False, False, 0)
 213 
 214         self.vbox1.pack_start(self.titlebar, False, False, 0)
 215 
 216         ## MDI Window Area
 217         #self.mdi_alignment = gtk.Alignment(0.5, 0.5, 0, 0)
 218         #self.mdi_alignment.show()
 219         #self.vbox1.pack_start(self.mdi_alignment)
 220         self._child_box = gtk.EventBox()
 221         self._child_box.add(self._child)
 222         self.vbox1.pack_start(self._child_box, True, True, 0)
 223         ##
 224         self.add(self.vbox1)
 225         self.show_all()
 226         pass
 227 
 228     def _raise(self, *args):
 229         try:
 230             window = self.get_window() or self.get_window(1)
 231             if window:
 232                 gtk.gdk.Window.raise_(window)
 233                 self.emit("switch", )
 234                 pass
 235             pass
 236         except:
 237             pass
 238         pass
 239 
 240     def lower(self, *args):
 241         try:
 242             window = self.get_window() or self.get_window(1)
 243             if window:
 244                 gtk.gdk.Window.lower(window)
 245                 pass
 246             pass
 247         except:
 248             pass
 249         pass
 250 
 251     def action(self):
 252         _print('action:', self)
 253         if self._is_min:
 254             self.unmax()
 255             pass
 256         self._raise()
 257         self._child.grab_focus()
 258         pass
 259 
 260     def on_focus(self, widget, *args):
 261         _print('on_focus:', widget, args)
 262         self._raise()
 263         if widget and 'mditabbar' in self.parent.parent.__dict__:
 264             mditabbar = self.parent.parent.mditabbar
 265             mditabbar.action_tab(self)
 266             pass
 267         pass
 268 
 269     def on_title_event(self, widget, event):
 270         #_print('on_title_event', widget, event)
 271         # for move
 272         if event.type == gtk.gdk.BUTTON_PRESS:
 273             if event.button == 3:
 274                 self.on_menu(widget, event)
 275                 return
 276             else:
 277                 self.on_focus(self)
 278                 self._child.grab_focus()
 279                 self._px, self._py = self.parent.get_pointer()
 280                 ## MdiWindow x, y
 281                 self._wx, self._wy = self.get_window().get_position()
 282                 ## MdiArea width, height
 283                 i, t, self._aw, self._ah = self.parent.get_allocation()
 284                 ## MdiWindow width, height
 285                 i, t, self._w, self._h = self.get_allocation()
 286                 ##
 287                 self._ox = self._wx - self._px
 288                 self._oy = self._wy - self._py
 289                 if self._w - event.x < 20 and self._h - event.y < 20:
 290                     self._is_in_resize_rb = True
 291                     pass
 292                 else:
 293                     self._is_in_move = True
 294                     pass
 295                 return
 296             return
 297         elif event.type == gtk.gdk.BUTTON_RELEASE:
 298             self._is_in_move = False
 299             self._is_in_resize_rb = False
 300             return
 301         ## move MdiWindow
 302         elif self._is_in_move and event.type == gtk.gdk.MOTION_NOTIFY:
 303             px, py = self.parent.get_pointer()
 304             if px < 5: px = 5
 305             if py < 0: py = 0
 306             if px > self._aw: px = self._aw
 307             if py > self._ah: py = self._ah
 308             mx = px + self._ox
 309             my = py + self._oy
 310             #self.move(mx, my)
 311             self.parent.move(self, mx, my)
 312             return
 313         ## resize MdiWindow
 314         elif self._is_in_resize_rb and event.type == gtk.gdk.MOTION_NOTIFY:
 315             x, y = event.x, event.y
 316             px, py = self.parent.get_pointer()
 317             if x < 30: x = 30
 318             if y < 30: y = 30
 319             if px > self._aw: x = self.get_allocation()[2]
 320             if py > self._ah: y = self.get_allocation()[3]
 321             self.set_size_request(int(x), int(y))
 322             return
 323         pass
 324 
 325     def on_menu(self, widget, event):
 326         _print('on_menu:', widget, event)
 327         pass
 328 
 329     def on_icon(self, widget, event):
 330         if event.button == 1:
 331             _print('on_icon:', widget, event)
 332         pass
 333 
 334     def on_min(self, widget, event):
 335         if event.button == 1:
 336             _print('on_min:', widget, event)
 337             self.min()
 338         pass
 339 
 340     def on_unmax(self, widget, event):
 341         if event.button != 1: return
 342         _print('on_unmax:', widget, event)
 343         self.unmax()
 344 
 345 
 346     def on_max(self, widget, event):
 347         if event.button != 1: return
 348         self.max()
 349         pass
 350 
 351     def on_close(self, widget, event):
 352         if event.button == 1:
 353             _print('on_close:', widget, event)
 354             self.close()
 355             pass
 356         pass
 357 
 358     def move(self, x, y):
 359         _print('move:', x, y)
 360         self.parent.move(self, x, y)
 361         pass
 362 
 363     def min(self, *args):
 364         self._is_min = True
 365         # save MdiWindow position x, y
 366         self._old_wx, self._old_wy = self.get_window().get_position()
 367         # save MdiWindow width, height
 368         i, t, self._old_w, self._old_h = self.get_allocation()
 369         self.parent.grab_focus()
 370         #self.lower()
 371         self.hide()
 372         if 'mditabbar' in self.parent.parent.__dict__:
 373             mditabbar = self.parent.parent.mditabbar
 374             mditabbar.next_page()
 375             pass
 376         pass
 377 
 378     def max(self, *args):
 379         i, t, self._w, self._h = self.get_allocation()
 380         i, t, self._aw, self._ah = self.parent.get_allocation()
 381         if self._w < self._aw or self._h < self._ah:
 382             self._is_max = False
 383             pass
 384         if self._is_max: return self.unmax()
 385         ##
 386         self._is_max = True
 387         self._is_min = False
 388         # save MdiWindow position x, y
 389         self._old_wx, self._old_wy = self.get_window().get_position()
 390         # save MdiWindow width, height
 391         i, t, self._old_w, self._old_h = self.get_allocation()
 392         self.move(0, 0)
 393         self.set_size_request(self._aw, self._ah)
 394         pass
 395 
 396     def unmax(self, *args):
 397         self._is_max = False
 398         self._is_min = False
 399         self.set_size_request(self._old_w, self._old_h)
 400         self.move(self._old_wx, self._old_wy)
 401         self.show_all()
 402         pass
 403 
 404     def close(self, *args):
 405         if 'mditabbar' in self.parent.parent.__dict__:
 406             mditabbar = self.parent.parent.mditabbar
 407             mditabbar.remove(self)
 408             pass
 409         self.destroy()
 410         pass
 411     
 412 class GtkMdiArea(gtk.Layout):
 413     __gtype_name__ = 'GtkMdiArea'
 414     __gsignals__ = {
 415         'switch-window': (gobject.SIGNAL_RUN_LAST, None, (gtk.Widget,)),
 416     }
 417     need_resize = 1L
 418     def __init__(self):
 419         self.__gobject_init__()
 420         #self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#003300"))
 421         self._old_w = 0
 422         self._old_h = 0
 423         self.unset_flags(gtk.CAN_FOCUS)
 424         self.connect("size-allocate", self.on_resize)
 425         pass
 426 
 427     def add(self, mdiwindow, x=0, y=0):
 428         gtk.Layout.put(self, mdiwindow, x, y)
 429         mdiwindow.connect("switch", self.on_switch)
 430         pass
 431 
 432     def on_resize(self, widget, rectangle):
 433         i, t, w, h = rectangle
 434         if self._old_w == w and self._old_h == h:
 435             return
 436         _print('on_resize:', widget, rectangle)
 437         self._old_w, self._old_h = w, h
 438         for p in self.children():
 439             if p._is_max:
 440                 p.set_size_request(w, h)
 441                 pass
 442             pass
 443         pass
 444 
 445     def on_switch(self, widget, *args):
 446         _print('on_switch', self, widget, args)
 447         self.emit("switch-window", widget)
 448         if 'mditabbar' in self.parent.__dict__:
 449             mditabbar = self.parent.mditabbar
 450             mditabbar.action_tab(widget)
 451             pass
 452         pass
 453 
 454 class GtkMdi(gtk.Table):
 455     def __init__(self):
 456         self.__gobject_init__()
 457         self.mdiarea = GtkMdiArea()
 458         self.mditabbar = GtkMdiTabbar()
 459         ## table.attach(widget, left_attach=0, right_attach=1, top_attach=0, bottom_attach=1)
 460         self.attach(self.mditabbar, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
 461         self.attach(self.mdiarea,    0, 1, 1, 2)
 462         pass
 463 
 464     def set_tab_pos(self, pos):
 465         # pos: 0: left, 1: right, 2: top, 3: bottom
 466         pass
 467 
 468     def add(self, mdiwindow, x=0, y=0):
 469         self.mdiarea.add(mdiwindow, x, y)
 470         self.mditabbar.add(mdiwindow)
 471         pass
 472 
 473     def tab_top(self, *args):
 474         pass
 475 
 476 
 477 def _demo():
 478     _print('main')
 479     w = gtk.Window()
 480     w.set_title("Test MDI")
 481     w.set_default_size(500, 500)
 482     mdi = GtkMdi()
 483     ##
 484     ts = gtk.ScrolledWindow()
 485     ts.add(gtk.TextView())
 486     ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 487     ts.set_size_request(150, 150)
 488     mw = GtkMdiWindow(ts, 'MDI Document 1')
 489     mdi.add(mw, 0, 0)
 490     ##
 491     ts = gtk.ScrolledWindow()
 492     ts.add(gtk.TextView())
 493     ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 494     ts.set_size_request(150, 150)
 495     mw = GtkMdiWindow(ts, 'MDI Document 2')
 496     mdi.add(mw, 30, 30)
 497     ##
 498     ts = gtk.ScrolledWindow()
 499     ts.add(gtk.TextView())
 500     ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 501     ts.set_size_request(150, 150)
 502     mw = GtkMdiWindow(ts, 'MDI Document 3')
 503     mdi.add(mw, 60, 60)
 504     
 505     
 506     w.add(mdi)
 507     w.show_all()
 508     w.connect('delete-event', gtk.main_quit)
 509     gtk.main()
 510 
 511 if __name__=="__main__":
 512     _demo()

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2021-05-11 08:52:12, 61.1 KB) [[attachment:Screenshot-Test-MDI-1.png]]
  • [get | view] (2021-05-11 08:52:12, 15.9 KB) [[attachment:gtkmdi.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.