Saturday, December 07, 2013

Simple program for a two year old child

I had blogged earlier about a program for a one year old.

Since then, my child has started identifying alphabets and has great fun hammering keys on his keyboard to produce letters. He has also started identifying numbers and lower case alphabets. Finally, he has strong preference on the color of the alphabets and the background.

So I present an update for my program, now for two year olds!

The basic structure is the same: it is a full screen GTK program that shows a number or alphabets. A number is shown in the middle of the screen. Alphabets are shown in both upper case and lower case. Finally, stars (an asterisk) is a recent favourite, so I allow typing that one special character. A brown bar at the bottom fills up as sleep-time approaches. This was useful in making the child aware of time: as the bar filled up, night time was approaching.

The full program is presented below.


#!/usr/bin/python

import datetime, gtk, string, pango

class BigChar():
    """ Create a Gtk window for a single giant textview that accepts all keyboard input. """
    def on_key_press(self, widget, data=None):
        """ Intercept all keypress events and show ascii
            characters. This requires the CAPS_LOCK to be off.  We
            don't intercept CAPS NUM or SCROLL lock, probably
            should."""
        # Start out by setting the current time
        self.set_time()
        ascii_value = data.keyval
        # Print the keycode received
        print ascii_value
        changedText = False
        # Lowercase alphabet should be shown as uppercase chars.
        if (ascii_value >= 97 and ascii_value <= 122):
            self.textBuffer.set_text(string.ascii_uppercase[ascii_value-97] + " "
                                     + string.ascii_lowercase[ascii_value-97])
            changedText = True
        # Uppercase alphabet should be shown as uppercase chars.
        if (ascii_value >= 65 and ascii_value <= 90):
            self.textBuffer.set_text(string.ascii_uppercase[ascii_value-65] + " "
                                     + string.ascii_lowercase[ascii_value-65])
            changedText = True
        # Numbers
        if (ascii_value >= 48 and ascii_value <= 57):
            self.textBuffer.set_text("%d" % (ascii_value - 48))
            changedText = True
        if (ascii_value >= 65456 and ascii_value <= 65466):
            self.textBuffer.set_text("%d" % (ascii_value - 65456))
            changedText = True
        if (ascii_value == 65450):
            self.textBuffer.set_text("*")
            changedText = True
        if (changedText):
            start = self.textBuffer.get_start_iter()
            end = self.textBuffer.get_end_iter()
            self.textBuffer.apply_tag_by_name("real_big", start, end)


    def realize_handler(self, widget):
        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
        color = gtk.gdk.Color()
        cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
        widget.window.set_cursor(cursor)

    def set_time(self):
        """Set the progress indicator to the current time.  The idea
        is to show time in a horizontal access with the morning being
        near the left edge and night being near the right edge."""
        current_time = datetime.datetime.now()
        # Total hours past since 6am
        # (Assume Dev wakes up at 6am)
        minutes_past = (current_time.hour - 6) * 60.0 + current_time.minute
        # Minutes are capped at 8am, which is when Dev goes to
        # bed. Expressed as minutes after 6am
        day_end = ((20 - 6) * 60.0)
        if (minutes_past < day_end):
            fraction = minutes_past / day_end
        else:
            fraction = 1.0
        self.progress.set_fraction(fraction)

    def __init__(self):
        """ Create a window with a single giant text view. Disables all chrome.
        """
        # Foreground and background color are read from here.
        background_color = "black"
        foreground_color = "#1133ff"

        self.w = gtk.Window(gtk.WINDOW_TOPLEVEL)
        # No border
        self.w.set_border_width(0)
        # Take over the entire screen
        self.w.fullscreen()

        # Connect the callback on_key_press to the signal key_press.
        self.w.connect("key_press_event", self.on_key_press)
        # self.w.connect("realize", self.realize_handler)
        # Make the widget aware of the signal to catch.
        self.w.set_events(gtk.gdk.KEY_PRESS_MASK)

        # Add a text view to show the key pressed
        textView = gtk.TextView()
        # Disable a cursor in the text view.
        textView.set_editable(False)
        textView.set_can_focus(False)
        # Show the single character in the middle
        textView.set_justification(gtk.JUSTIFY_CENTER)
        # This is the place we will write the character to
        self.textBuffer = textView.get_buffer()
        # Make the text view huge and bold
        fontdesc = pango.FontDescription("monospace bold 400")
        textView.modify_font(fontdesc)

        # Creates a tag that is applied to the text every time
        tag = self.textBuffer.create_tag(
            "real_big", background=background_color, foreground=foreground_color)
        # The progress bar shows the current proportion of awake-time for a child.
        self.progress = gtk.ProgressBar()
        self.set_time()

        
        # Make the text view take the entire window
        vbox = gtk.VBox(homogeneous=False, spacing=0)
        color = gtk.gdk.color_parse(background_color)
        self.progress.modify_bg(gtk.STATE_NORMAL, color)
        self.progress.modify_fg(gtk.STATE_NORMAL, color)
        textView.modify_base(gtk.STATE_NORMAL, color)

        vbox.pack_start(textView, expand=True, fill=False)
        vbox.pack_start(self.progress, expand=True, fill=True)

        self.w.modify_bg(gtk.STATE_NORMAL, color)
        self.w.add(vbox)

    def show(self):
        """ Show the window"""
        self.w.show_all()
        # gdkWindow = self.textView.get_window(gtk.TEXT_WINDOW_WIDGET)
        # display = self.textView.get_display()
        # cursor = gtk.gdk.Cursor(display, gtk.gdk.BLANK_CURSOR)
        # gdkWindow.set_cursor(cursor)


if __name__ == '__main__':
    # Create a bigchar window, and show it.
    bigchar = BigChar()
    bigchar.show()
    gtk.main()