Updates from October, 2016 Toggle Comment Threads | Keyboard Shortcuts

  • loctv 8:48 pm on October 19, 2016 Permalink | Reply
    Tags: ,   

    Mini game: Memory Puzzle 

    This is a really simple game, but it’s hard to win in short amount of time. Your task is to find all of the pairs of icons that look the same. There are totally (10*7)/2 pairs, this means the board’s width is 10 and height is 7.

    Let’s get started.
    First, we need to import some necessary modules.

    import pygame, random, sys
    from pygame.locals import *
    

    and declare all instances that we are going to use later.

    FPS = 30 # frame per second
    WINDOW_WIDTH = 640 # size of the window's width in pixel
    WINDOW_HEIGHT = 480 # size of the window's height in pixel
    REVEAL_SPEED = 8 # speed boxes' sliding reveal and cover
    BOX_SIZE = 40 # size of box width and height in pixel
    GAP_SIZE = 10 # space gap between boxes in pixel
    BOARD_WIDTH = 10 # the number of column icons
    BOARD_HEIGTH = 7 # the number of row icons
    X_MARGIN = int( (WINDOW_WIDTH - (BOARD_WIDTH*(BOX_SIZE+GAP_SIZE))) / 2)
    Y_MARGIN = int( (WINDOW_HEIGHT - (BOARD_HEIGTH*(BOX_SIZE+GAP_SIZE))) / 2)
    
    #            R    G    B
    GRAY     = (100, 100, 100)
    NAVYBLUE = ( 60, 60 , 100)
    WHITE    = (255, 255, 255)
    RED      = (255, 0  , 0)
    GREEN    = ( 0 , 255, 0)
    BLUE     = ( 0 , 0  , 255)
    YELLOW   = (255, 255, 0)
    ORANGE   = (255, 128, 0)
    PURPLE   = (255, 0  , 255)
    CYAN     = ( 0 , 255, 255)
    
    BACKGROUND_COLOR = NAVYBLUE
    BOX_COLOR = WHITE
    HIGHLIGHT_COLOR = BLUE
    LIGHT_BACKGROUND_COLOR = GRAY
    
    DONUT = 'donut'
    SQUARE = 'square'
    DIAMOND = 'diamond'
    LINES = 'lines'
    OVAL = 'oval'
    
    ALL_COLORS = [RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN]
    ALL_SHAPES = [DONUT, SQUARE, DIAMOND, LINES, OVAL]
    CLOCK, DISPLAY_SURFACE = None, None
    

    We use instances instead of ‘magic numbers’. Magic number is a number in your code, for example, you create window game in pygame by using pygame.display.set_mode method:

    window_surface = pygame.display.set_mode((400, 400))
    

    This code create a Surface object, a special Surface to be exact, all things in your game will be displayed by this Surface. 400 is width and height of this Surface, but using those numbers make it hard to understand and if you want to change the window’s width and height you must find this exact line of code. These numbers are called ‘magic numbers’. So the appropriate and more effective way to do this is using instances.

    WINDOW_WIDTH = 400
    WINDOW_HEIGHT = 400
    window_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    

    There’re totally 7 different colors and 5 shapes.

    Next the main function, this function include all game logic, graphics, etc.

    def main():
        global CLOCK, DISPLAY_SURFACE
        pygame.init() # initialize pygame
        CLOCK = pygame.time.Clock()
        DISPLAY_SURFACE = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32)
    
        mousex = 0
        mousey = 0
        pygame.display.set_caption('Memory Game') # set window's title
    
        main_board = get_randomized_board()  # create the board, random placed items
        revealed_boxes = generate_revealed_boxes_data(False) # there is no box revealed yet
        first_selection = None # store the x,y of the first click
    
        DISPLAY_SURFACE.fill(BACKGROUND_COLOR) # set background color
        start_game_animation(main_board) # start the game, show all items
    
        while True: # game loop
            mouse_clicked = False
            DISPLAY_SURFACE.fill(BACKGROUND_COLOR)
            draw_board(main_board, revealed_boxes)
    
            for event in pygame.event.get(): # check event
                if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEMOTION: # mouse hover event
                    mousex, mousey = event.pos
                elif event.type == MOUSEBUTTONUP: # mouse click event
                    mousex, mousey = event.pos
                    mouse_clicked = True
    
            box_x, box_y = get_box_at_pixel(mousex, mousey) # convert pixel coordinates to board coordinates
            if box_x != None and box_y != None:
                # the mouse is currently over a box
                if not revealed_boxes[box_x][box_y]: # if the box has not been revealed yet, highlight it
                    draw_highlight_box(box_x, box_y)
                if not revealed_boxes[box_x][box_y] and mouse_clicked: # click on an item
                    reveal_boxes_animation(main_board, [(box_x, box_y)]) # reveal that item
                    revealed_boxes[box_x][box_y] = True # temporarily mark this item revealed
    
                    if first_selection == None: # if this is the first box selected
                        first_selection = (box_x, box_y) # save it
                    else: # otherwise check if two revealed boxes are the sae
                        # get shape and color of two boxes
                        icon1_shape, icon1_color = get_shape_and_color(main_board, first_selection[0], first_selection[1])
                        icon2_shape, icon2_color = get_shape_and_color(main_board, box_x, box_y)
    
                        if icon1_shape != icon2_shape or icon1_color != icon2_color: # they are not the same
                            pygame.time.wait(1000) # wait 1 second
                            cover_boxes_animation(main_board, [(first_selection[0], first_selection[1]), (box_x, box_y)]) # then cover them
                            # remark them as they have not been revealed yet
                            revealed_boxes[first_selection[0]][first_selection[1]] = False
                            revealed_boxes[box_x][box_y] = False
                        # if they are the same, they remain revealed
                        elif has_won(revealed_boxes): # check for the win
                            game_won_animation(main_board) # start animation (just change the background color)
                            pygame.time.wait(2000) # then wait 2 seconds
    
                            main_board = get_randomized_board() # create new board
                            revealed_boxes = generate_revealed_boxes_data(False) # cover all the items
    
                            draw_board(main_board, revealed_boxes) # draw the board
                            pygame.display.update() # update game screen
                            pygame.time.wait(1000) # then wait 1 second
                            start_game_animation(main_board) # then start the game again
                        first_selection = None # after two item selected, reset this variable to None so that the next click will be the first item
    
            pygame.display.update() # final update each frame
            CLOCK.tick(FPS) # set frame per second
    
    

    Don’t panic, okey :> It’ll be crystal clear after I explain each line of code.
    First you use global keyword to access two global instances CLOCK and DISPLAY_SURFACE. Then you inititialize the game using pygame.init() method. Next, you create the game window, mousex and mousey to save the location of the mouse when player hover or click on a box, set window’s title, create game board. revealed_box is a 2d array, returned from function generate_revealed_boxes_data, with False as a argument. This means all of the values of revealed_boxes are False, just like there is no box that has been revealed yet. If first_selection is None, this is means the next time player click on a box, that box will be the first box in a pair. Fill the window with BACKGROUND_COLOR and start the game.

    The code in the game loop is already explained very clearly by comments, so check it out and free to ask me here if you’re stuck.

    Finally, I’m about to explain all the functions that are used in main function. First, generate_revealed_box_data, this function returns a 2-d array, with all values of each row equal val.
    The get_randomized_board function returns the game board, this function is like the main function, well commented so no need to explain more.
    The get_box_at_plixel converts game (or pixel) coordinates into board coordinates. What’s this mean? This means if you click or hover on a box on the screen, this function will convert that pixel value, for example (400, 200) to board coordinates , (boxx, boxy). This function is the reverse of lefttop_box, which converts game board coordinates to pixel coordinates.
    Then the draw_icon method, which takes 4 arguments, the game board, color, and boxx, boxxy. Convert boxx, boxy to pixel coordinates, then draw the icon (one of the five icons).
    Function draw_boxes_cover, draw icons, and if coverage > 0, draw the coverage over the items, this creates the animation effect.
    The reveal_boxes_animation and cover_boxes_animation makes use of draw_boxes_cover, with different coverage values.
    draw_board function draw the game board, if the box has been revealed, just draw the icon, if it’s not, draw the box cover it.
    start_game_animation, randomly reveal 8 boxes at a time. After quickly revealing those boxes will be covered it. This makes the game a little easier.
    The game_won_animation function makes the background change to LIGHT_BACKGROUND_COLOR and back to BACKGROUND_COLOR multiple times.
    has_won checks if all the values of revealed_box array are equal True.
    Here’s the code of all functions that’re explained above.

    def generate_revealed_boxes_data(val):
        # create a 2-D array of True or False values
        revealed_boxes = []
        for i in xrange(BOARD_WIDTH):
            revealed_boxes.append([val]*BOARD_HEIGTH)
        return revealed_boxes
    
    
    def get_randomized_board():
        # create game board
        # first we create an array saving all the possible combinations of shapes and colors
        icons = []
        for color in ALL_COLORS:
            for shape in ALL_SHAPES:
                icons.append((shape, color))
        random.shuffle(icons)
        num_icons_used = int(BOARD_WIDTH*BOARD_HEIGTH/2) # then we divide it by 2 because we just need half of them
        icons = icons[:num_icons_used]*2 # then we create a copy of current items, so we have even number of pairs of item
        random.shuffle(icons) # shuffle it
    
        # and convert into 2-D dimensional array
        board = []
        for x in xrange(BOARD_WIDTH):
            column = []
            for y in xrange(BOARD_HEIGTH):
                column.append(icons[0])
                del icons[0]
            board.append(column)
        return board
    
    def split_into_groups(group_size, list):
        # split a list into group
        result = []
        for i in xrange(0, len(list), group_size):
            result.append(list[i:i+group_size])
        return result
    
    def lefttop_box(boxx, boxy):
        # convert board coordinates to pixel coordinates
        left = boxx*(BOX_SIZE+GAP_SIZE) + X_MARGIN
        top = boxy*(BOX_SIZE+GAP_SIZE) + Y_MARGIN
        return (left, top)
    
    
    def get_box_at_pixel(x, y):
        # get the box on board where player click on
        for boxx in xrange(BOARD_WIDTH):
            for boxy in xrange(BOARD_HEIGTH):
                left, top = lefttop_box(boxx, boxy)
                box_rect = pygame.Rect(left, top, BOX_SIZE, BOX_SIZE)
                if box_rect.collidepoint(x, y):
                    return (boxx, boxy)
        return (None, None)
    
    
    def draw_icon(shape, color, boxx, boxy):
        # draw icon
        # these two variables are used to centralize the icon
        quarter = int(BOX_SIZE * 0.25)
        half = int(BOX_SIZE * 0.5)
    
        left, top = lefttop_box(boxx, boxy) # convert board coordinates to pixel coordinates
        if shape == DONUT:
            pygame.draw.circle(DISPLAY_SURFACE, color, (left+half, top+half), half-5)
            pygame.draw.circle(DISPLAY_SURFACE, BACKGROUND_COLOR, (left+half, top+half), quarter-5)
        elif shape == SQUARE:
            pygame.draw.rect(DISPLAY_SURFACE, color, (left+quarter, top+quarter, BOX_SIZE-half, BOX_SIZE-half))
        elif shape == DIAMOND:
            pygame.draw.polygon(DISPLAY_SURFACE, color, ((left+half, top), (left+BOX_SIZE-1, top+half), (left+half, top+BOX_SIZE-1),(left, top+half)))
        elif shape == LINES:
            for i in xrange(0, BOX_SIZE, 4):
                pygame.draw.line(DISPLAY_SURFACE, color, (left, top+i), (left+i, top))
                pygame.draw.line(DISPLAY_SURFACE, color, (left+i, top+BOX_SIZE-1), (left+BOX_SIZE-1, top+i))
        elif shape == OVAL:
            pygame.draw.ellipse(DISPLAY_SURFACE, color, (left, top + quarter, BOX_SIZE, half))
    
    
    def get_shape_and_color(board, boxx, boxy):
        # get shape and color of box with given coordinate
        return board[boxx][boxy][0], board[boxx][boxy][1]
    
    
    def draw_boxes_cover(board, boxes, coverage):
        # draw boxes with coverage
        # this create animation revealing and covering effect
        for box in boxes:
            left, top = lefttop_box(box[0], box[1])
            pygame.draw.rect(DISPLAY_SURFACE, BACKGROUND_COLOR, (left, top, BOX_SIZE, BOX_SIZE))
            shape, color = get_shape_and_color(board, box[0], box[1])
            # first we draw the icon
            draw_icon(shape, color, box[0], box[1])
            # then draw coverage on top of it
            if coverage > 0:
                pygame.draw.rect(DISPLAY_SURFACE, BOX_COLOR, (left, top, coverage, BOX_SIZE))
        pygame.display.update() # update the window
        CLOCK.tick(FPS) # slow down the animation
    
    
    def reveal_boxes_animation(board, boxes_to_reveal):
        # the box width will decrease each iteration until they reach 0
        for coverage in xrange(BOX_SIZE, -(REVEAL_SPEED)-1, -REVEAL_SPEED):
            draw_boxes_cover(board, boxes_to_reveal, coverage)
    
    
    def cover_boxes_animation(board, boxes_to_cover):
        # then they increase until they reach BOX_SIZE again
        for coverage in xrange(0, BOX_SIZE+REVEAL_SPEED, REVEAL_SPEED):
            draw_boxes_cover(board, boxes_to_cover, coverage)
    
    
    def draw_board(board, revealed):
        # draw the game board
        for boxx in xrange(BOARD_WIDTH):
            for boxy in xrange(BOARD_HEIGTH):
                left, top = lefttop_box(boxx, boxy) # convert board coordinates to game coordinates to draw
                if not revealed[boxx][boxy]: # if the box has not been revealed yet
                    # draw a box to cover it
                    pygame.draw.rect(DISPLAY_SURFACE, BOX_COLOR, (left, top, BOX_SIZE, BOX_SIZE))
                else: # otherwise, draw the icon
                    shape, color = get_shape_and_color(board, boxx, boxy)
                    draw_icon(shape, color, boxx, boxy)
    
    
    def draw_highlight_box(boxx, boxy):
        # draw a blue rect when player hover a box
        left, top = lefttop_box(boxx, boxy)
        pygame.draw.rect(DISPLAY_SURFACE, HIGHLIGHT_COLOR, (left-5, top-5, BOX_SIZE+10, BOX_SIZE+10), 4)
    
    
    def start_game_animation(board):
        covered_boxes = generate_revealed_boxes_data(False)
        boxes = []
        for x in xrange(BOARD_WIDTH):
            for y in xrange(BOARD_HEIGTH):
                boxes.append((x,y))
        random.shuffle(boxes)
        box_groups = split_into_groups(8, boxes)
    
        draw_board(board, covered_boxes)
        for box_group in box_groups:
            reveal_boxes_animation(board, box_group)
            cover_boxes_animation(board, box_group)
    
    
    def game_won_animation(board):
        covered_boxes = generate_revealed_boxes_data(True)
        color1 = LIGHT_BACKGROUND_COLOR
        color2 = BACKGROUND_COLOR
    
        for i in xrange(13):
            color1, color2 = color2, color1
            DISPLAY_SURFACE.fill(color1)
            draw_board(board, covered_boxes)
            pygame.display.update()
            pygame.time.wait(300)
    
    
    def has_won(revealed_boxes):
        for i in revealed_boxes:
            if False in i:
                return False
        else:
            return True
    

    Game play:

    Donate (I’ll very appreciate your donation, it will help a lot): https://www.paypal.me/TruongLoc

     
  • loctv 4:21 pm on September 23, 2016 Permalink | Reply
    Tags: ,   

    Handwritten Digit Recognition Using Neural Network 

    The training dataset is MNIST dataset, with 60k training images and 10k testing images. But with a little ‘twisted’, it becomes 180k training images. You can Google ‘MNIST dataset’ to know more.

    With 10k testing images, accuracy is more than 95%. But I don’t want to stop at that, I want to create a program that you can draw a digit, and then it will say which number that you’ve just drawn.

    Here’s the demo

    The program works quite well with numbers: 0,1,2,3,4,5,6,7,8 , but it can hardly recognize the number 9, because of several reasons. First reason is inside the MNIST dataset, the number 9 is the most … ugly number, it’s so small, and the second reason is the thickness of the number that we draw. I’ve used an algorithm that I came up with, to track a number in side an image. And maybe the algorithm itself is also the reason why the program didn’t work well as I expected.

    The source code as well as other related information and materials will be uploaded to Github at the end of this semester  (around at the end of December) .

    Update source code:

    https://github.com/MrNocTV/Handwritten-Digit-Recognition

     

     
  • loctv 1:42 pm on September 13, 2016 Permalink | Reply
    Tags: ,   

    Project: Footprint Editor 

    In this project, I’m going to make a text editor which involves the following features:
    + New
    + Open
    + Save / Save as
    + Copy/Cut
    + Paste
    + Change theme
    + Line indicator
    + And several more

    Day 1: Create text editor windows : create menu bar, shortcut_bar, line_text_bar, and text_field 
    Suppose we have some images to be used as the icon of each menu item:
    +new_file.gif
    +open_file.gif
    +save.gif
    +cut.gif
    +copy.gif
    +undo.gif
    +paste.gif
    +redo.gif
    These all images are place in the same for the with source code

    from tkinter import *
    PROGRAM_NAME = 'Footprint Editor'
    root = Tk() # root windows
    root.title(PROGRAM_NAME) # set window title
    root.geometry('350x350') # set the size of the window 350x350
    
    # create icon to be used for menu item
    new_file_icon = PhotoImage(file='new_file.gif')
    open_file_icon = PhotoImage(file='open_file.gif')
    save_file_icon = PhotoImage(file='save.gif')
    cut_icon = PhotoImage(file='cut.gif')
    copy_icon = PhotoImage(file='copy.gif')
    undo_icon = PhotoImage(file='undo.gif')
    paste_icon = PhotoImage(file='paste.gif')
    redo_icon = PhotoImage(file='redo.gif')
    
    # create the menu bar
    menu_bar = Menu(root)
    
    # create file_menu
    file_menu = Menu(menu_bar, tearoff=0) # tearoff is optional
    file_menu.add_command(label='New', accelerator='Ctrl+N', image=new_file_icon,
                            compound='left')
    file_menu.add_command(label='Open', accelerator='Ctrl+O', image=open_file_icon,
                            compound='left')
    file_menu.add_command(label='Save', accelerator='Ctrl+S', image=save_file_icon,
                            compound='left')
    file_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S',                                image=save_file_icon, compound='left')
    file_menu.add_seperator()
    file_menu.add_command(label='Exit', accelerator='Alt+F4', compound='left')
    menu_bar.add_cascade(label='File', menu=file_menu) # add file_menu to menu_bar
    
    # create edit_menu
    edit_menu = Menu(menu_bar, tearoff=0)
    edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', image=undo_icon,
                           compound='left')
    edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', image=redo_icon,
                           compound='left')
    edit_menu.add_seperator()
    edit_menu.add_command(label='Cut', accelerator='Ctrl+X', image=cut_icon,
                           compound='left')
    edit_menu.add_command(label='Copy', accelerator='Ctrl+C', image=copy_icon,
                           compound='left')
    edit_menu.add_command(label='Paste', accelerator='Ctrl+V', image=paste_icon,
                           compound='left')
    edit_menu.add_seperator()
    edit_menu.add_command(label='Find', accelerator='Ctrl+F', compound='left')
    edit_menu.add_seperator()
    edit_menu.add_command(label='Select All', accelerator='Ctrl+A', compound='left')
    menu_bar.add_cascade(label='Edit', menu=edit_menu) # add edit_menu to menu_bar
    
    # creat view_menu
    view_menu = Menu(menu_bar, tearoff=0)
    menu_bar.add_cascade(label='View', menu=view_menu)
    
    #create about_menu
    about_menu = Menu(menu_bar, tearoff=0)
    about_menu.add_command(label='About', compound='left')
    about_menu.add_command(label='Help', compound='left')
    menu_bar.add_cascade(label='About', menu=about_menu)
    
    root.config(menu=menu_bar) # set menu_bar as window's menu bar
    
    # add the shortcut_bar
    shortcut_bar = Frame(root, height=25, bg='light sea green')
    shortcut_bar.pack(expand='no', fill='x')
    
    # add the line number text field
    line_number_bar = Text(root, width=4, takefocus=0, border=0,
                          bg='khaki', state='disabled', wrap='none')
    line_number_bar.pack(side='left', fill='y')
    
    # add the content text field
    content_text = Text(root, wrap='word')
    content_text.pack(expand='yes', fill='both')
    # add the scrollbar next to content text field
    scroll_bar = Scrollbar(content_text)
    content_text.configure(yscrollcommand=scroll_bar.set)
    scroll_bar.configure(command=content_text.yview)
    scroll_bar.pack(side='right', fill='y')
    
    root.mainloop() # start the event loop
    

    The program so far (on Mac):
    screen-shot-2016-09-13-at-8-38-59-pm
    screen-shot-2016-09-13-at-8-40-13-pm
    screen-shot-2016-09-13-at-8-40-25-pm
    Day 2: Implement the view_menu, copy, cut, past, select_all,  features.
    Implement the view_menu :
    We use three types of menu item in this menu: Checkbutton, Radiobutton and Cascade menu.
    – Every checkbutton has a variable, it could be IntVar, BooleanVar, … But I think IntVar is the most common in use, if the button is checked, IntVar set to 1, otherwise, set to 0.
    – With radiobutton, these buttons have to be in a group, usually has a StringVar, whenever user click on a radiobutton, this StringVar set it value to radiobutton’s label.
    – Casecade menu is a type of menu we already know, it allows you to create menu that when you hover the mouse on it, it shows a new sub menu.
    Now, I’ll copy the code above and we will start day 2.

    from tkinter import *
    PROGRAM_NAME = 'Footprint Editor'
    root = Tk() # root windows
    root.title(PROGRAM_NAME) # set window title
    root.geometry('350x350') # set the size of the window 350x350
    # you just need to know that all features like cut, copy, paste, redo, undo
    # already there in Text, you don't have to code the logic
    # you just need to generate it when needed
    def cut():
         content_text.event_generate('<<Cut>>')
         return 'break' # job's done, no more propagation
    
    def copy():
         content_text.event_generate('<<Copy>>')
         return 'break' # same as above
    
    def paste():
         content_text.event_generate('<<Paste>>')
         return 'break'
    
    def undo():
         content_text.event_generate('<<Undo>>')
         return 'break'
    
    def redo(event=None):
         content_text.event_generate('<<Redo>>')
         return 'break'
    
    def select_all(event=None):
         content_text.tag_add('sel', 1.0, 'end') # SEL is built-in tag in tkinter
         return 'break' # job's done, no more propagation
    
    # create icon to be used for menu item
    new_file_icon = PhotoImage(file='new_file.gif')
    open_file_icon = PhotoImage(file='open_file.gif')
    save_file_icon = PhotoImage(file='save.gif')
    cut_icon = PhotoImage(file='cut.gif')
    copy_icon = PhotoImage(file='copy.gif')
    undo_icon = PhotoImage(file='undo.gif')
    paste_icon = PhotoImage(file='paste.gif')
    redo_icon = PhotoImage(file='redo.gif')
    
    # create the menu bar
    menu_bar = Menu(root)
    
    # create file_menu
    file_menu = Menu(menu_bar, tearoff=0) # tearoff is optional
    file_menu.add_command(label='New', accelerator='Ctrl+N', image=new_file_icon,
                            compound='left')
    file_menu.add_command(label='Open', accelerator='Ctrl+O', image=open_file_icon,
                            compound='left')
    file_menu.add_command(label='Save', accelerator='Ctrl+S', image=save_file_icon,
                            compound='left')
    file_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S',                                image=save_file_icon, compound='left')
    file_menu.add_seperator()
    file_menu.add_command(label='Exit', accelerator='Alt+F4', compound='left')
    menu_bar.add_cascade(label='File', menu=file_menu) # add file_menu to menu_bar
    
    # create edit_menu
    edit_menu = Menu(menu_bar, tearoff=0)
    edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', image=undo_icon,
                           compound='left', command=undo)
    edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', image=redo_icon,
                           compound='left', command=redo)
    edit_menu.add_seperator()
    edit_menu.add_command(label='Cut', accelerator='Ctrl+X', image=cut_icon,
                           compound='left', command=cut)
    edit_menu.add_command(label='Copy', accelerator='Ctrl+C', image=copy_icon,
                           compound='left', command=copy)
    edit_menu.add_command(label='Paste', accelerator='Ctrl+V', image=paste_icon,
                           compound='left', command=paste)
    edit_menu.add_seperator()
    edit_menu.add_command(label='Find', accelerator='Ctrl+F', compound='left')
    edit_menu.add_seperator()
    edit_menu.add_command(label='Select All', accelerator='Ctrl+A', compound='left'
                         , command=select_all)
    menu_bar.add_cascade(label='Edit', menu=edit_menu) # add edit_menu to menu_bar
    
    # creat view_menu
    view_menu = Menu(menu_bar, tearoff=0)
    show_line_number = IntVar()
    show_line_number.set(1) # this check button is selected by default
    view_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)
    show_cursor_info = IntVar()
    show_cursor_info.set(1) # this check button is selected by default
    view_menu.add_checkbutton(label='Show Cursor Info at Bottom', variable=show_cursor_info)
    highlight_line = IntVar()
    view_menu.add_checkbuton(label='Highlight Current Line', onvalue=1, offvalue=0, variable=highlight_line)
    themes_menu = Menu(menu_bar) # this is cascade menu as a menu item of view_menu
    """
    color scheme is defined with dictionary elements like:
    theme_name: fg.bg
    fg = foreground color
    bg = background color
    """
    color_schemes = {
    'Default' : '#000000.#FFFFFF',
    'Greygarious' : '#83406A.#D1D4D1',
    'Aquamarine' : '5B8340.#D1E7E0',
    'Bold Beige' : '#4B4620.#FFF0E1',
    'Cobalt Blue' : '#ffffBB.#3333aa',
    'Olive Green' : '#D1E7E0.#5B8340',
    'Night Mode' : '#FFFFFF.#000000'
    }
    theme_color = StringVar()
    theme_color.set('Default') # set 'Default' as default scheme
    for k in sorted(color_schemes):
         themes_menu.add_radiobutton(label=k, variable=theme_color)
    view_menu.add_cascade(label='Themes', menu=themes_menu)
    menu_bar.add_cascade(label='View', menu=view_menu)
    
    #create about_menu
    about_menu = Menu(menu_bar, tearoff=0)
    about_menu.add_command(label='About', compound='left')
    about_menu.add_command(label='Help', compound='left')
    menu_bar.add_cascade(label='About', menu=about_menu)
    
    root.config(menu=menu_bar) # set menu_bar as window's menu bar
    
    # add the shortcut_bar
    shortcut_bar = Frame(root, height=25, bg='light sea green')
    shortcut_bar.pack(expand='no', fill='x')
    
    # add the line number text field
    line_number_bar = Text(root, width=4, takefocus=0, border=0,
                          bg='khaki', state='disabled', wrap='none')
    line_number_bar.pack(side='left', fill='y')
    
    # add the content text field
    content_text = Text(root, wrap='word', undo=1) # enable undo feature
    content_text.pack(expand='yes', fill='both')
    # add the scrollbar next to content text field
    scroll_bar = Scrollbar(content_text)
    content_text.configure(yscrollcommand=scroll_bar.set)
    scroll_bar.configure(command=content_text.yview)
    scroll_bar.pack(side='right', fill='y')
    
    # by default, Control-y is binded to paste operation, so we
    # have to bind Control-y / Control-Y as redo operation
    content_text.bind('<Control-y>', redo)
    content_text.bind('<Control-Y>', redo)
    
    #bind Control-a / Control-A to select_all operation
    content_text.bind('<Control-a>', select_all)
    content_text.bind('<Control-A>', select_all)
    
    root.mainloop() # start the event loop
    

    Day 3: Implementing the Find Text, Open, Save, Save As, New features:

    from tkinter import *
    import tkinter.filedialog
    import tkinter.messagebox as tmb
    import os
    
    PROGRAM_NAME = "Footprint Editor"
    file_name = None
    
    root = Tk()
    root.geometry('350x350')
    root.title(PROGRAM_NAME)
    
    def cut():
        content_text.event_generate('<<Cut>>')
        return 'break' # job's done, no more propagation
    
    def copy():
        content_text.event_generate('<<Copy>>')
        return 'break' # job's done, no more propagation
    
    def paste():
        content_text.event_generate('<<Paste>>')
        return 'break' # jobs done, no more propagation
    
    def undo():
        content_text.event_generate('<<Undo>>')
        return 'break' # jobs done, no more propagation
    
    def redo(event=None):
        content_text.event_generate('<<Redo>>')
        return 'break' # jobs done, no more propagation
    
    def select_all(event=None):
        content_text.tag_add('sel', 1.0, 'end')
        return 'break'
    
    def find_text(event=None):
        search_toplevel = Toplevel(root)    # create a pop up window
        search_toplevel.title('Find Text')   # name the window 'Find Text'
        search_toplevel.transient(root) # make the search window appear on top of root
        search_toplevel.resizable(False, False)  # disable resize
        Label(search_toplevel, text='Find All:').grid(row=0, column=0, sticky='e')
        search_entry_widget = Entry(search_toplevel, width=25)
        search_entry_widget.grid(row=0, column = 1, sticky='we')
        search_entry_widget.focus_set() # set focus to this entry
        ignore_case_value = IntVar() # keep track of status of ignore_case
        Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(row=1, column=1, sticky='e')
        b = Button(search_toplevel, text='Find All', command=lambda: search_output(search_entry_widget.get(),
                                        ignore_case_value.get(), content_text, search_toplevel, search_entry_widget))
        b.grid(row=0, column=2, sticky='w'+'e')
        def close_search_window():
            content_text.tag_remove('match','1.0', END) # remove all the tags before closing the search window
            search_toplevel.destroy()  # explicitly close the search window
        search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window) # override default close operation of search windows
        return 'break'
    
    def search_output(pattern, if_ignore_case, content_text, search_toplevel, search_box):
        content_text.tag_remove('match', '1.0', END) # remove tag results of previous search
        matches_found = 0
        if pattern:  # if pattern is not empty
            start_pos = '1.0'
            while True:
                start_pos = content_text.search(pattern, start_pos, nocase=if_ignore_case, stopindex=END)
                if not start_pos: # if start_pos == None
                    break
                end_pos = '{}+{}c'.format(start_pos, len(pattern)) # endpos = startpos + length of pattern
                content_text.tag_add('match', start_pos, end_pos) # add tag into content_text
                matches_found += 1
                start_pos = end_pos        # update start_pos
            content_text.tag_config('match', foreground='red', background='yellow') # change foreground & background color of match tag
        search_box.focus_set()   # set focus on search_box_entry again
        search_toplevel.title('{} matches found'.format(matches_found))  # print out result
    
    def open_file(event=None):
        input_file_name = tkinter.filedialog.askopenfilename(defaultextension='.txt',
                                                         filetypes=[("All Files", "*"), ("Text Documents", "*.txt")])
        if input_file_name: # if input_file_name is not None
            global  file_name
            file_name = input_file_name # keep track of the file_name
            root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME)) # just displaying the filename - PROGRAM_NAME
            content_text.delete(1.0, END) # remove the current content before inserting the content of new file
            with open(input_file_name) as _file:
                content_text.insert(1.0, _file.read()) # get text from file and insert into content_text
            return 'break'
    
    def save(event=None):
        global file_name
        if file_name:
            write_to_file(file_name)
        else:
            save_as()
        return 'break'
    
    def save_as(event=None):
        input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension='.txt',
                            filetypes=[("All Files", ".*"), ("Text Documents", "*.txt")])
        if input_file_name: # check if input_file_name is not None
            global file_name
            file_name = input_file_name # keep track of the file_name
            write_to_file(file_name)
            root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME)) # change window title
        return 'break'
    
    def write_to_file(file_name):
        try:
            content = content_text.get(1.0, END) # get text inside content_text
            with open(file_name, 'w') as _file:
                _file.write(content) # write text inside content_text to file
        except IOError:
            pass
    
    def new_file(event=None):
        root.title('{} - {}'.format("Untitled", PROGRAM_NAME)) # set window title
        global file_name
        file_name = None # set file_name to None
        content_text.delete(1.0, END) # remove the content in content_text
        return 'break' # job's done, no more propagation
    
    def display_about_messagebox(event=None):
        tmb.showinfo("About", "{}{}".format(PROGRAM_NAME, "\nTkinter GUI Application\n "
                                                          "Development Blueprints"))
        return 'break'
    
    def display_help_messagebox(event=None):
        tmb.showinfo("Help", "Help Book: \nTkinter GUI Application\n Development Blueprints", icon='question')
        return 'break'
    
    def exit_editor(event=None):
        if tmb.askokcancel('Quit?', 'Really Quit?'): # using messagebox to ask user do they really want to quit
            root.destroy()
        return 'break'
    
    # getting icons ready
    new_file_icon = PhotoImage(file='new_file.gif')
    open_file_icon = PhotoImage(file='open_file.gif')
    save_file_icon = PhotoImage(file='save.gif')
    cut_icon = PhotoImage(file='cut.gif')
    copy_icon = PhotoImage(file='copy.gif')
    undo_icon = PhotoImage(file='undo.gif')
    paste_icon = PhotoImage(file='paste.gif')
    redo_icon = PhotoImage(file='redo.gif')
    
    #create the menu bar
    menu_bar = Menu(root)
    
    #create file menu
    file_menu = Menu(menu_bar, tearoff=0)
    file_menu.add_command(label='New', accelerator='Ctrl+N', image=new_file_icon, compound='left', command=new_file)
    file_menu.add_command(label='Open', accelerator='Ctrl+O', image=open_file_icon, compound='left', command=open_file)
    file_menu.add_command(label='Save', accelerator='Ctrl+S', image=save_file_icon, compound='left', command=save)
    file_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S', compound='left', command=save_as)
    file_menu.add_separator()
    file_menu.add_command(label='Exit', accelerator='Alt+F4', compound='left', command=exit_editor)
    menu_bar.add_cascade(label='File', menu=file_menu) # add to menu_bar
    
    # create edit menu
    edit_menu = Menu(menu_bar, tearoff=1)
    edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', image=undo_icon, compound='left', command=undo)
    edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', image=redo_icon, compound='left', command=redo)
    edit_menu.add_separator()
    edit_menu.add_command(label='Cut', accelerator='Ctrl+X', image=cut_icon, compound='left', command=cut)
    edit_menu.add_command(label='Copy', accelerator='Ctrl+C', image=copy_icon, compound='left', command=copy)
    edit_menu.add_command(label='Paste', accelerator='Ctrl+V', image=paste_icon, compound='left', command=paste)
    edit_menu.add_separator()
    edit_menu.add_command(label='Find', accelerator='Ctrl+F', compound='left', command=find_text)
    edit_menu.add_separator()
    edit_menu.add_command(label='Select All', accelerator='Ctrl+A', compound='left', command=select_all)
    menu_bar.add_cascade(label='Edit', menu=edit_menu) # add to menu_bar
    
    # create view menu
    view_menu = Menu(menu_bar)
    show_line_no = IntVar()
    show_line_no.set(1)
    view_menu.add_checkbutton(label="Show Line Number", variable=show_line_no)
    show_cursor_info = IntVar()
    show_cursor_info.set(1)
    view_menu.add_checkbutton(label='Show Cursor Location at Bottom', variable=show_cursor_info)
    highlight_line = IntVar()
    view_menu.add_checkbutton(label='Highlight Current Line', onvalue=1, offvalue=0, variable=highlight_line)
    themes_menu = Menu(menu_bar, tearoff=0)
    view_menu.add_cascade(label='Themes', menu=themes_menu)
    menu_bar.add_cascade(label='View', menu=view_menu) # add to menu_bar
    """
    color scheme is defined with dictionary elements like theme_name: fg.bg
    """
    color_schemes = {
        'Default' : '#000000.#FFFFFF',
        'Greygarious': '#83406A.#D1D4D1',
        'Aquamarine': '#5B8340.#D1E7E0',
        'Bold Beige': '#4B4620.#FFF0E1',
        'Cobalt Blue': '#ffffBB.#3333aa',
        'Olive Green': '#D1E7E0.#5B8340',
        'Night Mode': '#FFFFFF.#000000',
    }
    theme_choice = StringVar()
    theme_choice.set('Default')
    for k in sorted(color_schemes):
        themes_menu.add_radiobutton(label=k, variable=theme_choice)
    
    # create about menu
    about_menu = Menu(menu_bar)
    about_menu.add_command(label='About', compound='left', command=display_about_messagebox)
    about_menu.add_command(label='Help', compound='left', command=display_help_messagebox)
    menu_bar.add_cascade(label='About', menu=about_menu)
    root.config(menu=menu_bar)
    
    # add the shorcut bar
    shortcut_bar = Frame(root, height=25, bg='light sea green')
    shortcut_bar.pack(expand='no', fill='x')
    
    # add line number text field
    line_number_bar = Text(root, width=4, pady=-3, takefocus=0, border=0,
                           bg='khaki', state='disabled', wrap='none')
    line_number_bar.pack(side='left', fill='y')
    
    # add the content text field
    content_text = Text(root, wrap='word', undo=1)
    content_text.pack(expand='yes', fill='both')
    # add the scroll bar next to content text field
    scroll_bar = Scrollbar(content_text)
    content_text.configure(yscrollcommand=scroll_bar.set) # ?
    scroll_bar.config(command=content_text.yview) # ?
    scroll_bar.pack(side='right', fill='y')
    
    # handling redo quirk
    # note: on mac, Control == Command
    content_text.bind('<Control-y>', redo)
    content_text.bind('<Control-Y>', redo)
    
    # bin select all as Control-A / Control-a to content_text
    content_text.bind('<Control-a>', select_all)
    content_text.bind('<Control-A>', select_all)
    
    # bin find all feature to Ctrl+f shortcut
    content_text.bind('<Control-f>', find_text)
    content_text.bind('<Control-F>', find_text)
    
    # bin open file feature to Ctrl+o shortcut
    content_text.bind('<Control-o>', open_file)
    content_text.bind('<Control-O>', open_file)
    
    # bin save and save_as feature to Ctrl+S and Shift+Ctrl+S shortcuts
    content_text.bind('<Control-s>', save)
    content_text.bind('<Control-S>', save)
    content_text.bind('<Shift-Control-s>', save_as)
    content_text.bind('<Shift-Control-S>', save_as)
    
    # bin new file feature to Ctrl+N shorcut
    content_text.bind('<Control-n>', new_file)
    content_text.bind('<Control-N>', new_file)
    
    content_text.bind('<KeyPress-F1>', display_help_messagebox)
    
    root.protocol('WM_DELETE_WINDOW', exit_editor) # override destroy handler
    root.mainloop()
    

    Day 4: Adding icons to toolbar, implement View menu functions, adding themes, popup menu.

    from tkinter import *
    import tkinter.filedialog
    import tkinter.messagebox as tmb
    import os
    
    PROGRAM_NAME = "Footprint Editor"
    file_name = None
    
    root = Tk()
    root.geometry('350x350')
    root.title(PROGRAM_NAME)
    
    def cut():
        content_text.event_generate('<<Cut>>')
        on_content_changed()
        return 'break'
    
    def copy():
        content_text.event_generate('<<Copy>>')
        return 'break' # job's done, no more propagation
    
    def paste():
        content_text.event_generate('<<Paste>>')
        on_content_changed()
        return 'break'
    
    def undo():
        content_text.event_generate('<<Undo>>')
        on_content_changed()
        return 'break'
    
    def redo(event=None):
        content_text.event_generate('<<Redo>>')
        on_content_changed()
        return 'break'
    
    def select_all(event=None):
        content_text.tag_add('sel', 1.0, 'end')
        return 'break'
    
    def find_text(event=None):
        search_toplevel = Toplevel(root)    # create a pop up window
        search_toplevel.title('Find Text')   # name the window 'Find Text'
        search_toplevel.transient(root) # make the search window appear on top of root
        search_toplevel.resizable(False, False)  # disable resize
        Label(search_toplevel, text='Find All:').grid(row=0, column=0, sticky='e')
        search_entry_widget = Entry(search_toplevel, width=25)
        search_entry_widget.grid(row=0, column = 1, sticky='we')
        search_entry_widget.focus_set() # set focus to this entry
        ignore_case_value = IntVar() # keep track of status of ignore_case
        Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(row=1, column=1, sticky='e')
        b = Button(search_toplevel, text='Find All', command=lambda: search_output(search_entry_widget.get(),
                                        ignore_case_value.get(), content_text, search_toplevel, search_entry_widget))
        b.grid(row=0, column=2, sticky='w'+'e')
        def close_search_window():
            content_text.tag_remove('match','1.0', END) # remove all the tags before closing the search window
            search_toplevel.destroy()  # explicitly close the search window
        search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window) # override default close operation of search windows
        return 'break'
    
    def search_output(pattern, if_ignore_case, content_text, search_toplevel, search_box):
        content_text.tag_remove('match', '1.0', END) # remove tag results of previous search
        matches_found = 0
        if pattern:  # if pattern is not empty
            start_pos = '1.0'
            while True:
                start_pos = content_text.search(pattern, start_pos, nocase=if_ignore_case, stopindex=END)
                if not start_pos: # if start_pos == None
                    break
                end_pos = '{}+{}c'.format(start_pos, len(pattern)) # endpos = startpos + length of pattern
                content_text.tag_add('match', start_pos, end_pos) # add tag into content_text
                matches_found += 1
                start_pos = end_pos        # update start_pos
            content_text.tag_config('match', foreground='red', background='yellow') # change foreground & background color of match tag
        search_box.focus_set()   # set focus on search_box_entry again
        search_toplevel.title('{} matches found'.format(matches_found))  # print out result
    
    def open_file(event=None):
        input_file_name = tkinter.filedialog.askopenfilename(defaultextension='.txt',
                                                         filetypes=[("All Files", "*"), ("Text Documents", "*.txt")])
        if input_file_name: # if input_file_name is not None
            global  file_name
            file_name = input_file_name # keep track of the file_name
            root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME)) # just displaying the filename - PROGRAM_NAME
            content_text.delete(1.0, END) # remove the current content before inserting the content of new file
            with open(input_file_name) as _file:
                content_text.insert(1.0, _file.read()) # get text from file and insert into content_text
            on_content_changed()
        return 'break'
    
    def save(event=None):
        global file_name
        if file_name:
            write_to_file(file_name)
        else:
            save_as()
        return 'break'
    
    def save_as(event=None):
        input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension='.txt',
                            filetypes=[("All Files", ".*"), ("Text Documents", "*.txt")])
        if input_file_name: # check if input_file_name is not None
            global file_name
            file_name = input_file_name # keep track of the file_name
            write_to_file(file_name)
            root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME)) # change window title
        return 'break'
    
    def write_to_file(file_name):
        try:
            content = content_text.get(1.0, END) # get text inside content_text
            with open(file_name, 'w') as _file:
                _file.write(content) # write text inside content_text to file
        except IOError:
            pass
    
    def new_file(event=None):
        root.title('{} - {}'.format("Untitled", PROGRAM_NAME)) # set window title
        global file_name
        file_name = None # set file_name to None
        content_text.delete(1.0, END) # remove the content in content_text
        on_content_changed()
        return 'break'
    
    def display_about_messagebox(event=None):
        tmb.showinfo("About", "{}{}".format(PROGRAM_NAME, "\nTkinter GUI Application\n "
                                                          "Development Blueprints"))
        return 'break'
    
    def display_help_messagebox(event=None):
        tmb.showinfo("Help", "Help Book: \nTkinter GUI Application\n Development Blueprints", icon='question')
        return 'break'
    
    def exit_editor(event=None):
        if tmb.askokcancel('Quit?', 'Really Quit?'): # using messagebox to ask user do they really want to quit
            root.destroy()
        return 'break'
    
    def on_content_changed(event=None):
        update_line_numbers()
        update_cursor_info_bar()
    
    def get_line_numbers():
        output = ''
        if show_line_no.get():
            row, col = content_text.index("end").split(".") # calculate the last line and column in the text
                                                            # 1.0 is row 1, column 0
            print(row, col)
            for i in range(1, int(row)):
                output += str(i) + '\n'
        return output
    
    def update_line_numbers(event=None):
        line_numbers = get_line_numbers()
        line_number_bar.config(state='normal') # allow changing content inside line_number_bar
        line_number_bar.delete('1.0', 'end') # remove the old content
        line_number_bar.insert('1.0', line_numbers) # insert new line_numbers
        line_number_bar.config(state='disable') # disallow changing content inside line_number_bar
    
    def show_cursor_info_bar():
        show_curso_info_checked = show_cursor_info.get()
        if show_curso_info_checked:
            cursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')
        else:
            cursor_info_bar.pack_forget()
    
    def update_cursor_info_bar(event=None):
        row, col = content_text.index(INSERT).split('.') # get current position of row, col
        line_num, col_num = str(int(row)), str(int(col)+1)
        infotext = "Line: {0} | Column: {1}".format(line_num, col_num)
        cursor_info_bar.config(text=infotext)
    
    def highlight_line(interval=100):
        content_text.tag_remove('active_line', 1.0, 'end')
        content_text.tag_add("active_line", "insert linestart",
                             "insert lineend+1c")
        content_text.after(interval, toggle_highlight)
    
    def undo_highlight(event=None):
        content_text.tag_remove('active_line', 1.0, 'end')
    
    def toggle_highlight(event=None):
        if to_highlight_line.get():
            highlight_line()
        else:
            undo_highlight()
    
    def change_theme(event=None):
        selected_theme = theme_choice.get()
        fg_bg_colors = color_schemes.get(selected_theme)
        fg_color, bg_color = fg_bg_colors.split(".")
        content_text.config(background=bg_color, foreground=fg_color)
    
    def show_popup_menu(event=None):
        popup_menu.tk_popup(event.x_root, event.y_root)
        return 'break'
    
    # getting icons ready
    new_file_icon = PhotoImage(file='new_file.gif')
    open_file_icon = PhotoImage(file='open_file.gif')
    save_file_icon = PhotoImage(file='save.gif')
    cut_icon = PhotoImage(file='cut.gif')
    copy_icon = PhotoImage(file='copy.gif')
    undo_icon = PhotoImage(file='undo.gif')
    paste_icon = PhotoImage(file='paste.gif')
    redo_icon = PhotoImage(file='redo.gif')
    find_text_icon = PhotoImage(file='find_text.gif')
    
    #create the menu bar
    menu_bar = Menu(root)
    
    #create file menu
    file_menu = Menu(menu_bar, tearoff=0)
    file_menu.add_command(label='New', accelerator='Ctrl+N', image=new_file_icon, compound='left', command=new_file)
    file_menu.add_command(label='Open', accelerator='Ctrl+O', image=open_file_icon, compound='left', command=open_file)
    file_menu.add_command(label='Save', accelerator='Ctrl+S', image=save_file_icon, compound='left', command=save)
    file_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S', compound='left', command=save_as)
    file_menu.add_separator()
    file_menu.add_command(label='Exit', accelerator='Alt+F4', compound='left', command=exit_editor)
    menu_bar.add_cascade(label='File', menu=file_menu) # add to menu_bar
    
    # create edit menu
    edit_menu = Menu(menu_bar, tearoff=1)
    edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', image=undo_icon, compound='left', command=undo)
    edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', image=redo_icon, compound='left', command=redo)
    edit_menu.add_separator()
    edit_menu.add_command(label='Cut', accelerator='Ctrl+X', image=cut_icon, compound='left', command=cut)
    edit_menu.add_command(label='Copy', accelerator='Ctrl+C', image=copy_icon, compound='left', command=copy)
    edit_menu.add_command(label='Paste', accelerator='Ctrl+V', image=paste_icon, compound='left', command=paste)
    edit_menu.add_separator()
    edit_menu.add_command(label='Find', accelerator='Ctrl+F', image=find_text_icon, compound='left', command=find_text)
    edit_menu.add_separator()
    edit_menu.add_command(label='Select All', accelerator='Ctrl+A', compound='left', command=select_all)
    menu_bar.add_cascade(label='Edit', menu=edit_menu) # add to menu_bar
    
    # create view menu
    view_menu = Menu(menu_bar)
    show_line_no = IntVar()
    show_line_no.set(1)
    view_menu.add_checkbutton(label="Show Line Number", variable=show_line_no)
    show_cursor_info = IntVar()
    show_cursor_info.set(1)
    view_menu.add_checkbutton(label='Show Cursor Location at Bottom', variable=show_cursor_info, command=show_cursor_info_bar)
    to_highlight_line = IntVar()
    view_menu.add_checkbutton(label='Highlight Current Line', onvalue=1, offvalue=0, variable=to_highlight_line, command=toggle_highlight)
    themes_menu = Menu(menu_bar, tearoff=0)
    view_menu.add_cascade(label='Themes', menu=themes_menu)
    menu_bar.add_cascade(label='View', menu=view_menu) # add to menu_bar
    """
    color scheme is defined with dictionary elements like theme_name: fg.bg
    """
    color_schemes = {
        'Default' : '#000000.#FFFFFF',
        'Greygarious': '#83406A.#D1D4D1',
        'Aquamarine': '#5B8340.#D1E7E0',
        'Bold Beige': '#4B4620.#FFF0E1',
        'Cobalt Blue': '#ffffBB.#3333aa',
        'Olive Green': '#D1E7E0.#5B8340',
        'Night Mode': '#FFFFFF.#000000',
    }
    theme_choice = StringVar()
    theme_choice.set('Default')
    for k in sorted(color_schemes):
        themes_menu.add_radiobutton(label=k, variable=theme_choice, command=change_theme)
    
    # create about menu
    about_menu = Menu(menu_bar)
    about_menu.add_command(label='About', compound='left', command=display_about_messagebox)
    about_menu.add_command(label='Help', compound='left', command=display_help_messagebox)
    menu_bar.add_cascade(label='About', menu=about_menu)
    root.config(menu=menu_bar)
    
    # add the shorcut bar
    shortcut_bar = Frame(root, height=25, bg='light sea green')
    shortcut_bar.pack(expand='no', fill='x')
    # add icons to shortcut bar
    new_shortcut = Button(shortcut_bar, image=new_file_icon, command=new_file)
    new_shortcut.pack(side='left')
    open_shortcut = Button(shortcut_bar, image=open_file_icon, command=open_file)
    open_shortcut.pack(side='left')
    save_shortcut = Button(shortcut_bar, image=save_file_icon, command=save)
    save_shortcut.pack(side='left')
    cut_shortcut = Button(shortcut_bar, image=cut_icon, command=cut)
    cut_shortcut.pack(side='left')
    copy_shortcut = Button(shortcut_bar, image=copy_icon, command=copy)
    copy_shortcut.pack(side='left')
    paste_shortcut = Button(shortcut_bar, image=paste_icon, command=paste)
    paste_shortcut.pack(side='left')
    undo_shortcut = Button(shortcut_bar, image=undo_icon, command=undo)
    undo_shortcut.pack(side='left')
    redo_shortcut = Button(shortcut_bar, image=redo_icon, command=redo)
    redo_shortcut.pack(side='left')
    find_shortcut = Button(shortcut_bar, image=find_text_icon, command=find_text)
    find_shortcut.pack(side='left')
    
    # add line number text field
    line_number_bar = Text(root, width=4, pady=-3, takefocus=0, border=0,
                           bg='khaki', state='disabled', wrap='none')
    line_number_bar.pack(side='left', fill='y')
    
    # add the content text field
    content_text = Text(root, wrap='word', undo=1)
    content_text.pack(expand='yes', fill='both')
    # add the scroll bar next to content text field
    scroll_bar = Scrollbar(content_text)
    content_text.configure(yscrollcommand=scroll_bar.set) # ?
    scroll_bar.config(command=content_text.yview) # ?
    scroll_bar.pack(side='right', fill='y')
    
    # adding popup menu
    popup_menu = Menu(content_text)
    for i in ('cut', 'copy', 'paste', 'undo', 'redo'):
        cmd = eval(i)
        popup_menu.add_command(label=i, compound='left', command=cmd)
    popup_menu.add_separator()
    popup_menu.add_command(label='Select All', command=select_all)
    
    # handling redo quirk
    # note: on mac, Control == Command
    content_text.bind('<Control-y>', redo)
    content_text.bind('<Control-Y>', redo)
    
    # bind select all as Control-A / Control-a to content_text
    content_text.bind('<Control-a>', select_all)
    content_text.bind('<Control-A>', select_all)
    
    # bind find all feature to Ctrl+f shortcut
    content_text.bind('<Control-f>', find_text)
    content_text.bind('<Control-F>', find_text)
    
    # bind open file feature to Ctrl+o shortcut
    content_text.bind('<Control-o>', open_file)
    content_text.bind('<Control-O>', open_file)
    
    # bind save and save_as feature to Ctrl+S and Shift+Ctrl+S shortcuts
    content_text.bind('<Control-s>', save)
    content_text.bind('<Control-S>', save)
    content_text.bind('<Shift-Control-s>', save_as)
    content_text.bind('<Shift-Control-S>', save_as)
    
    # bind new file feature to Ctrl+N shorcut
    content_text.bind('<Control-n>', new_file)
    content_text.bind('<Control-N>', new_file)
    
    content_text.bind('<KeyPress-F1>', display_help_messagebox)
    content_text.bind('<Any-KeyPress>', on_content_changed)
    
    # bind right mouse to popup menu
    content_text.bind('<Button-2>', show_popup_menu)
    
    content_text.tag_configure('active_line', background='ivory2')
    cursor_info_bar = Label(content_text, text='Line:1 | Column:1')
    cursor_info_bar.pack(expand='NO', fill=None, side='right', anchor='se')
    
    root.protocol('WM_DELETE_WINDOW', exit_editor) # override destroy handler
    root.mainloop()
    
     
  • loctv 5:42 am on May 16, 2016 Permalink | Reply
    Tags:   

    Fano Encoder 

    Screen Shot 2016-05-16 at 12.41.29 PM

    Source:
    https://drive.google.com/open?id=0B8sS9QBwRAtjQ194cjV2OWQxSlE

     
  • loctv 5:40 am on May 16, 2016 Permalink | Reply
    Tags:   

    Huffman Encoder 

    Screen Shot 2016-05-16 at 12.39.14 PM

    Source:
    https://drive.google.com/open?id=0B8sS9QBwRAtjaWhRUTUtUmNHa1U

     
  • loctv 2:40 pm on March 30, 2016 Permalink | Reply
    Tags:   

    Project: ThrustCopter (LibGDX Framework) 

    Starting making game by clone a game like flappy bird.
    The game’s rule is simple, try to fly the plane as far as possible, try to avoid colliding with terrain, meteors, pillars, … Some items can help you like fuel to maximize your distance, shield to prevent you from threats, star to increase your score.
    To control the plane, touch or click on the screen (the area before, above and below the plane)
    runnable jar file
    source code (gradle project)

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel