Hi! 

thanks for your reply!

On Sat, 2005-12-03 at 18:55 +0100, Jakub Piotr Cłapa wrote:

> > 2. I can't hide any of the widgets. E.g. a call to
> > self.__cal_label.hide() does not hide the label

Okay I found the problem to this, I used mainwindow.show_all()
in the test case. This had the effect that I could no longer hide the
time controls. 
But unfortunately this behaviour is different from what is done in the c
code! I am really lost with this one! 
Why are the widgets in the c code not shwown by the call to show_all??

> > 3. The c version of the widget had two different constructors, as far as
> > I understood is this impossible in python, so how do you cope with it.
> 
> You add keyword arguments to __init__ and check them on runtime or (my 
> own idea; not sure if it's Harmful(TM)) add a class method returning an 
> instance.

I dont' like the idea, since the two keywords would mean the same thing
and it would be unclear which one to fill out, or even both...
So overloading would be the best, if possible.
How do others handle this?

Finally I have attached the new state of the widget, it already is
useable, even so I have not yet added the set_property, get_property
stuff. Some help / demo code with this part would also be very cool.

Anyways this version can already be tested for functionality and bugs!

Thanks a lot, Fabian


# Python GTK+ date and time entry widget.
# Copyright (C) 2005  Fabian Sturm
#
# ported from the libgnomeui/gnome-dateedit.c
#
# This widget is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this widget; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA


import pygtk

pygtk.require('2.0')

import gobject
import gtk
from gtk import gdk
import time
import datetime


(DATE_EDIT_SHOW_TIME, 
 DATE_EDIT_24_HR, 
 DATE_EDIT_WEEK_STARTS_ON_MONDAY) = [1 << 0, 1 << 1, 1 << 2]
 
(DATE_CHANGED,
 TIME_CHANGED) = [1 << 0, 1 << 1]

 
 # gnome_date_edit_new:
 # @the_time: date and time to be displayed on the widget
 # @show_time: whether time should be displayed
 # @use_24_format: whether 24-hour format is desired for the time display.
 #
 # Description: Creates a new #GnomeDateEdit widget which can be used
 # to provide an easy to use way for entering dates and times.
 # If @the_time is 0 then current time is used.
 #
 # Returns: a new #GnomeDateEdit widget.
 # Todo: missing the version with the flags in the constructor
class DateEdit(gtk.HBox):
    __gtype_name__ = 'DateEdit'

    def __init__(self, the_time = None, show_time = True, use_24_format = True):
        gtk.HBox.__init__(self)

        # register custom signals, help can anyone explain this call parameters?
        # (I mean better than in the api docs)
        gobject.signal_new('time_changed', DateEdit,
                       gobject.SIGNAL_RUN_FIRST,
                       gobject.TYPE_NONE,
                       (gobject.TYPE_PYOBJECT,))
        gobject.signal_new('date_changed', DateEdit,
                       gobject.SIGNAL_RUN_FIRST,
                       gobject.TYPE_NONE,
                       (gobject.TYPE_PYOBJECT,))                       
        
        # preset values
        self.__lower_hour = 7;
        self.__upper_hour = 19;
        self.__flags = DATE_EDIT_SHOW_TIME

        # the date entry
        self.__date_entry = gtk.Entry()
        self.__date_entry.set_size_request(90, -1)
        self.pack_start(self.__date_entry, True, True, 0)
        self.__date_entry.show()
        
        # the date button
        self.__date_button = gtk.Button()
        self.__date_button.connect('clicked', self.select_clicked)
        self.pack_start(self.__date_button, False, False, 0)
        hbox = gtk.HBox(False, 3)
        self.__date_button.add(hbox)
        hbox.show()
        # calendar label, only show if the date editor has a time field
        self.__cal_label = gtk.Label('Calendar')
        self.__cal_label.set_alignment(0.0, 0.5)
        hbox.pack_start(self.__cal_label, True, True, 0)
        self.__cal_label.show()
        # the down arrow
        arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
        hbox.pack_start(arrow, True, False, 0)
        arrow.show()
        # finally show the button
        self.__date_button.show()
        
        # the time entry
        self.__time_entry = gtk.Entry()
        self.__time_entry.set_max_length(12)
        self.__time_entry.set_size_request(88, -1)
        self.pack_start(self.__time_entry, True, True, 0)
            
        # the time popup menu
        self.__time_popup = gtk.OptionMenu()
        self.pack_start(self.__time_popup, False, False, 0)
        self.connect('realize', self.fill_time_popup)
        
        if show_time == True:
            self.__time_entry.show()
            self.__time_popup.show()
        
        # the calendar popup
        self.__cal_popup = gtk.Window(gtk.WINDOW_POPUP)
        self.__cal_popup.set_events(self.__cal_popup.get_events() | gdk.KEY_PRESS_MASK)
        self.__cal_popup.connect('delete_event', self.delete_popup)
        self.__cal_popup.connect('key_press_event', self.key_press_popup)
        self.__cal_popup.connect('button_press_event', self.button_press_popup)
        self.__cal_popup.set_resizable(False) # Todo: Needed?
        frame = gtk.Frame()
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.__cal_popup.add(frame)
        frame.show()
        # the calendar
        self.__calendar = gtk.Calendar()
        self.__calendar.display_options(gtk.CALENDAR_SHOW_DAY_NAMES 
                                        | gtk.CALENDAR_SHOW_HEADING)
        self.__calendar.connect('day-selected', self.day_selected)
        self.__calendar.connect('day-selected-double-click', self.day_selected_double_click)
        frame.add(self.__calendar)
        self.__calendar.show()

        # set user provided flags, will toggle visibility of some widgets
        new_flags = 0
        if show_time is True:
            new_flags |= DATE_EDIT_SHOW_TIME
        if use_24_format is True:
            new_flags |= DATE_EDIT_24_HR
        self.set_flags(new_flags)

        # set provided date and time
        self.set_date_time(the_time)
        
    
    # Changes the display flags on an existing date editor widget
    def set_flags(self, flags):
        old_flags = self.__flags
        self.__flags = flags
        
        if (flags & DATE_EDIT_SHOW_TIME) != (old_flags & DATE_EDIT_SHOW_TIME):
            if flags & DATE_EDIT_SHOW_TIME is True:
                print 'show'
                self.__cal_label.show()
                self.__time_entry.show()
                self.__time_popup.show()
            else:
                print 'hide'
                self.__cal_label.hide()
                self.__time_entry.hide()
                self.__time_popup.hide()
            
        if (flags & DATE_EDIT_24_HR) != (old_flags & DATE_EDIT_24_HR):
            self.fill_time_popup(self)
        
        if (flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY) is (old_flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY):
            if flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY is True:
                self.__calendar.set_display_options(self.__calendar.get_display_options() | gtk.CALENDAR_WEEK_START_MONDAY)
            else:
                self.__calendar.set_display_options(self.__calendar.get_display_options() & ~gtk.CALENDAR_WEEK_START_MONDAY)
                 
            
    def set_date_time(self, the_time):      
        if the_time is None:
            the_time = datetime.datetime.today()
        assert isinstance(the_time, (datetime.datetime, datetime.date))
        # set the date
        self.__initial_time = the_time
        self.__date_entry.set_text(the_time.strftime('%x'))
        # set the time
        if self.__flags & DATE_EDIT_24_HR is True:
            self.__time_entry.set_text(the_time.strftime('%H:%M'))
        else:
            self.__time_entry.set_text(the_time.strftime('%I:%M %p'))


    def popup_grab_on_window(self, window, activate_time):
        if gdk.pointer_grab(window, True, gdk.BUTTON_PRESS_MASK 
                                          | gdk.BUTTON_RELEASE_MASK
                                          | gdk.POINTER_MOTION_MASK, 
                            None, None, activate_time) == 0:
                if gdk.keyboard_grab (window, True, activate_time) == 0:
                    return True
                else:
                    gdk.pointer_ungrab(activate_time)
                    return False
        return False


    def select_clicked(self, widget, data=None):
        # Temporarily grab pointer and keyboard on a window we know exists        
        if not self.popup_grab_on_window(widget.window, gtk.get_current_event_time()):
            print 'error during grab'
            return
        
        # set calendar date
        str = self.__date_entry.get_text()
        mtime = time.strptime(str, '%x')
        self.__calendar.select_month(mtime.tm_mon - 1, mtime.tm_year)
        self.__calendar.select_day(mtime.tm_mday)        
        
        # position and show popup window
        self.position_popup()
        self.__cal_popup.grab_add()
        self.__cal_popup.show()
        self.__calendar.grab_focus()
        
        # Now transfer our grabs to the popup window, this should always succed
        self.popup_grab_on_window(self.__cal_popup.window, gtk.get_current_event_time())


    def position_popup(self):
        req = self.__cal_popup.size_request()
        (x,y) = gdk.Window.get_origin(self.__date_button.window)

        x += self.__date_button.allocation.x
        y += self.__date_button.allocation.y
        bwidth = self.__date_button.allocation.width
        bheight = self.__date_button.allocation.height

        x += bwidth - req[0]
        y += bheight

        if x < 0: x = 0
        if y < 0: y = 0
        
        self.__cal_popup.move(x,y)


    def day_selected(self, widget, data=None):
        (year, month, day) = self.__calendar.get_date()
        month += 1        
        the_time = datetime.date(year, month, day)
        self.__date_entry.set_text(the_time.strftime('%x'))
        self.emit('date_changed', None)
        
        
    def day_selected_double_click(self, widget, data=None):
        self.hide_popup()


    def hide_popup(self):
        self.__cal_popup.hide()
        self.__cal_popup.grab_remove()


    def key_press_popup(self, widget, data=None):        
        # Todo, Fixme: what is the name of gdk.Escape? missing?
        if data == None or data.keyval != 65307:
            return False

        # Todo: does not work and what does it do anyway?
        # widget.stop_emission_by_name('key_press_event')
        self.hide_popup()
        return True


    # Todo: is this correct?
    def button_press_popup(self, widget, data=None):
        # We don't ask for button press events on the grab widget, so
        # if an event is reported directly to the grab widget, it must
        # be on a window outside the application (and thus we remove
        # the popup window). Otherwise, we check if the widget is a child
        # of the grab widget, and only remove the popup window if it
        # is not.
        if data == None or data.window == None:
            return False
            
        child = data.window.get_user_data()
        if child != widget:
            while child:
                if child == widget:
                    return False
                child = child.parent
                
        self.hide_popup()
        return True


    def delete_popup(self, widget, data=None):
        # Todo: when is this ever called??
        print 'delete_popup'
        hide_popup (gde);
        return TRUE;


    def fill_time_popup(self, widget, data=None):
        if self.__lower_hour > self.__upper_hour:
            return
        
        # create menu
        menu = gtk.Menu()
        for i in range(self.__lower_hour, self.__upper_hour + 1):
            the_time = datetime.time(i, 0)
            
            if self.__flags & DATE_EDIT_24_HR is True:
                label = the_time.strftime('%H:%M')
            else:
                label = the_time.strftime('%I:%M %p')
                
            item = gtk.MenuItem(label)
            menu.append(item)
            item.show()
            
            # create submenu
            submenu = gtk.Menu()
            item.set_submenu(submenu)
            for j in range(0,60,15):
                the_time = datetime.time(i,j)
                
                if self.__flags & DATE_EDIT_24_HR is True:
                    label = the_time.strftime('%H:%M')
                else:
                    label = the_time.strftime('%I:%M %p')
                # create submenu item
                submenu_item = gtk.MenuItem(label)
                submenu.append(submenu_item)
                # add event handler                
                submenu_item.connect('activate', self.time_selected, label)
                submenu_item.show()
                
        # finally replace current menu with this new one
        self.__time_popup.set_menu(menu)
            
            
    def time_selected(self, widget, data = None):
        self.__time_entry.set_text(data)
        self.emit('time_changed', None);
        
        
    # Todo: get_properties
        # PROP_TIME
        # PROP_DATE_EDIT_FLAGS
        # PROP_LOWER_HOUR
        # PROP_UPPER_HOUR
        # PROP_INITIAL_TIME
    # Todo: set_properties
        # PROP_TIME
        # PROP_DATE_EDIT_FLAGS
        # PROP_LOWER_HOUR
        # PROP_UPPER_HOUR
        
        

# Test the dateedit widget
gobject.type_register(DateEdit)

win = gtk.Window()
win.connect('delete-event', gtk.main_quit)

d = DateEdit(show_time = False)
win.add(d)
d.show()
win.show()

gtk.main()

# investgate widget.set_property("no-show-all", True)
_______________________________________________
pygtk mailing list   [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/

Reply via email to