#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''模块名
@version: $Id$
@author: U{Jiahua Huang <jhuangjiahua@gmail.com>}
@license: LGPL
'''

import gtk, gobject

import sys
_print = lambda *args: None
_print = lambda *args: sys.stdout.write(' '.join([str(i) for i in args]) + '\n')

try: import i18n
except: from gettext import gettext as _

class GtkMdiTabbar(gtk.Notebook):
    homogeneous_tabs = False

    def __init__(self):
        self.__gobject_init__()
        self.set_scrollable(True)
        self.popup_enable()
        self.set_homogeneous_tabs(self.homogeneous_tabs)
        self.unset_flags(gtk.CAN_FOCUS)
        ##
        self._is_action_jn = False
        ##
        #self.connect("grab-focus", self.on_focus)
        #self.connect("focus-tab", self.on_focus_tab)
        self.connect("create-window", self.on_create_window)
        self.connect("page-reordered", self.on_page_reordered)
        self.connect("change-current-page", self.on_change_current_page)
        self.connect("select-page", self.on_select_page)
        self.connect("switch-page", self.on_switch_page)
        pass

    def add(self, child):
        p = gtk.EventBox()
        child.tab = p
        p.p = child
        label = gtk.Label(child.title)
        self.append_page(p, label)
        self.set_tab_detachable(p, True)
        self.show_all()
        pass

    def action_tab(self, child):
        n = self.page_num(child.tab)
        self._is_action_jn = True
        self.set_current_page(n)
        pass

    def get_child_by_n(self, n):
        p = self.get_nth_page(n)
        if p:
            return p.p
        return

    def get_n_by_child(self, child):
        return  self.page_num(child.tab)

    def on_focus_tab(self, widget, *args):
        _print('on_focus_tab:', widget, args)
        pass

    def remove(self, child):
        p = self.page_num(child.tab)
        if p:
            self.remove_page(p)
            pass
        pass

    def on_focus(self, *args):
        _print('on_focus:', args)
        pass

    def on_create_window(self, page, x, y, *args):
        # when a detachable tab is dropped on the root window.
        _print('on_create_window:', page, x, y, args)
        pass

    def on_page_reordered(self, widget, child, page_num, *args):
        _print('on_page_reordered:', widget, child, page_num, args)
        pass

    def on_change_current_page(self, widget, offset, *args):
        _print('on_change_current_page:', widget, offset, args)
        pass

    def on_switch_page(self, widget, page, page_num, *args):
        if self._is_action_jn:
            self._is_action_jn = False
            return
        _print('on_switch_page:', widget, page, page_num, args)
        self.get_nth_page(page_num).p.action()
        pass

    def on_select_page(self, widget, move_focus, *args):
        _print('on_select_page:', widget, move_focus, args)
        pass

class GtkMdiWindow(gtk.EventBox):
    __gtype_name__ = 'GtkMdiWindow'
    __gsignals__ = {
        'switch': (gobject.SIGNAL_RUN_LAST, None, ()),
    }    
    bg_title = gtk.gdk.Color('#377F0C')
    fg_title = gtk.gdk.Color('#ffffff')
    defalut_max = False
    def __init__(self, child=gtk.Alignment(), title="", icon=None, skiptaskbar=False):
        self.__gobject_init__()
        self.title = title
        self.icon = icon
        self._is_in_move = False
        self._is_in_resize_rb = False
        self._is_max = False
        self._is_min = False
        ##
        self._old_x = 0
        self._old_y = 0
        self.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        ##
        self._child = child
        self.child_focus = child.child_focus
        self.child_get = child.child_get
        self.child_get_property = child.child_get_property
        self.child_notify = child.child_notify
        self.children = child.children
        self.child_set = child.child_set
        self.child_set_property = child.child_set_property
        self.child_type = child.child_type
        ##
        self.unset_flags(gtk.CAN_FOCUS)
        self.connect("set_focus_child", self.on_focus)
        self.connect("grab_focus", self.on_focus)
        ## move, resize
        self.connect("event", self.on_title_event)
        ##
        self.vbox1 = gtk.VBox(False, 0)
        ## MDI Window Border
        self.vbox1.set_border_width(3)
        #self.vbox1.connect("set_focus_child", self.on_focus)
        #self.vbox1.connect("grab_focus", self.on_focus)
        #self.vbox1.connect("expose_event", self.on_focus)
        #self.vbox1.connect("focus", self.on_focus)

        ## simulate MDI Window Title
        self.titlebar = gtk.HBox(False, 0)
        self.titlebar.unset_flags(gtk.CAN_FOCUS)
        self.titlebar.show()

        self.icon_label = gtk.Label("")
        self.icon_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
        self.icon_label.set_padding(5, 0)
        self.icon_label.set_markup("v")
        self.icon_label.show()
        ##
        eventbox = gtk.EventBox()
        eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        eventbox.connect("button_release_event", self.on_icon)
        eventbox.add(self.icon_label)
        self.titlebar.pack_start(eventbox, False, False, 0)

        self.title_label = gtk.Label(title)
        self.title_label.set_padding(10, 0)
        self.title_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
        self.title_label.show()
        self.titlebar.pack_start(self.title_label)


        ## min, max, close button
        self.min_label = gtk.Label("")
        self.min_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
        self.min_label.set_padding(5, 0)
        self.min_label.set_tooltip_markup(_("Iconify Window"))
        self.min_label.set_markup("_")
        self.min_label.show()
        ##
        eventbox = gtk.EventBox()
        eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        eventbox.connect("button_press_event", self.on_min)
        eventbox.add(self.min_label)
        self.titlebar.pack_start(eventbox, False, False, 0)

        self.max_label = gtk.Label("")
        self.max_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
        self.max_label.set_padding(5, 0)
        self.max_label.set_tooltip_markup(_("Maximize Window"))
        self.max_label.set_markup("+")
        self.max_label.show()
        ##
        eventbox = gtk.EventBox()
        eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        eventbox.connect("button_release_event", self.on_max)
        eventbox.add(self.max_label)
        self.titlebar.pack_start(eventbox, False, False, 0)

        self.close_label = gtk.Label("")
        self.close_label.modify_fg(gtk.STATE_NORMAL, self.fg_title)
        self.close_label.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        self.close_label.set_padding(5, 0)
        self.close_label.set_tooltip_markup(_("Close Window"))
        self.close_label.set_markup("x")
        self.close_label.show()
        ##
        eventbox = gtk.EventBox()
        eventbox.modify_bg(gtk.STATE_NORMAL, self.bg_title)
        eventbox.connect("button_release_event", self.on_close)
        eventbox.add(self.close_label)
        self.titlebar.pack_start(eventbox, False, False, 0)

        self.vbox1.pack_start(self.titlebar, False, False, 0)

        ## MDI Window Area
        #self.mdi_alignment = gtk.Alignment(0.5, 0.5, 0, 0)
        #self.mdi_alignment.show()
        #self.vbox1.pack_start(self.mdi_alignment)
        self._child_box = gtk.EventBox()
        self._child_box.add(self._child)
        self.vbox1.pack_start(self._child_box, True, True, 0)
        ##
        self.add(self.vbox1)
        self.show_all()
        pass

    def _raise(self, *args):
        try:
            window = self.get_window() or self.get_window(1)
            if window:
                gtk.gdk.Window.raise_(window)
                self.emit("switch", )
                pass
            pass
        except:
            pass
        pass

    def lower(self, *args):
        try:
            window = self.get_window() or self.get_window(1)
            if window:
                gtk.gdk.Window.lower(window)
                pass
            pass
        except:
            pass
        pass

    def action(self):
        _print('action:', self)
        if self._is_min:
            self.unmax()
            pass
        self._raise()
        self._child.grab_focus()
        pass

    def on_focus(self, widget, *args):
        _print('on_focus:', widget, args)
        self._raise()
        if widget and 'mditabbar' in self.parent.parent.__dict__:
            mditabbar = self.parent.parent.mditabbar
            mditabbar.action_tab(self)
            pass
        pass

    def on_title_event(self, widget, event):
        #_print('on_title_event', widget, event)
        # for move
        if event.type == gtk.gdk.BUTTON_PRESS:
            if event.button == 3:
                self.on_menu(widget, event)
                return
            else:
                self.on_focus(self)
                self._child.grab_focus()
                self._px, self._py = self.parent.get_pointer()
                ## MdiWindow x, y
                self._wx, self._wy = self.get_window().get_position()
                ## MdiArea width, height
                i, t, self._aw, self._ah = self.parent.get_allocation()
                ## MdiWindow width, height
                i, t, self._w, self._h = self.get_allocation()
                ##
                self._ox = self._wx - self._px
                self._oy = self._wy - self._py
                if self._w - event.x < 20 and self._h - event.y < 20:
                    self._is_in_resize_rb = True
                    pass
                else:
                    self._is_in_move = True
                    pass
                return
            return
        elif event.type == gtk.gdk.BUTTON_RELEASE:
            self._is_in_move = False
            self._is_in_resize_rb = False
            return
        ## move MdiWindow
        elif self._is_in_move and event.type == gtk.gdk.MOTION_NOTIFY:
            px, py = self.parent.get_pointer()
            if px < 5: px = 5
            if py < 0: py = 0
            if px > self._aw: px = self._aw
            if py > self._ah: py = self._ah
            mx = px + self._ox
            my = py + self._oy
            #self.move(mx, my)
            self.parent.move(self, mx, my)
            return
        ## resize MdiWindow
        elif self._is_in_resize_rb and event.type == gtk.gdk.MOTION_NOTIFY:
            x, y = event.x, event.y
            px, py = self.parent.get_pointer()
            if x < 30: x = 30
            if y < 30: y = 30
            if px > self._aw: x = self.get_allocation()[2]
            if py > self._ah: y = self.get_allocation()[3]
            self.set_size_request(int(x), int(y))
            return
        pass

    def on_menu(self, widget, event):
        _print('on_menu:', widget, event)
        pass

    def on_icon(self, widget, event):
        if event.button == 1:
            _print('on_icon:', widget, event)
        pass

    def on_min(self, widget, event):
        if event.button == 1:
            _print('on_min:', widget, event)
            self.min()
        pass

    def on_unmax(self, widget, event):
        if event.button != 1: return
        _print('on_unmax:', widget, event)
        self.unmax()


    def on_max(self, widget, event):
        if event.button != 1: return
        self.max()
        pass

    def on_close(self, widget, event):
        if event.button == 1:
            _print('on_close:', widget, event)
            self.close()
            pass
        pass

    def move(self, x, y):
        _print('move:', x, y)
        self.parent.move(self, x, y)
        pass

    def min(self, *args):
        self._is_min = True
        # save MdiWindow position x, y
        self._old_wx, self._old_wy = self.get_window().get_position()
        # save MdiWindow width, height
        i, t, self._old_w, self._old_h = self.get_allocation()
        self.parent.grab_focus()
        #self.lower()
        self.hide()
        if 'mditabbar' in self.parent.parent.__dict__:
            mditabbar = self.parent.parent.mditabbar
            mditabbar.next_page()
            pass
        pass

    def max(self, *args):
        i, t, self._w, self._h = self.get_allocation()
        i, t, self._aw, self._ah = self.parent.get_allocation()
        if self._w < self._aw or self._h < self._ah:
            self._is_max = False
            pass
        if self._is_max: return self.unmax()
        ##
        self._is_max = True
        self._is_min = False
        # save MdiWindow position x, y
        self._old_wx, self._old_wy = self.get_window().get_position()
        # save MdiWindow width, height
        i, t, self._old_w, self._old_h = self.get_allocation()
        self.move(0, 0)
        self.set_size_request(self._aw, self._ah)
        pass

    def unmax(self, *args):
        self._is_max = False
        self._is_min = False
        self.set_size_request(self._old_w, self._old_h)
        self.move(self._old_wx, self._old_wy)
        self.show_all()
        pass

    def close(self, *args):
        if 'mditabbar' in self.parent.parent.__dict__:
            mditabbar = self.parent.parent.mditabbar
            mditabbar.remove(self)
            pass
        self.destroy()
        pass
    
class GtkMdiArea(gtk.Layout):
    __gtype_name__ = 'GtkMdiArea'
    __gsignals__ = {
        'switch-window': (gobject.SIGNAL_RUN_LAST, None, (gtk.Widget,)),
    }
    need_resize = 1L
    def __init__(self):
        self.__gobject_init__()
        #self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#003300"))
        self._old_w = 0
        self._old_h = 0
        self.unset_flags(gtk.CAN_FOCUS)
        self.connect("size-allocate", self.on_resize)
        pass

    def add(self, mdiwindow, x=0, y=0):
        gtk.Layout.put(self, mdiwindow, x, y)
        mdiwindow.connect("switch", self.on_switch)
        pass

    def on_resize(self, widget, rectangle):
        i, t, w, h = rectangle
        if self._old_w == w and self._old_h == h:
            return
        _print('on_resize:', widget, rectangle)
        self._old_w, self._old_h = w, h
        for p in self.children():
            if p._is_max:
                p.set_size_request(w, h)
                pass
            pass
        pass

    def on_switch(self, widget, *args):
        _print('on_switch', self, widget, args)
        self.emit("switch-window", widget)
        if 'mditabbar' in self.parent.__dict__:
            mditabbar = self.parent.mditabbar
            mditabbar.action_tab(widget)
            pass
        pass

class GtkMdi(gtk.Table):
    def __init__(self):
        self.__gobject_init__()
        self.mdiarea = GtkMdiArea()
        self.mditabbar = GtkMdiTabbar()
        ## table.attach(widget, left_attach=0, right_attach=1, top_attach=0, bottom_attach=1)
        self.attach(self.mditabbar, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
        self.attach(self.mdiarea,    0, 1, 1, 2)
        pass

    def set_tab_pos(self, pos):
        # pos: 0: left, 1: right, 2: top, 3: bottom
        pass

    def add(self, mdiwindow, x=0, y=0):
        self.mdiarea.add(mdiwindow, x, y)
        self.mditabbar.add(mdiwindow)
        pass

    def tab_top(self, *args):
        pass


def _demo():
    _print('main')
    w = gtk.Window()
    w.set_title("Test MDI")
    w.set_default_size(500, 500)
    mdi = GtkMdi()
    ##
    ts = gtk.ScrolledWindow()
    ts.add(gtk.TextView())
    ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    ts.set_size_request(150, 150)
    mw = GtkMdiWindow(ts, 'MDI Document 1')
    mdi.add(mw, 0, 0)
    ##
    ts = gtk.ScrolledWindow()
    ts.add(gtk.TextView())
    ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    ts.set_size_request(150, 150)
    mw = GtkMdiWindow(ts, 'MDI Document 2')
    mdi.add(mw, 30, 30)
    ##
    ts = gtk.ScrolledWindow()
    ts.add(gtk.TextView())
    ts.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    ts.set_size_request(150, 150)
    mw = GtkMdiWindow(ts, 'MDI Document 3')
    mdi.add(mw, 60, 60)
    
    
    w.add(mdi)
    w.show_all()
    w.connect('delete-event', gtk.main_quit)
    gtk.main()

if __name__=="__main__":
    _demo()


