[
  {
    "path": "Chapter 01/1.01.py",
    "content": "\"\"\"\nCode illustration: 1.01\nYour first GUI application - the top level window\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nroot = tk.Tk()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.02.py",
    "content": "\"\"\"\nCode illustration: 1.02\nAdding some widgets\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nroot =tk.Tk()\nmy_label = tk.Label(root, text=\"I am a label widget\")  #(1)\nmy_button = tk.Button(root, text=\"I am a button\")  #(2)\nmy_label.pack()  #(3)\nmy_button.pack()  #(4)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.03.py",
    "content": "\"\"\"\r\nCode illustration: 01.03\r\nA demonstration of all core tkinter widgets\r\nTkinter GUI Application Development Blueprints\r\n\"\"\"\r\n\r\nimport tkinter as tk\r\n\r\nroot = tk.Tk()\r\nroot.title('I am a Top Level Widget, parent to other widgets')\r\n#create a frame widget for placing menu\r\nmy_menu_bar = tk.Frame(root, relief='raised', bd=2)\r\nmy_menu_bar.pack(fill=tk.X)\r\n\r\n# Create  Menu Widget 1 and Sub Menu 1\r\nmy_menu_button = tk.Menubutton(\r\n    my_menu_bar,\r\n    text='Menu tk.Button Widget 1',\r\n)\r\nmy_menu_button.pack(side=tk.LEFT)\r\n#menu widget\r\nmy_menu = tk.Menu(my_menu_button, tearoff=0)\r\nmy_menu_button['menu'] = my_menu\r\nmy_menu.add('command', label='Menu Widget 1')  #Add Sub Menu 1\r\n\r\n# Create  Menu2 and Submenu2\r\nmenu_button_2 = tk.Menubutton(\r\n    my_menu_bar,\r\n    text='Menu 2',\r\n)\r\nmenu_button_2.pack(side=tk.LEFT)\r\nmy_menu_2 = tk.Menu(menu_button_2, tearoff=0)\r\nmenu_button_2['menu'] = my_menu_2\r\nmy_menu_2.add('command', label='Sub Menu 2')  # Add Sub Menu 2\r\n\r\n#\r\n#\r\n# my_frame_1  and its contents\r\n#\r\n\r\n# creating a frame (my_frame_1)\r\nmy_frame_1 = tk.Frame(root, bd=2, relief=tk.SUNKEN)\r\nmy_frame_1.pack(side=tk.LEFT)\r\n\r\n# add label to to my_frame_1\r\ntk.Label(my_frame_1, text='I am a tk.Label widget').pack()\r\n\r\n#add entry widget to my_frame_1\r\ntv = tk.StringVar()  #discussed later\r\ntk.Entry(my_frame_1, textvariable=tv).pack()\r\ntv.set('I am an entry widget')\r\n\r\n#add button widget to my_frame_1\r\ntk.Button(my_frame_1, text='tk.Button widget').pack()\r\n\r\n#add check button widget to my_frame_1\r\ntk.Checkbutton(my_frame_1, text='Checktk.Button Widget').pack()\r\n\r\n#add radio buttons to my_frame_1\r\ntk.Radiobutton(my_frame_1, text='Radio tk.Button  Un', value=1).pack()\r\ntk.Radiobutton(my_frame_1, text='Radio tk.Button  Dos', value=2).pack()\r\ntk.Radiobutton(my_frame_1, text='Radio tk.Button  Tres', value=3).pack()\r\n\r\n#tk.OptionMenu Widget\r\ntk.Label(my_frame_1, text='Example of tk.OptionMenu Widget:').pack()\r\ntk.OptionMenu(my_frame_1, '', \"Option A\", \"Option B\", \"Option C\").pack()\r\n\r\n#adding my_image image\r\ntk.Label(my_frame_1, text='Image Fun with Bitmap Class:').pack()\r\nmy_image = tk.BitmapImage(file=\"gir.xbm\")\r\nmy_label = tk.Label(my_frame_1, image=my_image)\r\nmy_label.image = my_image  # keep a reference!\r\nmy_label.pack()\r\n\r\n#\r\n#\r\n# frame2 and widgets it contains.\r\n#\r\n#\r\n\r\n#create another frame(my_frame_2) to hold a list box, Spinbox Widget,Scale Widget, :\r\nmy_frame_2 = tk.Frame(root, bd=2, relief=tk.GROOVE)\r\nmy_frame_2.pack(side=tk.RIGHT)\r\n\r\n#add Photimage Class Widget to my_frame_2\r\ntk.Label(\r\n    my_frame_2, text='Image displayed with \\nPhotoImage class widget:').pack()\r\ndance_photo = tk.PhotoImage(file='dance.gif')\r\ndance_photo_label = tk.Label(my_frame_2, image=dance_photo)\r\ndance_photo_label.image = dance_photo\r\ndance_photo_label.pack()\r\n\r\n#add my_listbox widget to my_frame_2\r\ntk.Label(my_frame_2, text='Below is an example of my_listbox widget:').pack()\r\nmy_listbox = tk.Listbox(my_frame_2, height=4)\r\nfor line in ['Listbox Choice 1', 'Choice 2', 'Choice 3', 'Choice 4']:\r\n  my_listbox.insert(tk.END, line)\r\nmy_listbox.pack()\r\n\r\n#spinbox widget\r\ntk.Label(my_frame_2, text='Below is an example of spinbox widget:').pack()\r\ntk.Spinbox(my_frame_2, values=(1, 2, 4, 8, 10)).pack()\r\n\r\n#scale widget\r\ntk.Scale(\r\n    my_frame_2, from_=0.0, to=100.0, label='Scale widget',\r\n    orient=tk.HORIZONTAL).pack()\r\n\r\n#LabelFrame\r\nlabel_frame = tk.LabelFrame(\r\n    my_frame_2, text=\"LabelFrame Widget\", padx=10, pady=10)\r\nlabel_frame.pack(padx=10, pady=10)\r\ntk.Entry(label_frame).pack()\r\n\r\n#message widget\r\ntk.Message(my_frame_2, text='I am a Message widget').pack()\r\n\r\n#\r\n#\r\n# tk.Frame 3\r\n#\r\n#\r\n\r\nmy_frame_3 = tk.Frame(root, bd=2, relief=tk.SUNKEN)\r\n\r\n#text widget and associated tk.Scrollbar widget\r\nmy_text = tk.Text(my_frame_3, height=10, width=40)\r\nfile_object = open('textcontent.txt')\r\nfile_content = file_object.read()\r\nfile_object.close()\r\nmy_text.insert(tk.END, file_content)\r\nmy_text.pack(side=tk.LEFT, fill=tk.X, padx=5)\r\n\r\n#add scrollbar widget to the text widget\r\nmy_scrollbar = tk.Scrollbar(my_frame_3, orient=tk.VERTICAL, command=my_text.yview)\r\nmy_scrollbar.pack()\r\nmy_text.configure(yscrollcommand=my_scrollbar.set)\r\nmy_frame_3.pack()\r\n\r\n#\r\n#\r\n# tk.Frame 4\r\n#\r\n#\r\n#create another frame(my_frame_4)\r\nmy_frame_4 = tk.Frame(root)\r\nmy_frame_4.pack()\r\n\r\nmy_canvas = tk.Canvas(my_frame_4, bg='white', width=340, height=80)\r\nmy_canvas.pack()\r\nmy_canvas.create_oval(20, 15, 60, 60, fill='red')\r\nmy_canvas.create_oval(40, 15, 60, 60, fill='grey')\r\nmy_canvas.create_text(\r\n    130, 38, text='I am a tk.Canvas Widget', font=('arial', 8, 'bold'))\r\n\r\n#\r\n#\r\n# A paned window widget\r\n#\r\n#\r\n\r\ntk.Label(root, text='Below is an example of Paned window widget:').pack()\r\ntk.Label(\r\n    root,\r\n    text='Notice you can adjust the size of each pane by dragging it').pack()\r\nmy_paned_window_1 = tk.PanedWindow()\r\nmy_paned_window_1.pack(fill=tk.BOTH, expand=2)\r\nleft_pane_text = tk.Text(my_paned_window_1, height=6, width=15)\r\nmy_paned_window_1.add(left_pane_text)\r\nmy_paned_window_2 = tk.PanedWindow(my_paned_window_1, orient=tk.VERTICAL)\r\nmy_paned_window_1.add(my_paned_window_2)\r\ntop_pane_text = tk.Text(my_paned_window_2, height=3, width=3)\r\nmy_paned_window_2.add(top_pane_text)\r\nbottom_pane_text = tk.Text(my_paned_window_2, height=3, width=3)\r\nmy_paned_window_2.add(bottom_pane_text)\r\n\r\nroot.mainloop()\r\n"
  },
  {
    "path": "Chapter 01/1.04.py",
    "content": "\"\"\"\nCode illustration: 1.04\nA demonstration of some of pack() options\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nroot = tk.Tk()\n\nframe = tk.Frame(root)\n# demo of side and fill options\ntk.Label(frame, text=\"Pack Demo of side and fill\").pack()\ntk.Button(frame, text=\"A\").pack(side=tk.LEFT, fill=tk.Y)\ntk.Button(frame, text=\"B\").pack(side=tk.TOP, fill=tk.X)\ntk.Button(frame, text=\"C\").pack(side=tk.RIGHT, fill=tk.NONE)\ntk.Button(frame, text=\"D\").pack(side=tk.TOP, fill=tk.BOTH)\nframe.pack()  # note the top frame does not expand nor does it fill in\n#X or Y directions\n\n# demo of expand options - best understood by expanding the root widget\n# and seeing the effect on all the three buttons below.\ntk.Label(root, text=\"Pack Demo of expand\").pack()\ntk.Button(root, text=\"I do not expand\").pack()\ntk.Button(root, text=\"I do not fill x but I expand\").pack(expand=1)\ntk.Button(root, text=\"I fill x and expand\").pack(fill=tk.X, expand=1)\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.05.py",
    "content": "\"\"\"\nCode illustration: 1.05\nWhere to use pack() options\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nroot = tk.Tk()\nparent = tk.Frame(root)\n\n#placing widgets top-down\ntk.Button(parent, text='ALL IS WELL').pack(fill=tk.X)\ntk.Button(parent, text='BACK TO BASICS').pack(fill=tk.X)\ntk.Button(parent, text='CATCH ME IF U CAN').pack(fill=tk.X)\n#placing widgets side by side\ntk.Button(parent, text='LEFT').pack(side=tk.LEFT)\ntk.Button(parent, text='CENTER').pack(side=tk.LEFT)\ntk.Button(parent, text='RIGHT').pack(side=tk.LEFT)\nparent.pack()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.06.py",
    "content": "\"\"\"\nCode illustration: 1.06\nSimple example of grid Geometry Manager\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nroot = tk.Tk()\ntk.Label(root, text=\"Username\").grid(row=0, sticky=tk.W)\ntk.Label(root, text=\"Password\").grid(row=1, sticky=tk.W)\ntk.Entry(root).grid(row=0, column=1, sticky=tk.E)\ntk.Entry(root).grid(row=1, column=1, sticky=tk.E)\ntk.Button(root, text=\"Login\").grid(row=2, column=1, sticky=tk.E)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.07.py",
    "content": "\"\"\"\nCode illustration: 1.07\nA demonstration of grid() geometry manager options\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nparent = tk.Tk()\nparent.title('Find & Replace')\n\ntk.Label(parent, text=\"Find:\").grid(row=0, column=0, sticky='e')\ntk.Entry(parent, width=60).grid(row=0, column=1, padx=2, pady=2, sticky='we', columnspan=9)\n\ntk.Label(parent, text=\"Replace:\").grid(row=1, column=0, sticky='e')\ntk.Entry(parent).grid(row=1, column=1, padx=2, pady=2, sticky='we', columnspan=9)\n\ntk.Button(parent, text=\"Find\").grid(row=0, column=10, sticky='e'+'w', padx=2, pady=2)\ntk.Button(parent, text=\"Find All\").grid(row=1, column=10, sticky='e'+'w', padx=2)\ntk.Button(parent, text=\"Replace\").grid(row=2, column=10, sticky='e'+'w', padx=2)\ntk.Button(parent, text=\"Replace All\").grid(row=3, column=10, sticky='e'+'w', padx=2)\n\n\ntk.Checkbutton(parent, text='Match whole word only ').grid(row =2, column=1, columnspan=4,sticky='w')\ntk.Checkbutton(parent, text='Match Case').grid(row =3, column=1, columnspan=4,sticky='w')\ntk.Checkbutton(parent, text='Wrap around').grid(row =4, column=1, columnspan=4,sticky='w')\n\n\n\ntk.Label(parent, text=\"Direction:\").grid(row=2, column=6,sticky='w')\ntk.Radiobutton(parent, text='Up',  value=1).grid(row=3, column=6, columnspan=6, sticky='w')\ntk.Radiobutton(parent, text='Down',  value=2).grid(row=3, column=7,columnspan=2, sticky='e')\n\n\nparent.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.08.py",
    "content": "\"\"\"\nCode illustration: 1.08\nA demonstration of common place() options\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nroot = tk.Tk()\n# Absolute positioning\ntk.Button(root, text=\"Absolute Placement\").place(x=20, y=10)\n# Relative positioning\ntk.Button(\n    root, text=\"Relative\").place(\n        relx=0.8, rely=0.2, relwidth=0.5, width=10, anchor=tk.NE)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.09.py",
    "content": "\"\"\"\nCode illustration: 1.09\nA demonstration of event binding with the bind() method\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\n\nroot = tk.Tk()\ntk.Label(root, text='Click at different \\n locations in the frame below').pack()\ndef callback(event): ##(2)\n    print(dir(event))##(3) Inspecting the instance event\n    print(\"you clicked at\", event.x, event.y )##(4)\n\n\nframe = tk.Frame(root, bg='khaki', width=130, height=80)\nframe.bind(\"<Button-1>\", callback)##(1)\nframe.pack()\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.10.py",
    "content": "\"\"\"\nCode illustration: 1.10\nA demonstration of events and the information available in it.\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\n\ndef show_event_details(event):\n  print('='*50)\n  print(\"EventKeySymbol=\" + str(event.keysym))\n  print(\"EventType=\" + str(event.type))\n  print(\"EventWidgetId=\" + str(event.widget))\n  print(\"EventCoordinate (x,y)=(\" + str(event.x)+\",\"+str(event.y)+\")\")\n  print(\"Time:\", str(event.time))\n\nroot = tk.Tk()\n\nbutton = tk.Button(root, text=\"tk.Button Bound to: \\n Keyboard Enter & Mouse Click\") #create button\nbutton.pack(pady=5,padx=4)\nbutton.focus_force()\nbutton.bind(\"<Button-1>\", show_event_details)  #bind button to mouse click\nbutton.bind(\"<Return>\", show_event_details)#bind button to Enter Key\n\n\ntk.Label(text=\"tk.Entry is Bound to Mouseclick \\n, FocusIn and Keypress Event\").pack()\nentry = tk.Entry(root) #creating entry widget\nentry.pack()\n\n\n#binding entry widget to mouse click and focus in\nentry.bind(\"<Button-1>\", show_event_details) # left mouse click\nentry.bind(\"<Button-2>\", show_event_details) # right mouse click\nentry.bind(\"<FocusIn>\", show_event_details)\n\n#binding entry widget alphabets and numbers from keyboard\nalpha_num_keys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789'\nfor key in alpha_num_keys:\n    entry.bind(\"<KeyPress-%s>\"%key, show_event_details)\n\n#binding entry widget to keysym\nkeysyms = ['Alt_L', 'Alt_R','BackSpace', 'Cancel', 'Caps_Lock','Control_L',\n           'Control_R','Delete', 'Down', 'End', 'Escape', 'Execute','F1',\n           'F2', 'Home', 'Insert', 'Left','Linefeed','KP_0','KP_1','KP_2',\n           'KP_3','KP_4','KP_5','KP_6','KP_7','KP_8','KP_9','KP_Add',\n           'KP_Decimal','KP_Divide']\nfor i in keysyms:\n    entry.bind(\"<KeyPress-%s>\"%i, show_event_details)\n\n\n#binding tk.Canvas widget to Motion Event\ntk.Label(text=\"Canvas Bound to Motion Event\\n(Hover over the area \\nto see motion event )\").pack()\ncanvas = tk.Canvas(root, background='white',width=100, height=30)\ncanvas.pack()\ncanvas.bind('<Motion>', show_event_details)\n\n\ntk.Label(text=\"Entry Widget Bound to \\n<Any KeyPress>\").pack()\nentry_1 = tk.Entry(root) #creating entry widget\nentry_1.pack(pady=7)\n#binding entry widget to mouse click and focus in\nentry_1.bind(\"<Any KeyPress>\", show_event_details) # right mouse click\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.11.py",
    "content": "\"\"\"\nCode illustration: 1.11\nA demonstration of tkinter Variable Class\nIntVar, StringVar & BooleanVar\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nroot = tk.Tk()\n\ndef show():\n    print( \"You entered:\")\n    print( \"Employee Number: \"+ str(employee_number.get()))\n    print( \"Login Password: \"+ password.get())\n    print( \"Remember Me: \"+ str(remember_me.get()))\n    print( '*'*30)\n\n#demo of IntVar\ntk.Label(root, text=\"Employee Number:\").grid(row=1, column=1)\nemployee_number = tk.IntVar()\ntk.Entry(root, width=40, textvariable=employee_number).grid(row=1, column=2, columnspan=2)\nemployee_number.set(\"120350\")\n\n\n#demo of StringVar\ntk.Label(root, text=\"Login Password:\").grid(row=2, column=1, sticky='w')\npassword = tk.StringVar() # defines the widget state as string\ntk.Entry(root,width=40, show=\"*\",  textvariable=password).grid(row=2, column=2, columnspan=2)\npassword.set(\"mysecretpassword\")\n\ntk.Button(root,text=\"Login\", command=show).grid(row=3, column=3)\n\n#demo of Boolean var\nremember_me = tk.BooleanVar()\ntk.Checkbutton(root, text=\"Remember Me\", variable=remember_me).grid(row=3, column=2)\nremember_me.set(True)\n\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/1.12.py",
    "content": "\"\"\"\nCode illustration: 1.12\nA demonstration of tkinter styling\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nroot = tk.Tk()\nroot.configure(background='#4D4D4D')  #top level styling\n\n# connecting to the external styling optionDB.txt\nroot.option_readfile('optionDB.txt')\n\n#widget specific styling\ntext = tk.Text(\n    root,\n    background='#101010',\n    foreground=\"#D6D6D6\",\n    borderwidth=18,\n    relief='sunken',\n    width=17,\n    height=5)\ntext.insert(\n    tk.END,\n    \"Style is knowing who you are,what you want to say, and not giving a damn.\"\n)\ntext.grid(row=0, column=0, columnspan=6, padx=5, pady=5)\n\n# all the below widgets derive their styling from optionDB.txt file\ntk.Button(root, text='*').grid(row=1, column=1)\ntk.Button(root, text='^').grid(row=1, column=2)\ntk.Button(root, text='#').grid(row=1, column=3)\ntk.Button(root, text='<').grid(row=2, column=1)\ntk.Button(\n    root, text='OK', cursor='target').grid(\n        row=2, column=2)  #changing cursor style\ntk.Button(root, text='>').grid(row=2, column=3)\ntk.Button(root, text='+').grid(row=3, column=1)\ntk.Button(root, text='v').grid(row=3, column=2)\ntk.Button(root, text='-').grid(row=3, column=3)\nfor i in range(10):\n  tk.Button(\n      root, text=str(i)).grid(\n          column=3 if i % 3 == 0 else (1 if i % 3 == 1 else 2),\n          row=4 if i <= 3 else (5 if i <= 6 else 6))\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 01/gir.xbm",
    "content": "#define 1026234pirate_width 226\n#define 1026234pirate_height 199\nstatic char 1026234pirate_bits[] = {\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, \n  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x05, 0x80, 0x00, 0x40, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, \n  0x02, 0x40, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x6A, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95, 0x5B, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x6A, \n  0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x54, 0x02, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x16, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x40, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x00, 0x58, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xC0, 0x02, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xA0, 0x01, \n  0x54, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, \n  0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x60, 0x06, 0x40, 0x80, 0xA9, 0x1A, 0xA0, 0x00, 0x28, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x05, 0x60, 0x40, 0x5A, 0xF4, \n  0x60, 0x80, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x80, 0x02, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x0A, 0x50, 0xB0, 0x03, 0x00, 0x81, 0x81, 0x0A, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x70, 0x00, 0x03, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x42, 0x01, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x03, 0x60, 0xB3, \n  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, \n  0x54, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xC0, 0x08, 0x02, 0x90, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x40, 0x02, 0x86, 0x02, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5A, 0x05, 0xD8, 0x29, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x14, 0xA8, \n  0x09, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA5, \n  0x1A, 0x7C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x14, 0x06, 0x18, 0x18, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xB0, 0xDA, 0x55, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x04, 0x08, 0x10, 0x0A, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x58, 0x27, 0xAA, 0x0F, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x0A, 0x05, 0x05, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, \n  0xCF, 0x97, 0x95, 0x35, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x0A, 0xA2, 0x32, 0x08, 0x01, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x50, 0x79, 0xB5, 0x6A, 0xAA, 0x08, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x0A, \n  0x43, 0x21, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xEE, 0x75, \n  0xAD, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xD0, 0x06, 0x0A, 0x05, 0xB0, 0x12, 0x80, 0x02, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xA0, 0x33, 0x97, 0x56, 0x3D, 0x20, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0F, 0x1A, 0x86, 0x61, 0x10, \n  0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xDC, 0xF6, 0x06, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x04, 0x09, 0x91, 0x0A, 0x02, 0x82, 0x06, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xE8, 0x77, 0x0B, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x02, 0xA0, 0x45, 0x81, 0x01, \n  0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAF, 0x1D, 0x0A, 0x82, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, \n  0x0E, 0x06, 0x80, 0x02, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, \n  0x5F, 0x02, 0x04, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x18, 0x12, 0x08, 0x60, 0x80, 0x00, 0x10, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xD8, 0x5F, 0x01, 0x00, 0x86, 0x01, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x0C, 0x50, \n  0x57, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xAF, 0x02, \n  0x18, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x28, 0x16, 0xA0, 0x05, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xBE, 0x55, 0x42, 0x18, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x00, 0x10, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x2A, 0xE2, 0x60, 0x44, \n  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x20, 0xA4, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xAF, 0x15, 0xC4, 0x54, 0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x40, 0xA0, 0x58, 0x01, 0x00, 0x26, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x0A, 0x02, 0xA8, 0x6A, 0x02, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xB0, 0xA0, \n  0x05, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x15, \n  0x2C, 0x6B, 0xA5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x14, 0x40, 0xC0, 0x02, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xFA, 0x0A, 0xD0, 0x95, 0x7A, 0x02, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xE9, 0xAA, \n  0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFD, 0x05, 0x68, 0x2A, \n  0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, \n  0x05, 0x00, 0x00, 0x56, 0x55, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x40, 0xFF, 0x03, 0x90, 0xD5, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x26, 0x00, 0x58, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x05, 0x50, 0x9A, 0x57, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFF, \n  0x01, 0xA0, 0xD5, 0xAB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xA0, 0xFF, 0x01, 0x60, 0xEA, 0xE7, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xFE, 0x02, 0x80, \n  0x95, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x50, 0x7D, 0x01, 0x80, 0x5A, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x18, 0x80, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xDA, 0x00, 0x00, 0xA5, 0x15, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, \n  0x7D, 0x00, 0x00, 0x5A, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1C, 0x00, 0x05, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xB0, 0xFA, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, \n  0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFD, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xFA, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, \n  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x5A, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xFA, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x2B, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x40, 0xFA, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x3D, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x40, 0xFB, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE5, 0x1C, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xAB, \n  0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xE0, 0x57, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xAB, 0x05, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xD0, 0xD7, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x07, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, \n  0xE5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x58, 0xD5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xEA, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xFE, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x69, 0x02, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xFF, 0xAB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xAB, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x80, 0xFF, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x6B, 0x00, 0x00, \n  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xA0, 0xFF, 0x97, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xFF, 0x37, 0x00, 0x00, 0x00, 0x50, \n  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xFE, \n  0x7B, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x68, 0xFA, 0x7D, 0x00, 0x00, 0x00, 0x54, 0x28, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x55, 0x7E, 0x00, \n  0x00, 0x80, 0xAA, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xE5, 0xA9, 0x5D, 0x00, 0x00, 0x1A, 0x54, 0x05, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x57, 0x12, 0x00, 0x00, 0xCE, \n  0xA8, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xFA, \n  0xA9, 0x2A, 0x00, 0x80, 0x0B, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x80, 0xFD, 0x97, 0x17, 0x00, 0x40, 0x06, 0x60, 0x56, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xFE, 0xFB, 0x2B, \n  0x00, 0x00, 0x00, 0x64, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xA0, 0xF5, 0xF5, 0x17, 0x00, 0x00, 0x1C, 0x04, 0xFA, 0x01, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x5A, 0xFE, 0x1F, 0x00, 0x00, \n  0x6A, 0x09, 0xE4, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xA6, \n  0xA9, 0xFD, 0x17, 0x00, 0x00, 0xB4, 0x06, 0xFB, 0x01, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x40, 0x00, 0x49, 0xFA, 0x55, 0xFE, 0x0B, 0x00, 0x00, 0x7A, 0x5B, \n  0x6A, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xDF, 0xB4, 0xFE, 0xAB, 0xFE, \n  0x17, 0x00, 0x00, 0x94, 0xA5, 0xB9, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, \n  0x5F, 0x6B, 0xFF, 0x57, 0xFC, 0x15, 0x00, 0x00, 0xAC, 0x55, 0xDA, 0x0A, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xDA, 0xFF, 0xE7, 0x97, 0xFF, 0xAF, 0xFF, 0x0B, 0x00, \n  0x00, 0x54, 0xAB, 0x60, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA5, 0xFF, 0xDB, 0x5F, \n  0xFF, 0x57, 0xFE, 0x05, 0x00, 0x00, 0xA8, 0x36, 0xA0, 0x1F, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x70, 0x5A, 0x2D, 0xC5, 0xAF, 0xFF, 0xAF, 0xBB, 0x0A, 0x00, 0x00, 0x50, \n  0x09, 0xE0, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xD5, 0xAA, 0xDA, 0xA7, 0xFF, 0x67, \n  0xAA, 0x05, 0x00, 0x00, 0x40, 0x02, 0x40, 0x27, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xAA, \n  0x55, 0x67, 0xDA, 0xFF, 0xFB, 0x55, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, \n  0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x80, 0x7F, 0x55, 0xDA, 0xAF, 0x6D, 0xFF, 0xF9, 0xAA, 0x05, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xAA, 0xA5, 0x5F, \n  0x91, 0xFF, 0xF5, 0x55, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xC0, 0x5F, 0xAA, 0xAF, 0x27, 0xA9, 0xB6, 0x3A, 0xA9, 0x01, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xE7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xBF, 0x55, 0x5F, 0xF9, 0x5F, 0x59, \n  0x95, 0x5E, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xA0, 0x5F, \n  0xEA, 0xFF, 0xF6, 0x9F, 0xAA, 0xF8, 0xBF, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xF6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x58, 0x55, 0xAB, 0xD5, 0xFF, 0xFD, 0x7F, 0x55, 0xFF, 0xFF, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x03, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xA2, 0xDA, 0xD5, 0xFF, \n  0xFB, 0xFF, 0x9A, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x04, 0x54, 0xF5, 0xEB, 0xFF, 0xF7, 0xFF, 0xE5, 0xFF, 0xBF, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA8, 0xFA, 0xE5, 0xFF, 0xFF, 0xFF, \n  0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x06, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, \n  0xB5, 0xFB, 0xFF, 0xE7, 0xFF, 0xEB, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xA8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x01, 0x90, 0x55, 0xF6, 0xFF, 0x5F, 0xFF, 0xD7, 0xFF, \n  0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0F, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x78, 0xAA, 0xE9, \n  0xFF, 0xA3, 0xFF, 0xEB, 0xFF, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xB8, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x80, 0x00, 0xA8, 0x3F, 0xE7, 0xFF, 0x5B, 0xFE, 0x5B, 0xFF, 0x2F, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0xFF, 0xF8, 0xFF, 0x6F, \n  0xF9, 0xA5, 0xFE, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x3F, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, \n  0xE8, 0xFF, 0xAA, 0xFF, 0xAF, 0x5A, 0x5D, 0xDB, 0x0A, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xD0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x40, 0x00, 0xD4, 0xFF, 0xD5, 0xFF, 0x57, 0xA5, 0xAA, \n  0xA5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE4, 0xFF, \n  0xBA, 0xFF, 0xAB, 0x6E, 0x95, 0x9B, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xE0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x50, 0x00, 0xE8, 0xFF, 0x75, 0xFE, 0x57, 0xBF, 0xEA, 0x57, 0x05, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xAF, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0xE8, 0xFF, 0xFB, 0x69, \n  0xD1, 0x7F, 0xE9, 0x57, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, \n  0xAB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x06, \n  0x00, 0xF8, 0xFF, 0xF9, 0x97, 0xED, 0xFF, 0xF6, 0xAF, 0x02, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x60, 0x5E, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0xD0, 0xFF, 0xFD, 0x5A, 0xFA, 0xFF, \n  0xEB, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xAD, 0x06, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0xA8, \n  0xFF, 0x53, 0xA5, 0xE5, 0x7F, 0xD6, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x80, 0xDE, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x14, 0x00, 0x00, 0x50, 0xFA, 0x96, 0xDA, 0xFA, 0xBF, 0xAA, 0x65, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xE4, 0x07, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xA0, 0x55, 0xE9, \n  0x5F, 0xF5, 0x7F, 0xD5, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x80, 0xDF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x05, \n  0x00, 0x00, 0x50, 0xA6, 0xDA, 0xBF, 0xFA, 0xBF, 0xEA, 0x0F, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xDF, 0x2B, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0xA0, 0xFD, 0xF5, 0x5F, 0xF5, \n  0x7F, 0xF5, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBF, \n  0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, \n  0x00, 0xFF, 0xF9, 0xBF, 0xDC, 0x1F, 0xFA, 0x07, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x80, 0xBF, 0xFA, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x28, 0x02, 0x00, 0x00, 0x80, 0xFE, 0xFB, 0x7F, 0xBD, 0xEF, 0xF5, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xF9, 0x75, \n  0xFE, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0xFD, \n  0xFE, 0xBF, 0xBF, 0x57, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x80, 0xFE, 0xFD, 0x99, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, \n  0x02, 0x00, 0x00, 0x00, 0xFC, 0xFD, 0x5F, 0x7F, 0x69, 0x1D, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFC, 0xFF, 0xF6, 0x5E, \n  0x00, 0x00, 0x40, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x00, 0x60, 0xFA, 0x5F, \n  0x7F, 0x5A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xAE, 0xFB, 0x77, 0xA5, 0xE5, 0x01, 0x00, 0x00, 0x00, 0xA8, 0x01, 0x00, \n  0x00, 0x00, 0x80, 0xE5, 0xAF, 0xBE, 0xE5, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFD, 0xA8, 0x9F, 0xFA, 0x03, 0x00, \n  0x40, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x99, 0x67, 0x5D, 0x88, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xBB, \n  0x55, 0x5E, 0xED, 0x07, 0x00, 0x20, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x00, \n  0xA0, 0x11, 0x04, 0x00, 0xBC, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x5A, 0x75, 0xAD, 0xAA, 0xD1, 0x07, 0x00, 0x60, 0x00, \n  0x30, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x15, 0x00, 0x00, 0x9C, 0x02, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xBB, 0xDE, 0x76, \n  0xAA, 0xC7, 0x02, 0x60, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1C, \n  0x00, 0x00, 0x5C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xF0, 0x4F, 0x7F, 0xFD, 0x67, 0x2A, 0x04, 0x40, 0x00, 0x10, 0x00, \n  0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x6E, 0x02, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x9F, 0x7E, 0xFC, 0xFD, 0x05, \n  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1C, 0x00, 0x00, \n  0xE4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, \n  0x7F, 0xFF, 0xFF, 0xD3, 0x1A, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x60, 0x28, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xF0, 0xAF, 0xFE, 0xFE, 0x9B, 0x29, 0x18, 0x10, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0xD8, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x5F, 0x79, \n  0xFE, 0xE7, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, \n  0x01, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xA0, 0x65, 0xA2, 0xF9, 0xFB, 0x2B, 0x00, 0x08, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xA0, 0x1C, 0x00, 0x00, 0xAE, 0x01, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x5D, 0xF6, 0xFD, \n  0x17, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, \n  0x00, 0x6E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x7E, 0x7E, 0xAB, 0xFF, 0x15, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0xE0, 0x30, 0x00, 0x00, 0x9E, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xFF, 0x55, 0xF7, 0x1B, 0x80, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x9E, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, \n  0xFE, 0xAA, 0xE6, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xA0, 0x19, 0x00, 0x00, 0xEE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xA0, 0xFE, 0x55, 0x9D, 0x1A, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x08, 0x00, 0x00, 0xE6, 0x01, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFD, 0xEB, \n  0xD7, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x11, \n  0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x80, 0xFE, 0xF4, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x40, 0x2D, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7E, 0xFB, 0xFF, 0x07, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, \n  0xD8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xE5, 0xF7, 0xEF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x40, 0x29, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xF7, 0xF7, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x15, 0x00, 0x00, 0xD8, 0x01, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, \n  0xEB, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, \n  0x29, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x0B, 0x80, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xE0, 0x1C, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1D, 0x00, \n  0x00, 0xE8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1A, 0x00, 0x36, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x28, 0x00, 0x00, 0x6C, \n  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x15, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x40, 0x15, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x21, 0x00, 0x00, 0x6A, 0x01, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, \n  0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3F, \n  0x00, 0x00, 0xDC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x0D, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x80, 0x29, 0x00, 0x00, 0x6C, 0x03, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x3E, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1B, 0x00, 0x00, \n  0x94, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x80, 0x0D, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x80, 0x27, 0x00, 0x00, 0xA4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x16, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x78, 0x00, 0x00, 0xD8, 0x03, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, \n  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, \n  0x77, 0x00, 0x00, 0xB4, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0x38, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x36, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3B, 0x00, \n  0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x80, 0x07, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0E, 0x00, 0x14, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0x98, \n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, \n  0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0xE0, 0x29, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x68, 0x00, 0x00, 0xE8, 0x01, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, \n  0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1A, \n  0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x09, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0xA0, 0x07, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0B, 0x00, 0x06, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x66, 0x00, 0x00, \n  0x98, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x0C, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x80, 0xE2, 0x00, 0x00, 0xA8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x01, 0x00, 0xD0, 0xFE, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, \n  0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, \n  0xAA, 0x02, 0x00, 0xE8, 0x6B, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x09, 0x00, 0xF0, 0xB7, 0x0F, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x06, 0x00, 0x03, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0x95, \n  0x00, 0xF0, 0xAF, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xFE, 0x03, 0x80, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0xFA, 0x7B, 0x01, 0xA0, 0x5F, 0x2A, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE7, 0x05, 0xC0, 0x15, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x7B, 0x01, 0x90, \n  0xEF, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBD, \n  0x02, 0xE8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0xFA, 0xBD, 0x03, 0x40, 0xD9, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x51, 0x03, 0x58, 0x1F, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xEC, 0x03, 0x40, 0xDB, 0x05, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xBA, \n  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, \n  0x9B, 0x03, 0x00, 0xA7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0xF6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x80, 0x67, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };\n"
  },
  {
    "path": "Chapter 01/optionDB.txt",
    "content": "*Button*borderwidth:3\n*Button*relief: raised\n*Button*width: 3\n*Button*height: 1\n*Button*pady:3\n"
  },
  {
    "path": "Chapter 01/readme.txt",
    "content": "====================================================================\nCode Readme\nTkinter GUI Application Development Blueprints\nChapter 1: List of Programs\n====================================================================\n\n1.01  : Your first GUI application - the top level window\n1.02  : Adding some widgets\n1.03  : A demonstration of all core tkinter widgets\n1.04  : A demonstration of some of pack() options\n1.05  : Where to use pack() options\n1.06  : Simple example of grid Geometry Manager\n1.07  : A demonstration of common grid() options\n1.08  : A demonstration of common place() options\n1.09  : A demonstration of event binding with the bind() method\n1.10  : A demonstration of all Widget Binding\n1.11  : A demonstration of tkinter Variable Class IntVar, StringVar & BooleanVar\n1.12  : A demonstration of tkinter styling\n\n\nFile Extension: .py\nRequires Python 3.4.0 Installation to run.\n@author: Bhaskar Chauhdary\n"
  },
  {
    "path": "Chapter 01/textcontent.txt",
    "content": "I am a text-widget.\nTkinter includes 21 core widgets. This program demonstrates all of them.\n\nSee if you can identify all of them\n\n1) Toplevel Widget**\n2) Button Widget\n3) Canvas Widget \n4) Checkbutton Widget\n5) Entry Widget\n6) Frame Widget\n7) Label Widget\n8) LabelFrame Widget\n9) Listbox Widget\n10) Menu Widget\n11) Menubutton Widget\n12) Message Widget\n13) OptionMenu Widget\n14) PanedWindow Widget\n15) Radiobutton Widget\n16) Scale Widget\n17) Scrollbar Widget\n18) Spinbox Widget\n19) Text Widget\n20) Bitmap Class Widget\n21) Image Class Widget \n\n**  (hint - the window which houses all other widgets)\n\n\n"
  },
  {
    "path": "Chapter 02/2.01.py",
    "content": "\"\"\"\nCode illustration: 2.01\nText Editor Code\nStep 1: Adding Top-level\nStep 2: Add Menubuttons\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Menu\n\n\nPROGRAM_NAME = \"Footprint Editor\"\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\nmenu_bar = Menu(root)  # menu begins\n\nfile_menu = Menu(menu_bar, tearoff=0)\n# all file menu-items will be added here next\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\nview_menu = Menu(menu_bar, tearoff=0)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nmenu_bar.add_cascade(label='About',  menu=about_menu)\n\nroot.config(menu=menu_bar)  # menu ends\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.02.py",
    "content": "\"\"\"\nCode illustration: 2.02\nText Editor Code\nStep 3: Adding  Menu items to each menu\nStep 4: Adding labels to hold shortcut toolbar and line number\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar\n\n\nPROGRAM_NAME = \"Footprint Editor\"\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# getting icons ready for compound menu\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)  # menu begins\n\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N',\n                      compound='left', image=new_file_icon, underline=0)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O',\n                      compound='left', image=open_file_icon, underline=0)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0)\nfile_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S')\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4')\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0, accelerator='Ctrl+F')\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7, accelerator='Ctrl+A')\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\n# View menu-items displays some variations\n# so we tackle view menu code to be entered here in a later section\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About')\nabout_menu.add_command(label='Help')\nmenu_bar.add_cascade(label='About',  menu=about_menu)\n\nroot.config(menu=menu_bar)  # menu ends\n\n# add top shortcut bar & left line number bar\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\n\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\n\n# add the main content Text widget and Scrollbar widget\ncontent_text = Text(root, wrap='word')\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.03.py",
    "content": "\"\"\"\nCode illustration: 2.03\n\nAdding View Menu Items to demonstrate\nother Types of Menu Items\n    1. Checkbutton menu-item\n    2. Radiobutton menu-item\n    3. Cascade menu-item\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar\n\n\nPROGRAM_NAME = \"Footprint Editor\"\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N',\n                      compound='left', image=new_file_icon, underline=0)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O',\n                      compound='left', image=open_file_icon, underline=0)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0)\nfile_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S')\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4')\nmenu_bar.add_cascade(label='File', menu=file_menu)\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0, accelerator='Ctrl+F')\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7, accelerator='Ctrl+A')\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n##\n# Implementing Checkbutton, Radiobutton and Cascade menu-items under View Menu in this iteration\n##\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nhighlight_line = IntVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=highlight_line)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\n\"\"\"\ncolor scheme is defined with dictionary elements like -\n        theme_name : foreground_color.background_color\n\"\"\"\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\n\n#\n# End of View menu implementation in this iteration\n#\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About')\nabout_menu.add_command(label='Help')\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word')\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.04.py",
    "content": "\"\"\"\nCode illustration: 2.04\n\nleveraging Text widget built-in options for\n    1. Cut\n    2. Copy\n    3. Paste\n    4. Undo\n    5. Redo\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar\n\nPROGRAM_NAME = \"Footprint Editor\"\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# Adding Text Widget Built-in Functionality\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    return 'break'\n\n# end of this iteration\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N',\n                      compound='left', image=new_file_icon, underline=0)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O',\n                      compound='left', image=open_file_icon, underline=0)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0)\nfile_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S')\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4')\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0, accelerator='Ctrl+F')\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7, accelerator='Ctrl+A')\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nhighlight_line = IntVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=highlight_line)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About')\nabout_menu.add_command(label='Help')\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\n# handling redo quirk\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.05.py",
    "content": "\"\"\"\nCode illustration: 2.05\n\nText Widget Indexing and Tagging explained using\nimplementation of:\n    1. select_all\n    2. find_text\n\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar\n\nPROGRAM_NAME = \"Footprint Editor\"\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# Implementing select_all and find_text functions\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Tk.Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n    search_toplevel.resizable(False, False)\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                                   nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N',\n                      compound='left', image=new_file_icon, underline=0)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O',\n                      compound='left', image=open_file_icon, underline=0)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0)\nfile_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S')\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4')\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nhighlight_line = IntVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=highlight_line)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About')\nabout_menu.add_command(label='Help')\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\n\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.06.py",
    "content": "\"\"\"\nCode illustration: 2.06\nA demonstration of different types of top-level window\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nfrom tkinter import Tk, Label, Toplevel\n\nroot = Tk()\n\n# top level window\nroot.title('Toplevel Window')\nroot.geometry('300x300')\nLabel(root, text='I am the Main Toplevel window\\n All other windows here are my children').pack()\n\n\n# child toplevel\nchild_toplevel = Toplevel(root)\nLabel(child_toplevel, text='I am a child of root\\n If i loose focus, I may hide below the top level, \\n I am destroyed, if root is destroyed').pack()\nchild_toplevel.geometry('400x100+300+300')\n\n\n# transient window\ntransient_toplevel = Toplevel(root)\nLabel(transient_toplevel, text='I am a transient window of root\\n I always stay on top of my parent\\n I get hidden if my parent window is minimized').pack()\ntransient_toplevel.transient(root)\n\n\n# no window decoration\nno_window_decoration = Toplevel(root, bg='black')\nLabel(no_window_decoration, text='I am a top-level with no window manager\\n I cannot be resized or moved',\n      bg='black', fg='white').pack()\nno_window_decoration.overrideredirect(1)\nno_window_decoration.geometry('250x100+700+500')\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.07.py",
    "content": "\"\"\"\nCode illustration: 2.07\n\nAdding features:\n    File > New\n    File > Open\n    File > Save\n    File > Save As\n\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar, END\n\nimport tkinter.filedialog\n\n\nPROGRAM_NAME = \"Footprint Editor\"\nfile_name = None\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# new_file, open_file, save, save_as implementation\n\n\ndef new_file(event=None):\n    root.title(\"Untitled\")\n    global file_name\n    file_name = None\n    content_text.delete(1.0, END)\n\n\ndef open_file(event=None):\n    input_file_name = tkinter.filedialog.askopenfilename(defaultextension=\".txt\",\n                                                         filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n        content_text.delete(1.0, END)\n        with open(file_name) as _file:\n            content_text.insert(1.0, _file.read())\n\n\ndef write_to_file(file_name):\n    try:\n        content = content_text.get(1.0, 'end')\n        with open(file_name, 'w') as the_file:\n            the_file.write(content)\n    except IOError:\n        pass  # in actual we will show a error message box.\n        # we discuss message boxes in the next section so ignored here.\n\n\ndef save_as(event=None):\n    input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension=\".txt\",\n                                                           filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        write_to_file(file_name)\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n    return \"break\"\n\n\ndef save(event=None):\n    global file_name\n    if not file_name:\n        save_as()\n    else:\n        write_to_file(file_name)\n    return \"break\"\n\n# End of iteration\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n    search_toplevel.resizable(False, False)\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                            nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N', compound='left',\n                      image=new_file_icon, underline=0, command=new_file)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left',\n                      image=open_file_icon, underline=0, command=open_file)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0, command=save)\nfile_menu.add_command(\n    label='Save as', accelerator='Shift+Ctrl+S', command=save_as)\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4')\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nhighlight_line = IntVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=highlight_line)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About')\nabout_menu.add_command(label='Help')\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\n# Shortcut key bindings for this iteration\ncontent_text.bind('<Control-N>', new_file)\ncontent_text.bind('<Control-n>', new_file)\ncontent_text.bind('<Control-O>', open_file)\ncontent_text.bind('<Control-o>', open_file)\ncontent_text.bind('<Control-S>', save)\ncontent_text.bind('<Control-s>', save)\n# Iteration ends\n\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.08.py",
    "content": "\"\"\"\nCode illustration: 2.08\nA demonstration of tkinter.messagebox\nshowinfo\nshowwarning\nshowerror\naskquestion\naskokcancel\naskyesno\naskyesnocancel\naskretrycancel\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nfrom tkinter import Tk, Frame, Label, Button, BOTH, LEFT\n\nimport tkinter.messagebox as tmb\n\nroot = Tk()\n\nfr1 = Frame(root)\nfr2 = Frame(root)\nopt = {'fill': BOTH, 'side': LEFT, 'padx': 2, 'pady': 3}\n\n\n# Demo of tkinter.messagebox\nLabel(fr1, text=\"Demo of tkinter.messagebox\").pack()\nButton(fr1, text='info', command=lambda: tmb.showinfo(\n    \"Show Info\", \"This is FYI\")).pack(opt)\nButton(fr1, text='warning', command=lambda: tmb.showwarning(\n    \"Show Warning\", \"Don't be silly\")).pack(opt)\nButton(fr1, text='error', command=lambda: tmb.showerror(\n    \"Show Error\", \"It leaked\")).pack(opt)\nButton(fr1, text='question', command=lambda: tmb.askquestion(\n    \"Ask Question\", \"Can you read this ?\")).pack(opt)\nButton(fr2, text='okcancel', command=lambda: tmb.askokcancel(\n    \"Ask OK Cancel\", \"Say Ok or Cancel?\")).pack(opt)\nButton(fr2, text='yesno', command=lambda: tmb.askyesno(\n    \"Ask Yes-No\", \"Say yes or no?\")).pack(opt)\nButton(fr2, text='yesnocancel', command=lambda: tmb.askyesnocancel(\n    \"Yes-No-Cancel\", \"Say yes no cancel\")).pack(opt)\nButton(fr2, text='retrycancel', command=lambda: tmb.askretrycancel(\n    \"Ask Retry Cancel\", \"Retry or what?\")).pack(opt)\n\n\nfr1.pack()\nfr2.pack()\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.09.py",
    "content": "\"\"\"\nCode illustration: 2.09\n\nAdding:\n    About, Help Message Box\n    'Really Quit ?' Prompt  to exit button\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar, END\n\nimport tkinter.filedialog\nimport tkinter.messagebox\n\nPROGRAM_NAME = \"Footprint Editor\"\nfile_name = None\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# about, help and exit messagebox\n\n\ndef display_about_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"About\", PROGRAM_NAME + \"\\nTkinter GUI Application\\n Development Blueprints\")\n\n\ndef display_help_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"Help\", \"Help Book: \\nTkinter GUI Application\\n Development Blueprints\",\n        icon='question')\n\n\ndef exit_editor(event=None):\n    if tkinter.messagebox.askokcancel(\"Quit?\", \"Really quit?\"):\n        root.destroy()\n\n# keyboard shortcut for help added towards the last of this program\n# iteration ends\n\n\ndef new_file(event=None):\n    root.title(\"Untitled\")\n    global file_name\n    file_name = None\n    content_text.delete(1.0, END)\n\n\ndef open_file(event=None):\n    input_file_name = tkinter.filedialog.askopenfilename(defaultextension=\".txt\",\n                                                         filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n        content_text.delete(1.0, END)\n        with open(file_name) as _file:\n            content_text.insert(1.0, _file.read())\n\n\ndef write_to_file(file_name):\n    try:\n        content = content_text.get(1.0, 'end')\n        with open(file_name, 'w') as the_file:\n            the_file.write(content)\n    except IOError:\n        tkinter.messagebox.showwarning(\"Save\", \"Could not save the file.\")\n\n\ndef save_as(event=None):\n    input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension=\".txt\",\n                                                           filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        write_to_file(file_name)\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n    return \"break\"\n\ndef save(event=None):\n    global file_name\n    if not file_name:\n        save_as()\n    else:\n        write_to_file(file_name)\n    return \"break\"\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n    search_toplevel.resizable(False, False)\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                                   nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N', compound='left',\n                      image=new_file_icon, underline=0, command=new_file)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left',\n                      image=open_file_icon, underline=0, command=open_file)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0, command=save)\nfile_menu.add_command(\n    label='Save as', accelerator='Shift+Ctrl+S', command=save_as)\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4', command=exit_editor)\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nhighlight_line = IntVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=highlight_line)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About', command=display_about_messagebox)\nabout_menu.add_command(label='Help', command=display_help_messagebox)\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25, background='light sea green')\nshortcut_bar.pack(expand='no', fill='x')\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\n# added keyboard shortcut for help\ncontent_text.bind('<KeyPress-F1>', display_help_messagebox)\n# ends\n\n\ncontent_text.bind('<Control-N>', new_file)\ncontent_text.bind('<Control-n>', new_file)\ncontent_text.bind('<Control-O>', open_file)\ncontent_text.bind('<Control-o>', open_file)\ncontent_text.bind('<Control-S>', save)\ncontent_text.bind('<Control-s>', save)\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\n\nroot.protocol('WM_DELETE_WINDOW', exit_editor)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.10.py",
    "content": "\"\"\"\nCode illustration: 2.10\n\nAdding Shortcut Icons toolbar\nDisplaying Line Numbers\nHighlighting Current Line\n\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport os\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar, BooleanVar, Button, END\nimport tkinter.filedialog\nimport tkinter.messagebox\n\nPROGRAM_NAME = \"Footprint Editor\"\nfile_name = None\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n\ndef update_line_numbers(event=None):\n    line_numbers = get_line_numbers()\n    line_number_bar.config(state='normal')\n    line_number_bar.delete('1.0', 'end')\n    line_number_bar.insert('1.0', line_numbers)\n    line_number_bar.config(state='disabled')\n\n\ndef highlight_line(interval=100):\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n    content_text.tag_add(\n        \"active_line\", \"insert linestart\", \"insert lineend+1c\")\n    content_text.after(interval, toggle_highlight)\n\n\ndef undo_highlight():\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n\n\ndef toggle_highlight(event=None):\n    if to_highlight_line.get():\n        highlight_line()\n    else:\n        undo_highlight()\n\n\ndef on_content_changed(event=None):\n    update_line_numbers()\n\n\ndef get_line_numbers():\n    output = ''\n    if show_line_number.get():\n        row, col = content_text.index(\"end\").split('.')\n        for i in range(1, int(row)):\n            output += str(i) + '\\n'\n    return output\n\n\ndef display_about_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"About\", PROGRAM_NAME + \"\\nTkinter GUI Application\\n Development Blueprints\")\n\n\ndef display_help_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"Help\", \"Help Book: \\nTkinter GUI Application\\n Development Blueprints\",\n        icon='question')\n\n\ndef exit_editor(event=None):\n    if tkinter.messagebox.askokcancel(\"Quit?\", \"Really quit?\"):\n        root.destroy()\n\n\ndef new_file(event=None):\n    root.title(\"Untitled\")\n    global file_name\n    file_name = None\n    content_text.delete(1.0, END)\n    on_content_changed()\n\n\ndef open_file(event=None):\n    input_file_name = tkinter.filedialog.askopenfilename(defaultextension=\".txt\",\n                                                         filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n        content_text.delete(1.0, END)\n        with open(file_name) as _file:\n            content_text.insert(1.0, _file.read())\n    on_content_changed()\n\n\ndef write_to_file(file_name):\n    try:\n        content = content_text.get(1.0, 'end')\n        with open(file_name, 'w') as the_file:\n            the_file.write(content)\n    except IOError:\n        tkinter.messagebox.showwarning(\"Save\", \"Could not save the file.\")\n\n\ndef save_as(event=None):\n    input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension=\".txt\",\n                                                           filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        write_to_file(file_name)\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n    return \"break\"\n\ndef save(event=None):\n    global file_name\n    if not file_name:\n        save_as()\n    else:\n        write_to_file(file_name)\n    return \"break\"\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n    search_toplevel.resizable(False, False)\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                                   nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    on_content_changed()\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N', compound='left',\n                      image=new_file_icon, underline=0, command=new_file)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left',\n                      image=open_file_icon, underline=0, command=open_file)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0, command=save)\nfile_menu.add_command(\n    label='Save as', accelerator='Shift+Ctrl+S', command=save_as)\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4', command=exit_editor)\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number,\n                          command=update_line_numbers)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info)\nto_highlight_line = BooleanVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=to_highlight_line, command=toggle_highlight)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(label=k, variable=theme_choice)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About', command=display_about_messagebox)\nabout_menu.add_command(label='Help', command=display_help_messagebox)\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25)\nshortcut_bar.pack(expand='no', fill='x')\n\n# adding shortcut icons\nicons = ('new_file', 'open_file', 'save', 'cut', 'copy', 'paste',\n         'undo', 'redo', 'find_text')\nfor i, icon in enumerate(icons):\n    tool_bar_icon = PhotoImage(file='icons/{}.gif'.format(icon))\n    cmd = eval(icon)\n    tool_bar = Button(shortcut_bar, image=tool_bar_icon, command=cmd)\n    tool_bar.image = tool_bar_icon\n    tool_bar.pack(side='left')\n\n\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\ncontent_text.bind('<KeyPress-F1>', display_help_messagebox)\ncontent_text.bind('<Control-N>', new_file)\ncontent_text.bind('<Control-n>', new_file)\ncontent_text.bind('<Control-O>', open_file)\ncontent_text.bind('<Control-o>', open_file)\ncontent_text.bind('<Control-S>', save)\ncontent_text.bind('<Control-s>', save)\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\n\n# added in this iteration\ncontent_text.bind('<Any-KeyPress>', on_content_changed)\ncontent_text.tag_configure('active_line', background='ivory2')\n###\n\nroot.protocol('WM_DELETE_WINDOW', exit_editor)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.11.py",
    "content": "\"\"\"\nCode illustration: 2.11\n\nAdding cursor location info at bottom\nAdding Color Theme\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar, BooleanVar, Button, END, Label, INSERT\nimport tkinter.filedialog\nimport tkinter.messagebox\n\nPROGRAM_NAME = \"Footprint Editor\"\nfile_name = None\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# show cursor info at bottom\n\n\ndef show_cursor_info_bar():\n    show_cursor_info_checked = show_cursor_info.get()\n    if show_cursor_info_checked:\n        cursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')\n    else:\n        cursor_info_bar.pack_forget()\n\n\ndef update_cursor_info_bar(event=None):\n    row, col = content_text.index(INSERT).split('.')\n    line_num, col_num = str(int(row)), str(int(col) + 1)  # col starts at 0\n    infotext = \"Line: {0} | Column: {1}\".format(line_num, col_num)\n    cursor_info_bar.config(text=infotext)\n\n\n# change themes\ndef change_theme(event=None):\n    selected_theme = theme_choice.get()\n    fg_bg_colors = color_schemes.get(selected_theme)\n    foreground_color, background_color = fg_bg_colors.split('.')\n    content_text.config(\n        background=background_color, fg=foreground_color)\n\n\ndef update_line_numbers(event=None):\n    line_numbers = get_line_numbers()\n    line_number_bar.config(state='normal')\n    line_number_bar.delete('1.0', 'end')\n    line_number_bar.insert('1.0', line_numbers)\n    line_number_bar.config(state='disabled')\n\n\ndef highlight_line(interval=100):\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n    content_text.tag_add(\n        \"active_line\", \"insert linestart\", \"insert lineend+1c\")\n    content_text.after(interval, toggle_highlight)\n\n\ndef undo_highlight():\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n\ndef toggle_highlight(event=None):\n    if to_highlight_line.get():\n        highlight_line()\n    else:\n        undo_highlight()\n\ndef on_content_changed(event=None):\n    update_line_numbers()\n    update_cursor_info_bar()\n\n\ndef get_line_numbers():\n    output = ''\n    if show_line_number.get():\n        row, col = content_text.index(\"end\").split('.')\n        for i in range(1, int(row)):\n            output += str(i) + '\\n'\n    return output\n\n\ndef update_line_numbers(event=None):\n    line_numbers = get_line_numbers()\n    line_number_bar.config(state='normal')\n    line_number_bar.delete('1.0', 'end')\n    line_number_bar.insert('1.0', line_numbers)\n    line_number_bar.config(state='disabled')\n\n\ndef display_about_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"About\", PROGRAM_NAME + \"\\nTkinter GUI Application\\n Development Blueprints\")\n\n\ndef display_help_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"Help\", \"Help Book: \\nTkinter GUI Application\\n Development Blueprints\",\n        icon='question')\n\n\ndef exit_editor(event=None):\n    if tkinter.messagebox.askokcancel(\"Quit?\", \"Really quit?\"):\n        root.destroy()\n\n\ndef new_file(event=None):\n    root.title(\"Untitled\")\n    global file_name\n    file_name = None\n    content_text.delete(1.0, END)\n    on_content_changed()\n\n\ndef open_file(event=None):\n    input_file_name = tkinter.filedialog.askopenfilename(defaultextension=\".txt\",\n                                                         filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n        content_text.delete(1.0, END)\n        with open(file_name) as _file:\n            content_text.insert(1.0, _file.read())\n    on_content_changed()\n\n\ndef write_to_file(file_name):\n    try:\n        content = content_text.get(1.0, 'end')\n        with open(file_name, 'w') as the_file:\n            the_file.write(content)\n    except IOError:\n        tkinter.messagebox.showwarning(\"Save\", \"Could not save the file.\")\n\n\ndef save_as(event=None):\n    input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension=\".txt\",\n                                                           filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        write_to_file(file_name)\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n    return \"break\"\n\ndef save(event=None):\n    global file_name\n    if not file_name:\n        save_as()\n    else:\n        write_to_file(file_name)\n    return \"break\"\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n    search_toplevel.resizable(False, False)\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                            nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    on_content_changed()\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N', compound='left',\n                      image=new_file_icon, underline=0, command=new_file)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left',\n                      image=open_file_icon, underline=0, command=open_file)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0, command=save)\nfile_menu.add_command(\n    label='Save as', accelerator='Shift+Ctrl+S', command=save_as)\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4', command=exit_editor)\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number,\n                          command=update_line_numbers)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info, command=show_cursor_info_bar)\nto_highlight_line = BooleanVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=to_highlight_line, command=toggle_highlight)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(\n        label=k, variable=theme_choice, command=change_theme)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About', command=display_about_messagebox)\nabout_menu.add_command(label='Help', command=display_help_messagebox)\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25)\nshortcut_bar.pack(expand='no', fill='x')\n\nicons = ('new_file', 'open_file', 'save', 'cut', 'copy', 'paste',\n         'undo', 'redo', 'find_text')\nfor i, icon in enumerate(icons):\n    tool_bar_icon = PhotoImage(file='icons/{}.gif'.format(icon))\n    cmd = eval(icon)\n    tool_bar = Button(shortcut_bar, image=tool_bar_icon, command=cmd)\n    tool_bar.image = tool_bar_icon\n    tool_bar.pack(side='left')\n\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\n\n# add cursor info label\ncursor_info_bar = Label(content_text, text='Line: 1 | Column: 1')\ncursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')\n\n\ncontent_text.bind('<KeyPress-F1>', display_help_messagebox)\ncontent_text.bind('<Control-N>', new_file)\ncontent_text.bind('<Control-n>', new_file)\ncontent_text.bind('<Control-O>', open_file)\ncontent_text.bind('<Control-o>', open_file)\ncontent_text.bind('<Control-S>', save)\ncontent_text.bind('<Control-s>', save)\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\ncontent_text.bind('<Any-KeyPress>', on_content_changed)\ncontent_text.tag_configure('active_line', background='ivory2')\n\nroot.protocol('WM_DELETE_WINDOW', exit_editor)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/2.12.py",
    "content": "\"\"\"\nCode illustration: 2.12.py\nFeatures Added:\n    Add context/ Pop-up Menu\n    Set focus on launch\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport os\nfrom tkinter import Tk, PhotoImage, Menu, Frame, Text, Scrollbar, IntVar, \\\n    StringVar, BooleanVar, Button, END, Label, INSERT\nimport tkinter.filedialog\nimport tkinter.messagebox\n\nPROGRAM_NAME = \"Footprint Editor\"\nfile_name = None\n\nroot = Tk()\nroot.geometry('350x350')\nroot.title(PROGRAM_NAME)\n\n# show pop-up menu\n\n\ndef show_popup_menu(event):\n    popup_menu.tk_popup(event.x_root, event.y_root)\n\n\ndef show_cursor_info_bar():\n    show_cursor_info_checked = show_cursor_info.get()\n    if show_cursor_info_checked:\n        cursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')\n    else:\n        cursor_info_bar.pack_forget()\n\n\ndef update_cursor_info_bar(event=None):\n    row, col = content_text.index(INSERT).split('.')\n    line_num, col_num = str(int(row)), str(int(col) + 1)  # col starts at 0\n    infotext = \"Line: {0} | Column: {1}\".format(line_num, col_num)\n    cursor_info_bar.config(text=infotext)\n\n\ndef change_theme(event=None):\n    selected_theme = theme_choice.get()\n    fg_bg_colors = color_schemes.get(selected_theme)\n    foreground_color, background_color = fg_bg_colors.split('.')\n    content_text.config(\n        background=background_color, fg=foreground_color)\n\n\ndef update_line_numbers(event=None):\n    line_numbers = get_line_numbers()\n    line_number_bar.config(state='normal')\n    line_number_bar.delete('1.0', 'end')\n    line_number_bar.insert('1.0', line_numbers)\n    line_number_bar.config(state='disabled')\n\n\ndef highlight_line(interval=100):\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n    content_text.tag_add(\n        \"active_line\", \"insert linestart\", \"insert lineend+1c\")\n    content_text.after(interval, toggle_highlight)\n\n\ndef undo_highlight():\n    content_text.tag_remove(\"active_line\", 1.0, \"end\")\n\n\ndef toggle_highlight(event=None):\n    if to_highlight_line.get():\n        highlight_line()\n    else:\n        undo_highlight()\n\n\ndef on_content_changed(event=None):\n    update_line_numbers()\n    update_cursor_info_bar()\n\n\ndef get_line_numbers():\n    output = ''\n    if show_line_number.get():\n        row, col = content_text.index(\"end\").split('.')\n        for i in range(1, int(row)):\n            output += str(i) + '\\n'\n    return output\n\n\ndef display_about_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"About\", \"{}{}\".format(PROGRAM_NAME, \"\\nTkinter GUI Application\\n Development Blueprints\"))\n\n\ndef display_help_messagebox(event=None):\n    tkinter.messagebox.showinfo(\n        \"Help\", \"Help Book: \\nTkinter GUI Application\\n Development Blueprints\",\n        icon='question')\n\n\ndef exit_editor(event=None):\n    if tkinter.messagebox.askokcancel(\"Quit?\", \"Really quit?\"):\n        root.destroy()\n\n\ndef new_file(event=None):\n    root.title(\"Untitled\")\n    global file_name\n    file_name = None\n    content_text.delete(1.0, END)\n    on_content_changed()\n\n\ndef open_file(event=None):\n    input_file_name = tkinter.filedialog.askopenfilename(defaultextension=\".txt\",\n                                                         filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n        content_text.delete(1.0, END)\n        with open(file_name) as _file:\n            content_text.insert(1.0, _file.read())\n        on_content_changed()\n\n\ndef write_to_file(file_name):\n    try:\n        content = content_text.get(1.0, 'end')\n        with open(file_name, 'w') as the_file:\n            the_file.write(content)\n    except IOError:\n        tkinter.messagebox.showwarning(\"Save\", \"Could not save the file.\")\n\n\ndef save_as(event=None):\n    input_file_name = tkinter.filedialog.asksaveasfilename(defaultextension=\".txt\",\n                                                           filetypes=[(\"All Files\", \"*.*\"), (\"Text Documents\", \"*.txt\")])\n    if input_file_name:\n        global file_name\n        file_name = input_file_name\n        write_to_file(file_name)\n        root.title('{} - {}'.format(os.path.basename(file_name), PROGRAM_NAME))\n    return \"break\"\n\n\ndef save(event=None):\n    global file_name\n    if not file_name:\n        save_as()\n    else:\n        write_to_file(file_name)\n    return \"break\"\n\n\ndef select_all(event=None):\n    content_text.tag_add('sel', '1.0', 'end')\n    return \"break\"\n\n\ndef find_text(event=None):\n    search_toplevel = Toplevel(root)\n    search_toplevel.title('Find Text')\n    search_toplevel.transient(root)\n\n    Label(search_toplevel, text=\"Find All:\").grid(row=0, column=0, sticky='e')\n\n    search_entry_widget = Entry(\n        search_toplevel, width=25)\n    search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')\n    search_entry_widget.focus_set()\n    ignore_case_value = IntVar()\n    Checkbutton(search_toplevel, text='Ignore Case', variable=ignore_case_value).grid(\n        row=1, column=1, sticky='e', padx=2, pady=2)\n    Button(search_toplevel, text=\"Find All\", underline=0,\n           command=lambda: search_output(\n               search_entry_widget.get(), ignore_case_value.get(),\n               content_text, search_toplevel, search_entry_widget)\n           ).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)\n\n    def close_search_window():\n        content_text.tag_remove('match', '1.0', END)\n        search_toplevel.destroy()\n    search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)\n    return \"break\"\n\n\ndef search_output(needle, if_ignore_case, content_text,\n                  search_toplevel, search_box):\n    content_text.tag_remove('match', '1.0', END)\n    matches_found = 0\n    if needle:\n        start_pos = '1.0'\n        while True:\n            start_pos = content_text.search(needle, start_pos,\n                                            nocase=if_ignore_case, stopindex=END)\n            if not start_pos:\n                break\n            end_pos = '{}+{}c'.format(start_pos, len(needle))\n            content_text.tag_add('match', start_pos, end_pos)\n            matches_found += 1\n            start_pos = end_pos\n        content_text.tag_config(\n            'match', foreground='red', background='yellow')\n    search_box.focus_set()\n    search_toplevel.title('{} matches found'.format(matches_found))\n\n\ndef cut():\n    content_text.event_generate(\"<<Cut>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef copy():\n    content_text.event_generate(\"<<Copy>>\")\n    return \"break\"\n\n\ndef paste():\n    content_text.event_generate(\"<<Paste>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef undo():\n    content_text.event_generate(\"<<Undo>>\")\n    on_content_changed()\n    return \"break\"\n\n\ndef redo(event=None):\n    content_text.event_generate(\"<<Redo>>\")\n    on_content_changed()\n    return 'break'\n\nnew_file_icon = PhotoImage(file='icons/new_file.gif')\nopen_file_icon = PhotoImage(file='icons/open_file.gif')\nsave_file_icon = PhotoImage(file='icons/save.gif')\ncut_icon = PhotoImage(file='icons/cut.gif')\ncopy_icon = PhotoImage(file='icons/copy.gif')\npaste_icon = PhotoImage(file='icons/paste.gif')\nundo_icon = PhotoImage(file='icons/undo.gif')\nredo_icon = PhotoImage(file='icons/redo.gif')\n\nmenu_bar = Menu(root)\nfile_menu = Menu(menu_bar, tearoff=0)\nfile_menu.add_command(label='New', accelerator='Ctrl+N', compound='left',\n                      image=new_file_icon, underline=0, command=new_file)\nfile_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left',\n                      image=open_file_icon, underline=0, command=open_file)\nfile_menu.add_command(label='Save', accelerator='Ctrl+S',\n                      compound='left', image=save_file_icon, underline=0, command=save)\nfile_menu.add_command(\n    label='Save as', accelerator='Shift+Ctrl+S', command=save_as)\nfile_menu.add_separator()\nfile_menu.add_command(label='Exit', accelerator='Alt+F4', command=exit_editor)\nmenu_bar.add_cascade(label='File', menu=file_menu)\n\nedit_menu = Menu(menu_bar, tearoff=0)\nedit_menu.add_command(label='Undo', accelerator='Ctrl+Z',\n                      compound='left', image=undo_icon, command=undo)\nedit_menu.add_command(label='Redo', accelerator='Ctrl+Y',\n                      compound='left', image=redo_icon, command=redo)\nedit_menu.add_separator()\nedit_menu.add_command(label='Cut', accelerator='Ctrl+X',\n                      compound='left', image=cut_icon, command=cut)\nedit_menu.add_command(label='Copy', accelerator='Ctrl+C',\n                      compound='left', image=copy_icon, command=copy)\nedit_menu.add_command(label='Paste', accelerator='Ctrl+V',\n                      compound='left', image=paste_icon, command=paste)\nedit_menu.add_separator()\nedit_menu.add_command(label='Find', underline=0,\n                      accelerator='Ctrl+F', command=find_text)\nedit_menu.add_separator()\nedit_menu.add_command(label='Select All', underline=7,\n                      accelerator='Ctrl+A', command=select_all)\nmenu_bar.add_cascade(label='Edit', menu=edit_menu)\n\n\nview_menu = Menu(menu_bar, tearoff=0)\nshow_line_number = IntVar()\nshow_line_number.set(1)\nview_menu.add_checkbutton(label='Show Line Number', variable=show_line_number,\n                          command=update_line_numbers)\nshow_cursor_info = IntVar()\nshow_cursor_info.set(1)\nview_menu.add_checkbutton(\n    label='Show Cursor Location at Bottom', variable=show_cursor_info, command=show_cursor_info_bar)\nto_highlight_line = BooleanVar()\nview_menu.add_checkbutton(label='Highlight Current Line', onvalue=1,\n                          offvalue=0, variable=to_highlight_line, command=toggle_highlight)\nthemes_menu = Menu(menu_bar, tearoff=0)\nview_menu.add_cascade(label='Themes', menu=themes_menu)\n\ncolor_schemes = {\n    'Default': '#000000.#FFFFFF',\n    'Greygarious': '#83406A.#D1D4D1',\n    'Aquamarine': '#5B8340.#D1E7E0',\n    'Bold Beige': '#4B4620.#FFF0E1',\n    'Cobalt Blue': '#ffffBB.#3333aa',\n    'Olive Green': '#D1E7E0.#5B8340',\n    'Night Mode': '#FFFFFF.#000000',\n}\n\ntheme_choice = StringVar()\ntheme_choice.set('Default')\nfor k in sorted(color_schemes):\n    themes_menu.add_radiobutton(\n        label=k, variable=theme_choice, command=change_theme)\nmenu_bar.add_cascade(label='View', menu=view_menu)\n\nabout_menu = Menu(menu_bar, tearoff=0)\nabout_menu.add_command(label='About', command=display_about_messagebox)\nabout_menu.add_command(label='Help', command=display_help_messagebox)\nmenu_bar.add_cascade(label='About',  menu=about_menu)\nroot.config(menu=menu_bar)\n\nshortcut_bar = Frame(root,  height=25)\nshortcut_bar.pack(expand='no', fill='x')\n\nicons = ('new_file', 'open_file', 'save', 'cut', 'copy', 'paste',\n         'undo', 'redo', 'find_text')\nfor i, icon in enumerate(icons):\n    tool_bar_icon = PhotoImage(file='icons/{}.gif'.format(icon))\n    cmd = eval(icon)\n    tool_bar = Button(shortcut_bar, image=tool_bar_icon, command=cmd)\n    tool_bar.image = tool_bar_icon\n    tool_bar.pack(side='left')\n\nline_number_bar = Text(root, width=4, padx=3, takefocus=0,  border=0,\n                       background='khaki', state='disabled',  wrap='none')\nline_number_bar.pack(side='left',  fill='y')\n\ncontent_text = Text(root, wrap='word', undo=1)\ncontent_text.pack(expand='yes', fill='both')\nscroll_bar = Scrollbar(content_text)\ncontent_text.configure(yscrollcommand=scroll_bar.set)\nscroll_bar.config(command=content_text.yview)\nscroll_bar.pack(side='right', fill='y')\ncursor_info_bar = Label(content_text, text='Line: 1 | Column: 1')\ncursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')\n\n\ncontent_text.bind('<KeyPress-F1>', display_help_messagebox)\ncontent_text.bind('<Control-N>', new_file)\ncontent_text.bind('<Control-n>', new_file)\ncontent_text.bind('<Control-O>', open_file)\ncontent_text.bind('<Control-o>', open_file)\ncontent_text.bind('<Control-S>', save)\ncontent_text.bind('<Control-s>', save)\ncontent_text.bind('<Control-f>', find_text)\ncontent_text.bind('<Control-F>', find_text)\ncontent_text.bind('<Control-A>', select_all)\ncontent_text.bind('<Control-a>', select_all)\ncontent_text.bind('<Control-y>', redo)\ncontent_text.bind('<Control-Y>', redo)\ncontent_text.bind('<Any-KeyPress>', on_content_changed)\ncontent_text.tag_configure('active_line', background='ivory2')\n\n# set up the pop-up menu\npopup_menu = Menu(content_text)\nfor i in ('cut', 'copy', 'paste', 'undo', 'redo'):\n    cmd = eval(i)\n    popup_menu.add_command(label=i, compound='left', command=cmd)\npopup_menu.add_separator()\npopup_menu.add_command(label='Select All', underline=7, command=select_all)\ncontent_text.bind('<Button-3>', show_popup_menu)\n\n\n# bind right mouse click to show pop up and set focus to text widget on launch\ncontent_text.bind('<Button-3>', show_popup_menu)\ncontent_text.focus_set()\n\nroot.protocol('WM_DELETE_WINDOW', exit_editor)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 02/readme.txt",
    "content": "====================================================================\nCode Readme\nTkinter GUI Application Development Blueprints\nChapter 2: Make a Text-Editor\n====================================================================\nList of code samples:-\n\n2.01:   Add top-level window/ Add menubuttons\n2.02:   Add menu-items within each menu button/ Add labels to hold shortcut toolbar and line number\n2.03 :  View Menu items - showing different types of menu items\n2.04:   Leveraging power of text widget built-in options\n2.05:   Indexing and tagging - implementation of 'select all' and 'find all'\n2.06:   A demonstration of different types of top-level window\n2.07:   Adding File>New,File>Open,File>Save and File>Save As functionality\n2.08:   A demonstration of tkMessageBox\n2.09:   Add About, Help & Quit Functionality\n2.10:   Add shortcut icon toolbar/ display line numbers/ highlight current line\n2.11:   Add infobar\n2.12:   Add contextual menu \n\n@author: Bhaskar Chaudahary\n@publisher: Packt Publishing \n"
  },
  {
    "path": "Chapter 03/3.01.py",
    "content": "\"\"\"\nCode illustration: 3.01\n    - Creating OOP Based GUI structure\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk\n\nPROGRAM_NAME = ' Explosion Drum Machine '\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.02.py",
    "content": "\"\"\"\nCode illustration: 3.02\n    - Defining & Initializing the Data Structure\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.init_all_patterns()\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.03.py",
    "content": "\"\"\"\nCode illustration: 3.03\n    Displaying All Visual Elements:\n\n        Methods newly defined and implemented here:\n            - init_gui()\n            - create_top_bar()\n            - create_left_drum_loader()\n            - create_right_button_matrix()\n            - create_play_bar()\n            - find_number_of_columns()\n            - display_button_color()\n            - display_all_button_colors()\n            - get_button_value()\n            - on_button_clicked()\n            - process_button_clicked()\n            - set_button_value()\n\n        Methods added as command callback, defined here but not yet implemented\n            - on_pattern_changed()\n            - on_number_of_units_changed()\n            - on_bpu_changed()\n            - on_open_file_button_clicked()\n            - on_button_clicked()\n            - on_play_button_clicked()\n            - on_stop_button_clicked()\n            - on_loop_button_toggled()\n            - on_beats_per_minute_changed()\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\n\"\"\"\nCode illustration: 3.12\n    applying ttk themes to our play button, stop button, loopbutton\n    adding separators\n\n        new imports here:\n            - from tkinter import ttk\n        methods modified here:\n            - create_play_bar()\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def on_pattern_changed(self):\n        pass\n\n    def on_number_of_units_changed(self):\n        pass\n\n    def on_bpu_changed(self):\n        pass\n\n    def on_open_file_button_clicked(self, drum_index):\n        pass\n\n    def on_play_button_clicked(self):\n        pass\n\n    def on_stop_button_clicked(self):\n        pass\n\n    def on_loop_button_toggled(self):\n        pass\n\n    def on_beats_per_minute_changed(self):\n        pass\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled, textvariable=True)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.04.py",
    "content": "\"\"\"\nCode illustration: 3.04\n    - Adding all the getter & setter methods for our data structure.\n            - get_current_pattern_dict()\n            - get_bpu()\n            - set_bpu()\n            - get_number_of_units()\n            - set_number_of_units()\n            - get_list_of_drum_files()\n            - get_drum_file_path(drum_index)\n            - set_drum_file_path(drum_index, file_path)\n            - get_is_button_clicked_list()\n            - set_is_button_clicked_list(num_of_rows, num_of_columns)\n            - get_beats_per_minute()\n            - set_beats_per_minute()\n    - Defining on_number_of_units_changed() method\n    - Defining  on_bpu_changed() method\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox\n\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def on_pattern_changed(self):\n        pass\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n\n    def on_open_file_button_clicked(self, drum_index):\n        pass\n\n    def on_play_button_clicked(self):\n        pass\n\n    def on_stop_button_clicked(self):\n        pass\n\n    def on_loop_button_toggled(self):\n        pass\n\n    def on_beats_per_minute_changed(self):\n        pass\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.05.py",
    "content": "\"\"\"\nCode illustration: 3.05\n    - Loading drum samples\n\n        New modules imported here:\n            - os, tkinter.filedialog\n\n        New methods implemented here\n            on_open_file_button_clicked():\n            display_all_drum_file_names():\n            display_drum_name():\n\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END\n\nfrom tkinter import filedialog\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def on_pattern_changed(self):\n        pass\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n\n    def on_play_button_clicked(self):\n        pass\n\n    def on_stop_button_clicked(self):\n        pass\n\n    def on_loop_button_toggled(self):\n        pass\n\n    def on_beats_per_minute_changed(self):\n        pass\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.06.py",
    "content": "\"\"\"\n               ****** Non reponsive warning ! ******\n    - This program becomes non responsive on playback of audio files.\n    - It is meant to be that way as a demonstration.\n    - You can close the program by stopping the python script\n                *************************************\n\nCode illustration: 3.06\n\n    Playing Audio\n        New Modules Imported Here\n            - import pygame\n            - import time\n\n        Attributes Added here:\n            - self.loop\n            - self.now_playing\n\n        New Methods defined here:\n            init_pygame()\n            play_sound()\n            start_play()\n            stop_play()\n            play_pattern()\n            time_to_play_each_column()\n            on_beats_per_minute_changed()\n            get_column_from_matrix()\n\n        Dummy Methods that existed earlier but modified here:\n            on_loop_button_toggled()\n            on_play_button_clicked()\n            on_stop_button_clicked()\n\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nimport time\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END, BooleanVar\nfrom tkinter import filedialog\nimport pygame\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.loop = True\n        self.now_playing = False\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def on_pattern_changed(self):\n        pass\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_play_button_clicked(self):\n        self.start_play()\n\n    def start_play(self):\n        self.init_pygame()\n        self.play_pattern()\n\n    def on_stop_button_clicked(self):\n        self.stop_play()\n\n    def stop_play(self):\n        self.now_playing = False\n\n    def init_pygame(self):\n        pygame.mixer.pre_init(44100, -16, 1, 512)\n        pygame.init()\n\n    def play_sound(self, sound_filename):\n        if sound_filename is not None:\n            pygame.mixer.Sound(sound_filename).play()\n\n    def get_column_from_matrix(self, matrix, i):\n        return [row[i] for row in matrix]\n\n\n    def play_pattern(self):\n        self.now_playing = True\n        while self.now_playing:\n            play_list = self.get_is_button_clicked_list()\n            num_columns = len(play_list[0])\n            for column_index in range(num_columns):\n                column_to_play = self.get_column_from_matrix(\n                      play_list, column_index)\n                for i, item in enumerate(column_to_play):\n                    if item:\n                        sound_filename = self.get_drum_file_path(i)\n                        self.play_sound(sound_filename)\n                time.sleep(self.time_to_play_each_column())\n                if not self.now_playing: break\n            if not self.loop: break\n        self.now_playing = False\n\n    def time_to_play_each_column(self):\n        beats_per_second = self.beats_per_minute / 60\n        time_to_play_each_column = 1 / beats_per_second\n        return time_to_play_each_column\n\n\n    def on_loop_button_toggled(self):\n        self.loop = self.loopbuttonvar.get()\n\n    def on_beats_per_minute_changed(self):\n        self.beats_per_minute = int(self.beats_per_minute_widget.get())\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbuttonvar = BooleanVar()\n        self.loopbuttonvar.set(True)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled, variable=self.loopbuttonvar)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.07.py",
    "content": "\"\"\"\nCode illustration: 3.07\n\n    Tkinter and Threading\n    **********************\n       New modules imported here:\n            - threading\n\n        New methods defined here:\n            - play_in_thread()\n            - toggle_play_button_state()\n\n        Method modified here:\n            - start_play()\n            - __init__ method - to override the close button\n            - on_play_button_clicked()\n            - on_stop_button_clicked()\n            - on_loop_button_toggled()\n            - play_pattern() - added a call to toggle_play_button_state()\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nimport time\nimport threading\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END, BooleanVar\nfrom tkinter import filedialog\nimport pygame\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.loop = True\n        self.now_playing = False\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def on_pattern_changed(self):\n        pass\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def play_in_thread(self):\n        self.thread = threading.Thread(target = self.play_pattern)\n        self.thread.start()\n\n\n    def on_play_button_clicked(self):\n        self.start_play()\n        self.toggle_play_button_state()\n\n    def start_play(self):\n        self.init_pygame()\n        self.play_in_thread()\n\n    def on_stop_button_clicked(self):\n        self.stop_play()\n        self.toggle_play_button_state()\n\n\n    def toggle_play_button_state(self):\n        if self.now_playing:\n            self.play_button.config(state=\"disabled\")\n        else:\n            self.play_button.config(state=\"normal\")\n\n    def exit_app(self):\n        self.now_playing = False\n        if messagebox.askokcancel(\"Quit\", \"Really quit?\"):\n            self.root.destroy()\n\n    def stop_play(self):\n        self.now_playing = False\n\n    def init_pygame(self):\n        pygame.mixer.pre_init(44100, -16, 1, 512)\n        pygame.init()\n\n    def play_sound(self, sound_filename):\n        if sound_filename is not None:\n            pygame.mixer.Sound(sound_filename).play()\n\n    def get_column_from_matrix(self, matrix, i):\n        return [row[i] for row in matrix]\n\n\n    def play_pattern(self):\n        self.now_playing = True\n        self.toggle_play_button_state()\n        while self.now_playing:\n            play_list = self.get_is_button_clicked_list()\n            num_columns = len(play_list[0])\n            for column_index in range(num_columns):\n                column_to_play = self.get_column_from_matrix(\n                      play_list, column_index)\n                for i, item in enumerate(column_to_play):\n                    if item:\n                        sound_filename = self.get_drum_file_path(i)\n                        self.play_sound(sound_filename)\n                time.sleep(self.time_to_play_each_column())\n                if not self.now_playing: break\n            if not self.loop: break\n        self.now_playing = False\n        self.toggle_play_button_state()\n\n    def time_to_play_each_column(self):\n        beats_per_second = self.beats_per_minute / 60\n        time_to_play_each_column = 1 / beats_per_second\n        return time_to_play_each_column\n\n\n    def on_loop_button_toggled(self):\n        self.loop = self.loopbuttonvar.get()\n\n    def on_beats_per_minute_changed(self):\n        self.beats_per_minute = int(self.beats_per_minute_widget.get())\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbuttonvar = BooleanVar()\n        self.loopbuttonvar.set(True)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled, variable=self.loopbuttonvar)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.08.py",
    "content": "\"\"\"\nCode illustration: 3.08\n\n    Adding support for multiple beat patterns\n\n        New methods added here:\n            - display_pattern_name()\n            - change_pattern()\n            - restart_play_of_new_pattern\n\n        Methods modified here:\n            - create_top_bar() - added a call to display_pattern_name()\n            - on_pattern_changed()\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nimport time\nimport threading\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END, BooleanVar\nfrom tkinter import filedialog\nimport pygame\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.loop = True\n        self.now_playing = False\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def display_pattern_name(self):\n        self.current_pattern_name_widget.config(state='normal')\n        self.current_pattern_name_widget.delete(0, 'end')\n        self.current_pattern_name_widget.insert(0,\n                                                'Pattern {}'.format(self.current_pattern_index))\n        self.current_pattern_name_widget.config(state='readonly')\n\n    def on_pattern_changed(self):\n        self.change_pattern()\n\n    def change_pattern(self):\n        self.current_pattern_index = int(self.pattern_index_widget.get())\n        self.display_pattern_name()\n        self.create_left_drum_loader()\n        self.display_all_drum_file_names()\n        self.create_right_button_matrix()\n        self.display_all_button_colors()\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def play_in_thread(self):\n        self.thread = threading.Thread(target = self.play_pattern)\n        self.thread.start()\n\n\n    def on_play_button_clicked(self):\n        self.start_play()\n        self.toggle_play_button_state()\n\n    def start_play(self):\n        self.init_pygame()\n        self.play_in_thread()\n\n    def on_stop_button_clicked(self):\n        self.stop_play()\n        self.toggle_play_button_state()\n\n\n    def toggle_play_button_state(self):\n        if self.now_playing:\n            self.play_button.config(state=\"disabled\")\n        else:\n            self.play_button.config(state=\"normal\")\n\n    def exit_app(self):\n        self.now_playing = False\n        if messagebox.askokcancel(\"Quit\", \"Really quit?\"):\n            self.root.destroy()\n\n    def stop_play(self):\n        self.now_playing = False\n\n    def init_pygame(self):\n        pygame.mixer.pre_init(44100, -16, 1, 512)\n        pygame.init()\n\n    def play_sound(self, sound_filename):\n        if sound_filename is not None:\n            pygame.mixer.Sound(sound_filename).play()\n\n    def get_column_from_matrix(self, matrix, i):\n        return [row[i] for row in matrix]\n\n\n    def play_pattern(self):\n        self.now_playing = True\n        self.toggle_play_button_state()\n        while self.now_playing:\n            play_list = self.get_is_button_clicked_list()\n            num_columns = len(play_list[0])\n            for column_index in range(num_columns):\n                column_to_play = self.get_column_from_matrix(\n                      play_list, column_index)\n                for i, item in enumerate(column_to_play):\n                    if item:\n                        sound_filename = self.get_drum_file_path(i)\n                        self.play_sound(sound_filename)\n                time.sleep(self.time_to_play_each_column())\n                if not self.now_playing: break\n            if not self.loop: break\n        self.now_playing = False\n        self.toggle_play_button_state()\n\n    def time_to_play_each_column(self):\n        beats_per_second = self.beats_per_minute / 60\n        time_to_play_each_column = 1 / beats_per_second\n        return time_to_play_each_column\n\n\n    def on_loop_button_toggled(self):\n        self.loop = self.loopbuttonvar.get()\n\n    def on_beats_per_minute_changed(self):\n        self.beats_per_minute = int(self.beats_per_minute_widget.get())\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbuttonvar = BooleanVar()\n        self.loopbuttonvar.set(True)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled, variable=self.loopbuttonvar)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n        self.display_pattern_name()\n\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(label=\"Load Project\")\n        self.file_menu.add_command(label=\"Save Project\")\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\")\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\")\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.09.py",
    "content": "\"\"\"\nCode illustration: 3.09\n    Saving Drum Patterns | Object Persistence: pickling and unpickling\n\n        New modules imported here:\n            - pickle\n\n        New methods created here:\n            - load_project()\n            - save_project()\n            - reconstruct_first_pattern()\n            - show_about()\n\n        Methods modified here:\n            - create_top_menu() added command callback to load_project and save_project\n\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nimport time\nimport pickle\nimport threading\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END, BooleanVar, messagebox\nfrom tkinter import filedialog\nimport pygame\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.current_pattern_index = 0\n        self.loop = True\n        self.now_playing = False\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.init_all_patterns()\n        self.init_gui()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n\n\n    #\n    # getters and setters begins\n    #\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def display_pattern_name(self):\n        self.current_pattern_name_widget.config(state='normal')\n        self.current_pattern_name_widget.delete(0, 'end')\n        self.current_pattern_name_widget.insert(0,\n                                                'Pattern {}'.format(self.current_pattern_index))\n        self.current_pattern_name_widget.config(state='readonly')\n\n    def on_pattern_changed(self):\n        self.change_pattern()\n\n    def change_pattern(self):\n        self.current_pattern_index = int(self.pattern_index_widget.get())\n        self.display_pattern_name()\n        self.create_left_drum_loader()\n        self.display_all_drum_file_names()\n        self.create_right_button_matrix()\n        self.display_all_button_colors()\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def play_in_thread(self):\n        self.thread = threading.Thread(target = self.play_pattern)\n        self.thread.start()\n\n\n    def on_play_button_clicked(self):\n        self.start_play()\n        self.toggle_play_button_state()\n\n    def start_play(self):\n        self.init_pygame()\n        self.play_in_thread()\n\n    def on_stop_button_clicked(self):\n        self.stop_play()\n        self.toggle_play_button_state()\n\n\n    def toggle_play_button_state(self):\n        if self.now_playing:\n            self.play_button.config(state=\"disabled\")\n        else:\n            self.play_button.config(state=\"normal\")\n\n    def exit_app(self):\n        self.now_playing = False\n        if messagebox.askokcancel(\"Quit\", \"Really quit?\"):\n            self.root.destroy()\n\n    def stop_play(self):\n        self.now_playing = False\n\n    def init_pygame(self):\n        pygame.mixer.pre_init(44100, -16, 1, 512)\n        pygame.init()\n\n    def play_sound(self, sound_filename):\n        if sound_filename is not None:\n            pygame.mixer.Sound(sound_filename).play()\n\n    def get_column_from_matrix(self, matrix, i):\n        return [row[i] for row in matrix]\n\n\n    def play_pattern(self):\n        self.now_playing = True\n        self.toggle_play_button_state()\n        while self.now_playing:\n            play_list = self.get_is_button_clicked_list()\n            num_columns = len(play_list[0])\n            for column_index in range(num_columns):\n                column_to_play = self.get_column_from_matrix(\n                      play_list, column_index)\n                for i, item in enumerate(column_to_play):\n                    if item:\n                        sound_filename = self.get_drum_file_path(i)\n                        self.play_sound(sound_filename)\n                time.sleep(self.time_to_play_each_column())\n                if not self.now_playing: break\n            if not self.loop: break\n        self.now_playing = False\n        self.toggle_play_button_state()\n\n    def time_to_play_each_column(self):\n        beats_per_second = self.beats_per_minute / 60\n        time_to_play_each_column = 1 / beats_per_second\n        return time_to_play_each_column\n\n\n    def on_loop_button_toggled(self):\n        self.loop = self.loopbuttonvar.get()\n\n    def on_beats_per_minute_changed(self):\n        self.beats_per_minute = int(self.beats_per_minute_widget.get())\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        self.loopbuttonvar = BooleanVar()\n        self.loopbuttonvar.set(True)\n        self.loopbutton = Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled, variable=self.loopbuttonvar)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n        self.display_pattern_name()\n\n    def load_project(self):\n        file_path = filedialog.askopenfilename(\n            filetypes=[('Explosion Beat File', '*.ebt')], title='Load Project')\n        if not file_path:\n            return\n        pickled_file_object = open(file_path, \"rb\")\n        try:\n            self.all_patterns = pickle.load(pickled_file_object)\n        except EOFError:\n            messagebox.showerror(\"Error\",\n                                 \"Explosion Beat file seems corrupted or invalid !\")\n        pickled_file_object.close()\n        try:\n            self.change_pattern()\n            self.root.title(os.path.basename(file_path) + PROGRAM_NAME)\n        except:\n            messagebox.showerror(\"Error\",\n                                 \"An unexpected error occurred trying to process the beat file\")\n\n    def save_project(self):\n        saveas_file_name = filedialog.asksaveasfilename(\n            filetypes=[('Explosion Beat File', '*.ebt')], title=\"Save project as...\")\n        if saveas_file_name is None:\n            return\n        pickle.dump(self.all_patterns, open(saveas_file_name, \"wb\"))\n        self.root.title(os.path.basename(saveas_file_name) + PROGRAM_NAME)\n\n\n    def show_about(self):\n        messagebox.showinfo(PROGRAM_NAME,\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"Load Project\", command=self.load_project)\n        self.file_menu.add_command(\n            label=\"Save Project\", command=self.save_project)\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\", command=self.exit_app)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\", command=self.show_about)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.10.py",
    "content": "\"\"\"\nCode illustration: 3.10.py\n\n    1. tkinter versus ttk Themed Widgets\n    2. new widgets introduced in ttk\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Button, Label, Checkbutton, Entry, PanedWindow, \\\n            Radiobutton, Scale, VERTICAL, HORIZONTAL, W\nfrom tkinter import ttk\n\n\nroot = Tk()\n\nstyle = ttk.Style()\n\nprint(style.theme_names())\n\n# style.theme_use('default')\n\nroot.title('Tkinter Versus ttk Themed Widgets')\n\nttk.Separator(root, orient=VERTICAL).grid(\n    row=0, rowspan=8, column=1, sticky=\"wns\")\n\nLabel(root, text='Tkinter    Versus').grid(row=0, columnspan=2, sticky='ew')\nttk.Label(root, text='ttk').grid(row=0, column=1)\n\n\nButton(root, text='tk Button').grid(row=1, column=0)\nttk.Button(root, text='ttk Button').grid(row=1, column=1)\n\n\nCheckbutton(root, text='tk CheckButton').grid(row=2, column=0)\nttk.Checkbutton(root, text='ttk CheckButton').grid(row=2, column=1)\n\nEntry(root).grid(row=3, column=0)\nttk.Entry(root).grid(row=3, column=1)\n\n\nPanedWindow(root).grid(row=4, column=0)\nttk.PanedWindow(root).grid(row=4, column=1)\n\nRadiobutton(root, text='tk Radio').grid(row=5, column=0)\nttk.Radiobutton(root, text='ttk Radio').grid(row=5, column=1)\n\n\nScale(root, orient=HORIZONTAL).grid(row=6, column=0)\nttk.Scale(root).grid(row=6, column=1)\n\nttk.Separator(root, orient=HORIZONTAL).grid(row=7, columnspan=2, sticky=\"ew\")\nttk.Label(root, text='NEW WIDGETS INTRODUCED IN ttk').grid(row=8, columnspan=2)\nttk.Separator(root, orient=HORIZONTAL).grid(row=9, columnspan=2, sticky=\"ew\")\n\nttk.Combobox(root).grid(row=11, column=0)\n\n\nmy_notebook = ttk.Notebook(root)\nmy_notebook.grid(row=12, column=1)\nframe_1 = ttk.Frame(my_notebook)\nframe_2 = ttk.Frame(my_notebook)\nmy_notebook.add(frame_1, text='Tab One')\nmy_notebook.add(frame_2, text='Tab Two')\n\nttk.Progressbar(root, length=140, value=65).grid(row=13, column=0)\n\nmy_tree = ttk.Treeview(root, height=2, columns=2)\nmy_tree.grid(row=14, columnspan=2)\nmy_tree.heading('#0', text='Column A', anchor=W)\nmy_tree.heading(2, text='Column B', anchor=W)\nmy_tree.column(2, stretch=0, width=70)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.11.py",
    "content": "\"\"\"\nCode illustration: 3.11.py\n    ttk widgets styling and theming explained\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk\nfrom tkinter import ttk\nroot = Tk()\n\nstyle = ttk.Style()\n# defining the global style - applied when no other style is defined\nstyle.configure('.', font='Arial 14', foreground='brown', background='yellow')\n# this label inherits the global style as style option not specified for it\nttk.Label(root, text='I have no style of my own').pack()\n# defining a new style named danger and configuring its style only for the\n# button widget\nstyle.configure('danger.TButton', font='Times 12', foreground='red', padding=1)\nttk.Button(root, text='Styled Dangerously', style='danger.TButton').pack()\n# Different  styling for different widget states\nstyle.map(\"new_state_new_style.TButton\", foreground=[\n          ('pressed', 'red'), ('active', 'blue')])\nttk.Button(text=\"Different Style for different states\",\n           style=\"new_state_new_style.TButton\").pack()\n# Overriding current theme styles for the Entry widget\ncurrent_theme = style.theme_use()\nstyle.theme_settings(\n    current_theme,\n    {\"TEntry\":\n     {\"configure\":\n      {\"padding\": 10},\n      \"map\": {\n          \"foreground\": [(\"focus\", \"red\")]\n      }\n      }\n     }\n)\nprint(style.theme_names())\nprint(style.theme_use())\n# this is effected by change of themes even though no style specified\nttk.Entry().pack()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 03/3.12.py",
    "content": "\"\"\"\nCode illustration: 3.12\n    applying ttk themes to our play button, stop button, loopbutton\n    adding separators\n\n        new imports here:\n            - from tkinter import ttk\n        methods modified here:\n            - create_play_bar()\n\nChapter 3 : Programmable Drum Machine\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport os\nimport time\nimport pickle\nimport threading\nfrom tkinter import Tk, Entry, W, E, N, S, PhotoImage, Checkbutton, Button, \\\n        Menu, Frame, Label, Spinbox, END, BooleanVar, messagebox\nfrom tkinter import filedialog\nfrom tkinter import messagebox\nfrom tkinter import ttk\nimport pygame\n\n\nPROGRAM_NAME = ' Explosion Drum Machine '\nMAX_NUMBER_OF_PATTERNS = 10\nMAX_NUMBER_OF_DRUM_SAMPLES = 5\nMAX_NUMBER_OF_UNITS = 5\nMAX_BPU = 5\nINITIAL_NUMBER_OF_UNITS = 4\nINITIAL_BPU = 4\nINITIAL_BEATS_PER_MINUTE = 240\nMIN_BEATS_PER_MINUTE = 80\nMAX_BEATS_PER_MINUTE = 360\nCOLOR_1 = 'grey55'\nCOLOR_2 = 'khaki'\nBUTTON_CLICKED_COLOR = 'green'\n\n\nclass DrumMachine:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.title(PROGRAM_NAME)\n        self.all_patterns = [None] * MAX_NUMBER_OF_PATTERNS\n        self.current_pattern_index = 0\n        self.loop = True\n        self.now_playing = False\n        self.beats_per_minute = INITIAL_BEATS_PER_MINUTE\n        self.drum_load_entry_widget = [None] * MAX_NUMBER_OF_DRUM_SAMPLES\n        self.root.protocol('WM_DELETE_WINDOW', self.exit_app)\n        self.init_all_patterns()\n        self.init_gui()\n\n    def get_current_pattern_dict(self):\n        return self.all_patterns[self.current_pattern_index]\n\n    def get_bpu(self):\n        return self.get_current_pattern_dict()['bpu']\n\n    def set_bpu(self):\n        self.get_current_pattern_dict()['bpu'] = int(self.bpu_widget.get())\n\n    def get_number_of_units(self):\n        return self.get_current_pattern_dict()['number_of_units']\n\n    def set_number_of_units(self):\n        self.get_current_pattern_dict(\n        )['number_of_units'] = int(self.number_of_units_widget.get())\n\n    def get_list_of_drum_files(self):\n        return self.get_current_pattern_dict()['list_of_drum_files']\n\n    def get_drum_file_path(self, drum_index):\n        return self.get_list_of_drum_files()[drum_index]\n\n    def set_drum_file_path(self, drum_index, file_path):\n        self.get_list_of_drum_files()[drum_index] = file_path\n\n    def get_is_button_clicked_list(self):\n        return self.get_current_pattern_dict()['is_button_clicked_list']\n\n    def set_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        self.get_current_pattern_dict()['is_button_clicked_list'] = [\n            [False] * num_of_columns for x in range(num_of_rows)]\n\n\n    def set_beats_per_minute(self):\n        self.get_current_pattern_dict(\n        )['beats_per_minute'] = self.beats_per_minute_widget.get()\n\n    def init_all_patterns(self):\n        self.all_patterns = [\n            {\n                'list_of_drum_files': [None] * MAX_NUMBER_OF_DRUM_SAMPLES,\n                'number_of_units': INITIAL_NUMBER_OF_UNITS,\n                'bpu': INITIAL_BPU,\n                'is_button_clicked_list':\n                self.init_is_button_clicked_list(\n                    MAX_NUMBER_OF_DRUM_SAMPLES,\n                    INITIAL_NUMBER_OF_UNITS * INITIAL_BPU\n                )\n            }\n            for k in range(MAX_NUMBER_OF_PATTERNS)]\n\n    def init_is_button_clicked_list(self, num_of_rows, num_of_columns):\n        return [[False] * num_of_columns for x in range(num_of_rows)]\n\n    def load_project(self):\n        file_path = filedialog.askopenfilename(\n            filetypes=[('Explosion Beat File', '*.ebt')], title='Load Project')\n        if not file_path:\n            return\n        pickled_file_object = open(file_path, \"rb\")\n        try:\n            self.all_patterns = pickle.load(pickled_file_object)\n        except EOFError:\n            messagebox.showerror(\"Error\",\n                                 \"Explosion Beat file seems corrupted or invalid !\")\n        pickled_file_object.close()\n        try:\n            self.change_pattern()\n            self.root.title(os.path.basename(file_path) + PROGRAM_NAME)\n        except:\n            messagebox.showerror(\"Error\",\n                                 \"An unexpected error occurred trying to process the beat file\")\n\n    def save_project(self):\n        saveas_file_name = filedialog.asksaveasfilename(\n            filetypes=[('Explosion Beat File', '*.ebt')], title=\"Save project as...\")\n        if saveas_file_name is None:\n            return\n        pickle.dump(self.all_patterns, open(saveas_file_name, \"wb\"))\n        self.root.title(os.path.basename(saveas_file_name) + PROGRAM_NAME)\n\n\n    def show_about(self):\n        messagebox.showinfo(PROGRAM_NAME,\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def exit_app(self):\n        self.now_playing = False\n        if messagebox.askokcancel(\"Quit\", \"Really quit?\"):\n            self.root.destroy()\n\n    def display_pattern_name(self):\n        self.current_pattern_name_widget.config(state='normal')\n        self.current_pattern_name_widget.delete(0, 'end')\n        self.current_pattern_name_widget.insert(0,\n                                                'Pattern {}'.format(self.current_pattern_index))\n        self.current_pattern_name_widget.config(state='readonly')\n\n    def on_pattern_changed(self):\n        self.change_pattern()\n\n    def change_pattern(self):\n        self.current_pattern_index = int(self.pattern_index_widget.get())\n        self.display_pattern_name()\n        self.create_left_drum_loader()\n        self.display_all_drum_file_names()\n        self.create_right_button_matrix()\n        self.display_all_button_colors()\n\n    def on_number_of_units_changed(self):\n        self.set_number_of_units()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_bpu_changed(self):\n        self.set_bpu()\n        self.set_is_button_clicked_list(MAX_NUMBER_OF_DRUM_SAMPLES,\n                                        self.find_number_of_columns())\n        self.create_right_button_matrix()\n\n    def on_open_file_button_clicked(self, drum_index):\n        def event_handler():\n            file_path = filedialog.askopenfilename(defaultextension=\".wav\",\n                                                   filetypes=[(\"Wave Files\", \"*.wav\"), (\"OGG Files\", \"*.ogg\")])\n            if not file_path:\n                return\n            self.set_drum_file_path(drum_index, file_path)\n            self.display_all_drum_file_names()\n        return event_handler\n\n    def display_all_drum_file_names(self):\n        for i, drum_name in enumerate(self.get_list_of_drum_files()):\n            self.display_drum_name(i, drum_name)\n\n    def display_drum_name(self, text_widget_num, file_path):\n        if file_path is None:\n            return\n        drum_name = os.path.basename(file_path)\n        self.drum_load_entry_widget[text_widget_num].delete(0, END)\n        self.drum_load_entry_widget[text_widget_num].insert(0, drum_name)\n\n    def play_in_thread(self):\n        self.thread = threading.Thread(target = self.play_pattern)\n        self.thread.start()\n\n    def on_play_button_clicked(self):\n        self.start_play()\n        self.toggle_play_button_state()\n\n    def start_play(self):\n        self.init_pygame()\n        self.play_in_thread()\n\n    def on_stop_button_clicked(self):\n        self.stop_play()\n        self.toggle_play_button_state()\n\n    def stop_play(self):\n        self.now_playing = False\n\n\n    def init_pygame(self):\n        pygame.mixer.pre_init(44100, -16, 1, 512)\n        pygame.init()\n\n    def play_sound(self, sound_filename):\n        if sound_filename is not None:\n            pygame.mixer.Sound(sound_filename).play()\n\n    def get_column_from_matrix(self, matrix, i):\n        return [row[i] for row in matrix]\n\n    def toggle_play_button_state(self):\n        if self.now_playing:\n            self.play_button.config(state=\"disabled\")\n        else:\n            self.play_button.config(state=\"normal\")\n\n    def play_pattern(self):\n        self.now_playing = True\n        self.toggle_play_button_state()\n        while self.now_playing:\n            play_list = self.get_is_button_clicked_list()\n            num_columns = len(play_list[0])\n            for column_index in range(num_columns):\n                column_to_play = self.get_column_from_matrix(\n                      play_list, column_index)\n                for i, item in enumerate(column_to_play):\n                    if item:\n                        sound_filename = self.get_drum_file_path(i)\n                        self.play_sound(sound_filename)\n                time.sleep(self.time_to_play_each_column())\n                if not self.now_playing: break\n            if not self.loop: break\n        self.now_playing = False\n        self.toggle_play_button_state()\n\n    def time_to_play_each_column(self):\n        beats_per_second = self.beats_per_minute / 60\n        time_to_play_each_column = 1 / beats_per_second\n        return time_to_play_each_column\n\n    def on_loop_button_toggled(self):\n        self.loop = self.loopbutton.instate(['selected'])\n\n    def on_beats_per_minute_changed(self):\n        self.beats_per_minute = int(self.beats_per_minute_widget.get())\n\n    def get_button_value(self, row, col):\n        return self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col]\n\n    def find_number_of_columns(self):\n        return int(self.number_of_units_widget.get()) * int(self.bpu_widget.get())\n\n    def process_button_clicked(self, row, col):\n        self.set_button_value(row, col, not self.get_button_value(row, col))\n        self.display_button_color(row, col)\n\n    def set_button_value(self, row, col, bool_value):\n        self.all_patterns[self.current_pattern_index][\n            'is_button_clicked_list'][row][col] = bool_value\n\n    def on_button_clicked(self, row, col):\n        def event_handler():\n            self.process_button_clicked(row, col)\n        return event_handler\n\n    def display_all_button_colors(self):\n        number_of_columns = self.find_number_of_columns()\n        for r in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for c in range(number_of_columns):\n                self.display_button_color(r, c)\n\n    def display_button_color(self, row, col):\n        bpu = int(self.bpu_widget.get())\n        original_color = COLOR_1 if ((col//bpu) % 2) else COLOR_2\n        button_color = BUTTON_CLICKED_COLOR if self.get_button_value(\n            row, col) else original_color\n        self.buttons[row][col].config(background=button_color)\n\n    def create_play_bar(self):\n        playbar_frame = Frame(self.root, height=15)\n        start_row = MAX_NUMBER_OF_DRUM_SAMPLES + 10\n        playbar_frame.grid(row=start_row, columnspan=13,\n                           sticky=W + E, padx=15, pady=10)\n        self.play_icon = PhotoImage(file=\"images/play.gif\")\n        self.play_button = ttk.Button(\n            playbar_frame, text='Play',  image=self.play_icon, compound='left', command=self.on_play_button_clicked)\n        self.play_button.grid(row=start_row, column=1, padx=2)\n        ttk.Button(playbar_frame, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=start_row, column=3, padx=2)\n        ttk.Separator(playbar_frame, orient='vertical').grid(\n            row=start_row, column=5, sticky=\"ns\", padx=5)\n        self.loopbutton = ttk.Checkbutton(\n            playbar_frame, text='Loop', command=self.on_loop_button_toggled)\n        self.loopbutton.grid(row=start_row, column=16, padx=5)\n        self.loopbutton.state(['selected'])\n        ttk.Separator(playbar_frame, orient='vertical').grid(\n            row=start_row, column=20, sticky=\"ns\", padx=5)\n        Label(playbar_frame, text='Beats Per Minute').grid(\n            row=start_row, column=25)\n        self.beats_per_minute_widget = Spinbox(playbar_frame, from_=MIN_BEATS_PER_MINUTE, to=MAX_BEATS_PER_MINUTE, width=5,\n                increment=5.0, command=self.on_beats_per_minute_changed)\n        self.beats_per_minute_widget.grid(row=start_row, column=30)\n        self.beats_per_minute_widget.delete(0,\"end\")\n        self.beats_per_minute_widget.insert(0,INITIAL_BEATS_PER_MINUTE)\n        ttk.Separator(playbar_frame, orient='vertical').grid(\n            row=start_row, column=35, sticky=\"ns\", padx=5)\n        photo = PhotoImage(file='images/signature.gif')\n        label = Label(playbar_frame, image=photo)\n        label.image = photo\n        label.grid(row=start_row, column=50, padx=1, sticky='w')\n\n    def create_right_button_matrix(self):\n        right_frame = Frame(self.root)\n        right_frame.grid(row=10, column=6, sticky=W +\n                         E + N + S, padx=15, pady=4)\n        self.buttons = [[None for x in range(\n            self.find_number_of_columns())] for x in range(MAX_NUMBER_OF_DRUM_SAMPLES)]\n        for row in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            for col in range(self.find_number_of_columns()):\n                self.buttons[row][col] = Button(\n                    right_frame, command=self.on_button_clicked(row, col))\n                self.buttons[row][col].grid(row=row, column=col)\n                self.display_button_color(row, col)\n\n    def create_left_drum_loader(self):\n        left_frame = Frame(self.root)\n        left_frame.grid(row=10, column=0, columnspan=6, sticky=W + E + N + S)\n        open_file_icon = PhotoImage(file='images/openfile.gif')\n        for i in range(MAX_NUMBER_OF_DRUM_SAMPLES):\n            open_file_button = Button(left_frame, image=open_file_icon,\n                                      command=self.on_open_file_button_clicked(i))\n            open_file_button.image = open_file_icon\n            open_file_button.grid(row=i, column=0,  padx=5, pady=4)\n            self.drum_load_entry_widget[i] = Entry(left_frame)\n            self.drum_load_entry_widget[i].grid(\n                row=i, column=4, padx=7, pady=4)\n\n    def create_top_bar(self):\n        topbar_frame = Frame(self.root, height=25)\n        topbar_frame.grid(row=0, columnspan=12, rowspan=10, padx=5, pady=5)\n\n        Label(topbar_frame, text='Pattern Number:').grid(row=0, column=1)\n        self.pattern_index_widget = Spinbox(topbar_frame, from_=0, to=MAX_NUMBER_OF_PATTERNS - 1, width=5,\n                command=self.on_pattern_changed)\n        self.pattern_index_widget.grid(row=0, column=2)\n        self.current_pattern_name_widget = Entry(topbar_frame)\n        self.current_pattern_name_widget.grid(row=0, column=3, padx=7, pady=2)\n\n        Label(topbar_frame, text='Number of Units:').grid(row=0, column=4)\n        self.number_of_units_widget = Spinbox(topbar_frame, from_=1, to=MAX_NUMBER_OF_UNITS, width=5,\n                command=self.on_number_of_units_changed)\n        self.number_of_units_widget.delete(0,\"end\")\n        self.number_of_units_widget.insert(0,INITIAL_NUMBER_OF_UNITS)\n        self.number_of_units_widget.grid(row=0, column=5)\n        Label(topbar_frame, text='BPUs:').grid(row=0, column=6)\n        self.bpu_widget = Spinbox(topbar_frame, from_=1, to=MAX_BPU, width=5,\n                command=self.on_bpu_changed)\n        self.bpu_widget.grid(row=0, column=7)\n        self.bpu_widget.delete(0,\"end\")\n        self.bpu_widget.insert(0,INITIAL_BPU)\n        self.display_pattern_name()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.root)\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"Load Project\", command=self.load_project)\n        self.file_menu.add_command(\n            label=\"Save Project\", command=self.save_project)\n        self.file_menu.add_separator()\n        self.file_menu.add_command(label=\"Exit\", command=self.exit_app)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(label=\"About\", command=self.show_about)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.root.config(menu=self.menu_bar)\n\n    def init_gui(self):\n        self.create_top_menu()\n        self.create_top_bar()\n        self.create_left_drum_loader()\n        self.create_right_button_matrix()\n        self.create_play_bar()\n\n\nif __name__ == '__main__':\n    root = Tk()\n    DrumMachine(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 03/readme.txt",
    "content": "====================================================================\nCode Readme\nTkinter GUI Application Development Blueprints\nChapter 3: Drum Machine\n====================================================================\nList of code samples:\n\n3.01:   Creating OOP Based GUI structure\n3.02:   Defining & Initializing the Data Structure \n3.03:   Displaying All Visual Elements\n3.04:   Adding all the getter & setter methods for our data structure\n3.05:   Loading drum samples\n3.06:   Playing Audio\n3.07:   Tkinter and Threading\n3.08:   Adding support for multiple beat patterns\n3.09:   Object Persistence: pickling and unpickling\n3.10:   tkinter versus ttk Themed Widgets / new widgets introduced in ttk\n3.11:   ttk widgets styling and theming explained\n3.12:   applying ttk themes to our play button, stop button, loopbutton / adding separators\n\n\n\n"
  },
  {
    "path": "Chapter 04/4.01/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64 # denoting 64 pixels\nBOARD_COLOR_1 =  \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\n\n    \n"
  },
  {
    "path": "Chapter 04/4.01/controller.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport model\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n"
  },
  {
    "path": "Chapter 04/4.01/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.01\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\n"
  },
  {
    "path": "Chapter 04/4.01/model.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\n\n\nclass Model():\n\n    def __init__(self):\n        pass\n"
  },
  {
    "path": "Chapter 04/4.01/view.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, messagebox\nimport controller\nfrom configurations import *\n\n\nclass View():\n\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=BOARD_COLOR_2)\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def on_new_game_menu_clicked(self):\n        pass\n\n    def on_preference_menu_clicked(self):\n        pass\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                self.canvas.create_rectangle(\n                    x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        print(\"Hey you clicked on\", clicked_row, clicked_column)\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n\ndef main(controller):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, controller)\n    root.mainloop()\n\n\ndef init_new_game():\n    game_controller = controller.Controller()\n    main(game_controller)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.02/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nBOARD_COLOR_1 = \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\n\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\n# remember capital letters - White pieces, Small letters - Black pieces\nSTART_PIECES_POSITION = {\n    \"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n    \"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\",\n    \"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\",\n    \"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\"\n}\n\nSHORT_NAME = {\n    'R': 'Rook',  'N': 'Knight',  'B': 'Bishop',\n    'Q': 'Queen',  'K': 'King',  'P': 'Pawn'\n}\n"
  },
  {
    "path": "Chapter 04/4.02/controller.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport model\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n"
  },
  {
    "path": "Chapter 04/4.02/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.02\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\n"
  },
  {
    "path": "Chapter 04/4.02/model.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport piece\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        pass\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n"
  },
  {
    "path": "Chapter 04/4.02/piece.py",
    "content": "\"\"\"\nCode illustration: 4.02\n@ Tkinter GUI Application Development Blueprints\n\"\"\" \nfrom configurations import *\nimport exceptions\n\n\ndef create_piece (piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n    \nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n   \n    def keep_reference(self, model):\n        self.model = model\n\nclass King(Piece):\n    pass\n    \nclass Queen(Piece):\n    pass\n\nclass Rook(Piece):\n    pass\n    \nclass Bishop(Piece):\n    pass\n    \nclass Knight(Piece):\n    pass\n    \nclass Pawn(Piece):\n    pass\n    \n\n\n"
  },
  {
    "path": "Chapter 04/4.02/view.py",
    "content": "\"\"\"\nCode illustration: 4.01\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, messagebox\nimport controller\nfrom configurations import *\n\n\nclass View():\n\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=\"black\")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def on_new_game_menu_clicked(self):\n        pass\n\n    def on_preference_menu_clicked(self):\n        pass\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                self.canvas.create_rectangle(\n                    x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        print(\"Hey you clicked on\", clicked_row, clicked_column)\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def get_alternate_color(self, current_color):\n        if current_color == BOARD_COLOR_1:\n            next_color = BOARD_COLOR_2\n        else:\n            next_color = BOARD_COLOR_1\n        return next_color\n\n\ndef main(controller):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, controller)\n    root.mainloop()\n\n\ndef init_new_game():\n    game_controller = controller.Controller()\n    main(game_controller)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.03/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.03\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nBOARD_COLOR_1 = \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\n\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\nSHORT_NAME = {\n    'R': 'Rook',  'N': 'Knight',  'B': 'Bishop',\n    'Q': 'Queen',  'K': 'King',  'P': 'Pawn'\n}\n\n# remember capital letters - White pieces, Small letters - Black pieces\nSTART_PIECES_POSITION = {\n    \"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n    \"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\",\n    \"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\",\n    \"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\"\n}\n"
  },
  {
    "path": "Chapter 04/4.03/controller.py",
    "content": "\"\"\"\nCode illustration: 4.03\n    New method added here:\n        get_numeric_notation(position)\n        get_all_peices_on_chess_board()\n        reset_game_data()\n        reset_to_initial_locations()\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport model\nimport piece\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n\n    def get_all_peices_on_chess_board(self):\n        return self.model.items()\n\n    def reset_game_data(self):\n        self.model.reset_game_data()\n\n    def reset_to_initial_locations(self):\n        self.model.reset_to_initial_locations()\n\n    def get_numeric_notation(self, position):\n        return piece.get_numeric_notation(position)\n"
  },
  {
    "path": "Chapter 04/4.03/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.03\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\n"
  },
  {
    "path": "Chapter 04/4.03/model.py",
    "content": "\"\"\"\nCode illustration: 4.03\n\n    Methods modified here:\n        __init__ method (added a call to reset_to_initial_locations())\n        \n    Methods defined here:\n        reset_to_initial_locations()\n        reset_game_data()\n        \n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport piece\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        self.reset_to_initial_locations()\n\n    def reset_game_data(self):\n        captured_pieces = {'white': [], 'black': []}\n        player_turn = None\n        halfmove_clock = 0\n        fullmove_number = 1\n        history = []\n\n    def reset_to_initial_locations(self):\n        self.clear()\n        for position, value in START_PIECES_POSITION.items():\n            self[position] = piece.create_piece(value)\n            self[position].keep_reference(self)\n        self.player_turn = 'white'\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n"
  },
  {
    "path": "Chapter 04/4.03/piece.py",
    "content": "\"\"\"\nCode illustration: 4.03\n\n    New Imports\n        import sys\n    \n       \n    Methods Added\n        - all classes and methods\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\" \nfrom configurations import *\nimport sys\nimport exceptions\n\n\ndef create_piece (piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n    \ndef get_numeric_notation(rowcol):\n    row, col = rowcol\n    return int(col)-1, X_AXIS_LABELS.index(row) \n\n\nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n   \n    def keep_reference(self, model):\n        self.model = model\n\nclass King(Piece):\n    pass\n    \nclass Queen(Piece):\n    pass\n\nclass Rook(Piece):\n    pass\n    \nclass Bishop(Piece):\n    pass\n    \nclass Knight(Piece):\n    pass\n    \nclass Pawn(Piece):\n    pass\n"
  },
  {
    "path": "Chapter 04/4.03/view.py",
    "content": "\"\"\"\nCode illustration: 4.03\n\n    New attributes added here:\n        images = {}\n\n    New methods defined here:\n        draw_single_piece(position, piece)\n        calculate_piece_coordinate(x, y)\n        draw_all_pieces()\n        start_new_game()\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, PhotoImage, messagebox\nimport controller\nfrom configurations import *\n\n\nclass View():\n\n    images = {}\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n        self.start_new_game()\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=\"black\")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def on_new_game_menu_clicked(self):\n        pass\n\n    def on_preference_menu_clicked(self):\n        pass\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                self.canvas.create_rectangle(\n                    x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        print(\"Hey you clicked on\", clicked_row, clicked_column)\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def calculate_piece_coordinate(self, row, col):\n        x0 = (col * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        y0 = ((7 - row) * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        return (x0, y0)\n\n    def draw_single_piece(self, position, piece):\n        x, y = self.controller.get_numeric_notation(position)\n        if piece:\n            filename = \"../pieces_image/{}_{}.png\".format(\n                piece.name.lower(), piece.color)\n            if filename not in self.images:\n                self.images[filename] = PhotoImage(file=filename)\n            x0, y0 = self.calculate_piece_coordinate(x, y)\n            self.canvas.create_image(x0, y0, image=self.images[\n                                     filename], tags=(\"occupied\"), anchor=\"c\")\n\n    def draw_all_pieces(self):\n        self.canvas.delete(\"occupied\")\n        for position, piece in self.controller.get_all_peices_on_chess_board():\n            self.draw_single_piece(position, piece)\n\n    def start_new_game(self):\n        self.controller.reset_game_data()\n        self.controller.reset_to_initial_locations()\n        self.draw_all_pieces()\n        self.info_label.config(text=\"   White to Start the Game  \")\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n\ndef main(controller):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, controller)\n    root.mainloop()\n\n\ndef init_new_game():\n    game_controller = controller.Controller()\n    main(game_controller)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.04/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.04\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nBOARD_COLOR_1 = \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\n\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\nSHORT_NAME = {  \n'R':'Rook',  'N':'Knight',  'B':'Bishop',  \n'Q':'Queen',  'K':'King',  'P':'Pawn'\n}\n\n# remember capital letters - White pieces, Small letters - Black pieces \nSTART_PIECES_POSITION  = { \n\"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n\"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\", \n\"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\", \n\"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\" \n    }\n\nORTHOGONAL_POSITIONS  = ((-1,0),(0,1),(1,0),(0, -1))\nDIAGONAL_POSITIONS  = ((-1,-1),(-1,1),(1,-1),(1,1))\nKNIGHT_POSITIONS = ((-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1))\n"
  },
  {
    "path": "Chapter 04/4.04/controller.py",
    "content": "\"\"\"\nCode illustration: 4.04\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport model\nimport piece\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n\n    def get_all_peices_on_chess_board(self):\n        return self.model.items()\n\n    def reset_game_data(self):\n        self.model.reset_game_data()\n\n    def reset_to_initial_locations(self):\n        self.model.reset_to_initial_locations()\n\n    def get_numeric_notation(self, position):\n        return piece.get_numeric_notation(position)\n"
  },
  {
    "path": "Chapter 04/4.04/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.04\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\n"
  },
  {
    "path": "Chapter 04/4.04/model.py",
    "content": "\"\"\"\nCode illustration: 4.04\n\n    New methods added here:\n        all_positions_occupied_by_color(color)\n        all_occupied_positions()\n        \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport piece\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        self.reset_to_initial_locations()\n\n    def all_positions_occupied_by_color(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece.color == color:\n                result.append(position)\n        return result\n\n    def all_occupied_positions(self):\n        return self.all_positions_occupied_by_color('white') + self.all_positions_occupied_by_color('black')\n\n    def reset_game_data(self):\n        captured_pieces = {'white': [], 'black': []}\n        player_turn = None\n        halfmove_clock = 0\n        fullmove_number = 1\n        history = []\n\n    def reset_to_initial_locations(self):\n        self.clear()\n        for position, value in START_PIECES_POSITION.items():\n            self[position] = piece.create_piece(value)\n            self[position].keep_reference(self)\n        self.player_turn = 'white'\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n"
  },
  {
    "path": "Chapter 04/4.04/piece.py",
    "content": "\"\"\"\nCode illustration: 4.04\n\n    Methods Added\n        - moves_available(current_position, directions, distance)\n\n    Classes Modified:\n        all classes\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport sys\nimport exceptions\n\n\ndef create_piece(piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n\n\ndef get_numeric_notation(rowcol):\n    row, col = rowcol\n    return int(col) - 1, X_AXIS_LABELS.index(row)\n\n\nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n\n    def keep_reference(self, model):\n        self.model = model\n\n    def moves_available(self, current_position, directions, distance):\n        model = self.model\n        allowed_moves = []\n        piece = self\n        start_row, start_column = get_numeric_notation(current_position)\n        for x, y in directions:\n            collision = False\n            for step in range(1, distance + 1):\n                if collision:\n                    break\n                destination = start_row + step * x, start_column + step * y\n                if self.possible_position(destination) not in model.all_occupied_positions():\n                    allowed_moves.append(destination)\n                elif self.possible_position(destination) in model.all_positions_occupied_by_color(piece.color):\n                    collision = True\n                else:\n                    allowed_moves.append(destination)\n                    collision = True\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n    def possible_position(self, destination):\n        return self.model.get_alphanumeric_position(destination)\n\n\nclass King(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 1\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position.upper(), self.directions, self.max_distance)\n\n\nclass Queen(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position.upper(), self.directions, self.max_distance)\n\n\nclass Rook(Piece):\n    directions = ORTHOGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position.upper(), self.directions, self.max_distance)\n\n\nclass Bishop(Piece):\n    directions = DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position.upper(), self.directions, self.max_distance)\n\n\nclass Knight(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        allowed_moves = []\n        start_position = get_numeric_notation(current_position.upper())\n        piece = model.get(pos.upper())\n        for x, y in KNIGHT_POSITIONS:\n            destination = start_position[0] + x, start_position[1] + y\n            if(model.get_alphanumeric_position(destination) not in model.all_positions_occupied_by_color(piece.color)):\n                allowed_moves.append(destination)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n\nclass Pawn(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        piece = self\n        if self.color == 'white':\n            initial_position, direction, enemy = 1, 1, 'black'\n        else:\n            initial_position, direction, enemy = 6, -1, 'white'\n        allowed_moves = []\n        # Moving\n        prohibited = model.all_occupied_positions()\n        start_position = get_numeric_notation(current_position.upper())\n        forward = start_position[0] + direction, start_position[1]\n        if model.get_alphanumeric_position(forward) not in prohibited:\n            allowed_moves.append(forward)\n            if start_position[0] == initial_position:\n                # If pawn is in starting position allow double moves\n                double_forward = (forward[0] + direction, forward[1])\n                if model.get_alphanumeric_position(double_forward) not in prohibited:\n                    allowed_moves.append(double_forward)\n        # Attacking\n        for a in range(-1, 2, 2):\n            attack = start_position[0] + direction, start_position[1] + a\n            if model.get_alphanumeric_position(attack) in model.all_positions_occupied_by_color(enemy):\n                allowed_moves.append(attack)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n"
  },
  {
    "path": "Chapter 04/4.04/view.py",
    "content": "\"\"\"\nCode illustration: 4.04\n\n    New attributes added here:\n        images = {}\n\n    New methods defined here:\n        draw_single_piece(position, piece)\n        calculate_piece_coordinate(x, y)\n        draw_all_pieces()\n        start_new_game()\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, PhotoImage, messagebox\nimport controller\nfrom configurations import *\n\n\nclass View():\n\n    images = {}\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n        self.start_new_game()\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=\"black\")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def on_new_game_menu_clicked(self):\n        pass\n\n    def on_preference_menu_clicked(self):\n        pass\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                self.canvas.create_rectangle(\n                    x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        print(\"Hey you clicked on\", clicked_row, clicked_column)\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def calculate_piece_coordinate(self, row, col):\n        x0 = (col * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        y0 = ((7 - row) * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        return (x0, y0)\n\n    def draw_single_piece(self, position, piece):\n        x, y = self.controller.get_numeric_notation(position)\n        if piece:\n            filename = \"../pieces_image/{}_{}.png\".format(\n                piece.name.lower(), piece.color)\n            if filename not in self.images:\n                self.images[filename] = PhotoImage(file=filename)\n            x0, y0 = self.calculate_piece_coordinate(x, y)\n            self.canvas.create_image(x0, y0, image=self.images[\n                                     filename], tags=(\"occupied\"), anchor=\"c\")\n\n    def draw_all_pieces(self):\n        self.canvas.delete(\"occupied\")\n        for position, piece in self.controller.get_all_peices_on_chess_board():\n            self.draw_single_piece(position, piece)\n\n    def start_new_game(self):\n        self.controller.reset_game_data()\n        self.controller.reset_to_initial_locations()\n        self.draw_all_pieces()\n        self.info_label.config(text=\"   White to Start the Game  \")\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n\ndef main(controller):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, controller)\n    root.mainloop()\n\n\ndef init_new_game():\n    game_controller = controller.Controller()\n    main(game_controller)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.05/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.05\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nBOARD_COLOR_1 = \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\n\n\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\nSHORT_NAME = {\n    'R': 'Rook',  'N': 'Knight',  'B': 'Bishop',\n    'Q': 'Queen',  'K': 'King',  'P': 'Pawn'\n}\n\n# remember capital letters - White pieces, Small letters - Black pieces\nSTART_PIECES_POSITION = {\n    \"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n    \"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\",\n    \"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\",\n    \"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\"\n}\n\nORTHOGONAL_POSITIONS = ((-1, 0), (0, 1), (1, 0), (0, -1))\nDIAGONAL_POSITIONS = ((-1, -1), (-1, 1), (1, -1), (1, 1))\nKNIGHT_POSITIONS = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),\n                    (1, -2), (1, 2), (2, -1), (2, 1))\n"
  },
  {
    "path": "Chapter 04/4.05/controller.py",
    "content": "\"\"\"\nCode illustration: 4.05\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport model\nimport piece\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n\n    def get_all_peices_on_chess_board(self):\n        return self.model.items()\n\n    def reset_game_data(self):\n        self.model.reset_game_data()\n\n    def reset_to_initial_locations(self):\n        self.model.reset_to_initial_locations()\n\n    def get_numeric_notation(self, position):\n        return piece.get_numeric_notation(position)\n"
  },
  {
    "path": "Chapter 04/4.05/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.05\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\n"
  },
  {
    "path": "Chapter 04/4.05/model.py",
    "content": "\"\"\"\nCode illustration: 4.05\n\n    New methods added here:\n        get_all_available_moves(color)\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport piece\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        self.reset_to_initial_locations()\n\n    def get_all_available_moves(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece and piece.color == color:\n                moves = piece.moves_available(position)\n                if moves:\n                    result.extend(moves)\n        return result\n\n    def all_positions_occupied_by_color(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece.color == color:\n                result.append(position)\n        return result\n\n    def all_occupied_positions(self):\n        return self.all_positions_occupied_by_color('white') + self.all_positions_occupied_by_color('black')\n\n    def reset_game_data(self):\n        captured_pieces = {'white': [], 'black': []}\n        player_turn = None\n        halfmove_clock = 0\n        fullmove_number = 1\n        history = []\n\n    def reset_to_initial_locations(self):\n        self.clear()\n        for position, value in START_PIECES_POSITION.items():\n            self[position] = piece.create_piece(value)\n            self[position].keep_reference(self)\n        self.player_turn = 'white'\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n\n    def get_alphanumeric_position_of_king(self, color):\n        for position in self.keys():\n            this_piece = self.get_piece_at(position)\n            if isinstance(this_piece, piece.King) and this_piece.color == color:\n                return position\n\n    def is_king_under_check(self, color):\n        position_of_king = self.get_alphanumeric_position_of_king(color)\n        opponent = ('black' if color == 'white' else 'white')\n        return position_of_king in self.get_all_available_moves(opponent)\n"
  },
  {
    "path": "Chapter 04/4.05/piece.py",
    "content": "\"\"\"\nCode illustration: 4.05\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport sys\nimport exceptions\n\n\ndef create_piece(piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n\n\ndef get_numeric_notation(rowcol):\n    row, col = rowcol\n    return int(col) - 1, X_AXIS_LABELS.index(row)\n\n\nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n\n    def keep_reference(self, model):\n        self.model = model\n\n    def moves_available(self, current_position, directions, distance):\n        model = self.model\n        allowed_moves = []\n        piece = self\n        start_row, start_column = get_numeric_notation(current_position)\n        for x, y in directions:\n            collision = False\n            for step in range(1, distance + 1):\n                if collision:\n                    break\n                destination = start_row + step * x, start_column + step * y\n                if self.possible_position(destination) not in model.all_occupied_positions():\n                    allowed_moves.append(destination)\n                elif self.possible_position(destination) in model.all_positions_occupied_by_color(piece.color):\n                    collision = True\n                else:\n                    allowed_moves.append(destination)\n                    collision = True\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n    def possible_position(self, destination):\n        return self.model.get_alphanumeric_position(destination)\n\n\nclass King(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 1\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Queen(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Rook(Piece):\n    directions = ORTHOGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Bishop(Piece):\n    directions = DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Knight(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        allowed_moves = []\n        start_col, start_row = get_numeric_notation(current_position.upper())\n        piece = model.get(pos.upper())\n        for x, y in KNIGHT_POSITIONS:\n            destination = start_col + x, start_row + y\n            if model.get_alphanumeric_position(destination) not in model.all_positions_occupied_by_color(piece.color):\n                allowed_moves.append(destination)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n\nclass Pawn(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        piece = self\n        if self.color == 'white':\n            initial_position, direction, enemy = 1, 1, 'black'\n        else:\n            initial_position, direction, enemy = 6, -1, 'white'\n        allowed_moves = []\n        # Moving\n        prohibited = model.all_occupied_positions()\n        start_position = get_numeric_notation(current_position.upper())\n        forward = start_position[0] + direction, start_position[1]\n        if model.get_alphanumeric_position(forward) not in prohibited:\n            allowed_moves.append(forward)\n            if start_position[0] == initial_position:\n                # If pawn is in starting position allow double moves\n                double_forward = (forward[0] + direction, forward[1])\n                if model.get_alphanumeric_position(double_forward) not in prohibited:\n                    allowed_moves.append(double_forward)\n        # Attacking\n        for a in range(-1, 2, 2):\n            attack = start_position[0] + direction, start_position[1] + a\n            if model.get_alphanumeric_position(attack) in model.all_positions_occupied_by_color(enemy):\n                allowed_moves.append(attack)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n"
  },
  {
    "path": "Chapter 04/4.05/view.py",
    "content": "\"\"\"\nCode illustration: 4.05\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, PhotoImage, messagebox\nimport controller\nfrom configurations import *\n\n\nclass View():\n\n    images = {}\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n        self.start_new_game()\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=\"black\")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def on_new_game_menu_clicked(self):\n        pass\n\n    def on_preference_menu_clicked(self):\n        pass\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                self.canvas.create_rectangle(\n                    x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        print(\"Hey you clicked on\", clicked_row, clicked_column)\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def calculate_piece_coordinate(self, row, col):\n        x0 = (col * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        y0 = ((7 - row) * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        return (x0, y0)\n\n    def draw_single_piece(self, position, piece):\n        x, y = self.controller.get_numeric_notation(position)\n        if piece:\n            filename = \"../pieces_image/{}_{}.png\".format(\n                piece.name.lower(), piece.color)\n            if filename not in self.images:\n                self.images[filename] = PhotoImage(file=filename)\n            x0, y0 = self.calculate_piece_coordinate(x, y)\n            self.canvas.create_image(x0, y0, image=self.images[\n                                     filename], tags=(\"occupied\"), anchor=\"c\")\n\n    def draw_all_pieces(self):\n        self.canvas.delete(\"occupied\")\n        for position, piece in self.controller.get_all_peices_on_chess_board():\n            self.draw_single_piece(position, piece)\n\n    def start_new_game(self):\n        self.controller.reset_game_data()\n        self.controller.reset_to_initial_locations()\n        self.draw_all_pieces()\n        self.info_label.config(text=\"   White to Start the Game  \")\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n\ndef main(controller):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, controller)\n    root.mainloop()\n\n\ndef init_new_game():\n    game_controller = controller.Controller()\n    main(game_controller)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.06/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.06\n\n    added constant HIGHLIGHT_COLOR = \"#2EF70D\"\n    \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nBOARD_COLOR_1 = \"#e6a803\"\nBOARD_COLOR_2 = \"#8b8350\"\nHIGHLIGHT_COLOR = \"#2EF70D\"\n\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\nSHORT_NAME = {\n    'R': 'Rook',  'N': 'Knight',  'B': 'Bishop',\n    'Q': 'Queen',  'K': 'King',  'P': 'Pawn'\n}\n\n# remember capital letters - White pieces, Small letters - Black pieces\nSTART_PIECES_POSITION = {\n    \"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n    \"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\",\n    \"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\",\n    \"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\"\n}\n\nORTHOGONAL_POSITIONS = ((-1, 0), (0, 1), (1, 0), (0, -1))\nDIAGONAL_POSITIONS = ((-1, -1), (-1, 1), (1, -1), (1, 1))\nKNIGHT_POSITIONS = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),\n                    (1, -2), (1, 2), (2, -1), (2, 1))\n"
  },
  {
    "path": "Chapter 04/4.06/controller.py",
    "content": "\"\"\"\nCode illustration: 4.06\n\n    New methods added here:\n     shift( start_pos,end_pos)\n     get_all_peices_on_chess_board()\n     player_turn()\n     moves_available( position)\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport model\nimport piece\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n\n    def reset_game_data(self):\n        self.model.reset_game_data()\n\n    def reset_to_initial_locations(self):\n        self.model.reset_to_initial_locations()\n\n    def get_alphanumeric_position(self, rowcolumntuple):\n        return self.model.get_alphanumeric_position(rowcolumntuple)\n\n    def get_numeric_notation(self, rowcol):\n        return piece.get_numeric_notation(rowcol)\n\n    def get_piece_at(self, position_of_click):\n        return self.model.get_piece_at(position_of_click)\n\n    def pre_move_validation(self, start_pos, end_pos):\n        return self.model.pre_move_validation(start_pos, end_pos)\n\n    def get_all_peices_on_chess_board(self):\n        return self.model.items()\n\n    def player_turn(self):\n        return self.model.player_turn\n\n    def moves_available(self, position):\n        return self.model.moves_available(position)\n"
  },
  {
    "path": "Chapter 04/4.06/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.06\n\n    New classes added here:\n        InvalidMove(ChessError)\n        CheckMate(ChessError)\n        Draw(ChessError)\n        NotYourTurn(ChessError)\n        InvalidCoord(ChessError)\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\nclass Check(ChessError): pass\nclass InvalidMove(ChessError): pass\nclass CheckMate(ChessError): pass\nclass Draw(ChessError): pass\nclass NotYourTurn(ChessError): pass\nclass InvalidCoord(ChessError): pass\n"
  },
  {
    "path": "Chapter 04/4.06/model.py",
    "content": "\"\"\"\nCode illustration: 4.06\n        \n        New imports \n            from copy import deepcopy\n            import exceptions\n        \n        New methods added\n            pre_move_validation(self, initial_pos, final_pos)\n            is_king_under_check(color)\n            update_game_statistics(piece, dest, p1, p2)\n            move(start_pos, final_pos)\n            will_move_cause_check(p1, p2)\n            get_alphanumeric_position_of_king(color)\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom copy import deepcopy\nimport exceptions\nimport piece\nfrom configurations import *\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        self.reset_to_initial_locations()\n\n    def update_game_statistics(self, piece, dest, start_pos, end_pos):\n        if piece.color == 'black':\n            self.fullmove_number += 1\n        self.halfmove_clock += 1\n        abbr = piece.name\n        if abbr == 'pawn':\n            abbr = ''\n            self.halfmove_clock = 0\n        if dest is None:\n            move_text = abbr + end_pos.lower()\n        else:\n            move_text = abbr + 'x' + end_pos.lower()\n            self.halfmove_clock = 0\n        self.history.append(move_text)\n\n    def change_player_turn(self, color):\n        enemy = ('white' if color == 'black' else 'black')\n        self.player_turn = enemy\n\n    def pre_move_validation(self, initial_pos, final_pos):\n        initial_pos, final_pos = initial_pos.upper(), final_pos.upper()\n        piece = self.get_piece_at(initial_pos)\n        try:\n            piece_at_destination = self.get_piece_at(final_pos)\n        except:\n            piece_at_destination = None\n        if self.player_turn != piece.color:\n            raise exceptions.NotYourTurn(\"Not \" + piece.color + \"'s turn!\")\n        enemy = ('white' if piece.color == 'black' else 'black')\n        moves_available = piece.moves_available(initial_pos)\n        if final_pos not in moves_available:\n            raise exceptions.InvalidMove\n        if self.get_all_available_moves(enemy):\n            if self.will_move_cause_check(initial_pos, final_pos):\n                raise exceptions.Check\n        if not moves_available and self.is_king_under_check(piece.color):\n            raise exceptions.CheckMate\n        elif not moves_available:\n            raise exceptions.Draw\n        else:\n            self.move(initial_pos, final_pos)\n            self.update_game_statistics(\n                piece, piece_at_destination, initial_pos, final_pos)\n            self.change_player_turn(piece.color)\n\n    def move(self, start_pos, final_pos):\n        self[final_pos] = self.pop(start_pos, None)\n\n    def will_move_cause_check(self, start_position, end_position):\n        tmp = deepcopy(self)\n        tmp.move(start_position, end_position)\n        return tmp.is_king_under_check(self[start_position].color)\n\n    def get_all_available_moves(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece and piece.color == color:\n                moves = piece.moves_available(position)\n                if moves:\n                    result.extend(moves)\n        return result\n\n    def is_king_under_check(self, color):\n        position_of_king = self.get_alphanumeric_position_of_king(color)\n        opponent = ('black' if color == 'white' else 'white')\n        return position_of_king in self.get_all_available_moves(opponent)\n\n    def get_alphanumeric_position_of_king(self, color):\n        for position in self.keys():\n            this_piece = self.get_piece_at(position)\n            if isinstance(this_piece, piece.King) and this_piece.color == color:\n                return position\n\n    def all_positions_occupied_by_color(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece.color == color:\n                result.append(position)\n        return result\n\n    def all_occupied_positions(self):\n        return self.all_positions_occupied_by_color('white') + self.all_positions_occupied_by_color('black')\n\n    def reset_game_data(self):\n        captured_pieces = {'white': [], 'black': []}\n        player_turn = None\n        halfmove_clock = 0\n        fullmove_number = 1\n        history = []\n\n    def reset_to_initial_locations(self):\n        self.clear()\n        for position, value in START_PIECES_POSITION.items():\n            self[position] = piece.create_piece(value)\n            self[position].keep_reference(self)\n        self.player_turn = 'white'\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n"
  },
  {
    "path": "Chapter 04/4.06/piece.py",
    "content": "\"\"\"\nCode illustration: 4.06\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configurations import *\nimport sys\nimport exceptions\n\n\ndef create_piece(piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n\n\ndef get_numeric_notation(rowcol):\n    row, col = rowcol\n    return int(col) - 1, X_AXIS_LABELS.index(row)\n\n\nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n\n    def keep_reference(self, model):\n        self.model = model\n\n    def moves_available(self, current_position, directions, distance):\n        model = self.model\n        allowed_moves = []\n        piece = self\n        start_row, start_column = get_numeric_notation(current_position)\n        for x, y in directions:\n            collision = False\n            for step in range(1, distance + 1):\n                if collision:\n                    break\n                destination = start_row + step * x, start_column + step * y\n                if self.possible_position(destination) not in model.all_occupied_positions():\n                    allowed_moves.append(destination)\n                elif self.possible_position(destination) in model.all_positions_occupied_by_color(piece.color):\n                    collision = True\n                else:\n                    allowed_moves.append(destination)\n                    collision = True\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n    def possible_position(self, destination):\n        return self.model.get_alphanumeric_position(destination)\n\n\nclass King(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 1\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Queen(Piece):\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Rook(Piece):\n    directions = ORTHOGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Bishop(Piece):\n    directions = DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Knight(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        allowed_moves = []\n        start_col, start_row = get_numeric_notation(current_position.upper())\n        piece = model.get(current_position)\n        for x, y in KNIGHT_POSITIONS:\n            destination = start_col + x, start_row + y\n            if model.get_alphanumeric_position(destination) not in model.all_positions_occupied_by_color(piece.color):\n                allowed_moves.append(destination)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n\nclass Pawn(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        piece = self\n        if self.color == 'white':\n            initial_position, direction, enemy = 1, 1, 'black'\n        else:\n            initial_position, direction, enemy = 6, -1, 'white'\n        allowed_moves = []\n        # Moving\n        prohibited = model.all_occupied_positions()\n        start_position = get_numeric_notation(current_position.upper())\n        forward = start_position[0] + direction, start_position[1]\n        if model.get_alphanumeric_position(forward) not in prohibited:\n            allowed_moves.append(forward)\n            if start_position[0] == initial_position:\n                # If pawn is in starting position allow double moves\n                double_forward = (forward[0] + direction, forward[1])\n                if model.get_alphanumeric_position(double_forward) not in prohibited:\n                    allowed_moves.append(double_forward)\n        # Attacking\n        for a in range(-1, 2, 2):\n            attack = start_position[0] + direction, start_position[1] + a\n            if model.get_alphanumeric_position(attack) in model.all_positions_occupied_by_color(enemy):\n                allowed_moves.append(attack)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n"
  },
  {
    "path": "Chapter 04/4.06/view.py",
    "content": "\"\"\"\nCode illustration: 4.06\n\n    Attributes added\n        selected_piece_position = None\n        all_squares_to_be_highlighted = []\n\n    Methods added\n         update_label(piece, start_pos, end_pos)\n         update_highlight_list(position)\n         shift( start_pos, end_pos)\n\n\n    Method modified\n         on_square_clicked(event)\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, PhotoImage, messagebox\nimport controller\nimport exceptions\nfrom configurations import *\n\n\nclass View():\n\n    selected_piece_position = None\n    all_squares_to_be_highlighted = []\n    images = {}\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n    highlight_color = HIGHLIGHT_COLOR\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n        self.start_new_game()\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \", fg=\"black\")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def on_preference_menu_clicked(self):\n        self.show_prefereces_window()\n\n    def show_prefereces_window(self):\n        preferenceswindow.PreferencesWindow(self.parent)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def start_new_game(self):\n        self.controller.reset_game_data()\n        self.controller.reset_to_initial_locations()\n        self.draw_all_pieces()\n        self.info_label.config(text=\"   White to Start the Game  \")\n\n    def reset_board_state(self):\n        self.selected_piece_position = None\n        self.all_squares_to_be_highlighted = []\n        self.images = {}\n\n    def on_new_game_menu_clicked(self):\n        self.start_new_game()\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        position_of_click = self.controller.get_alphanumeric_position(\n            (clicked_row, clicked_column))\n        # on second click\n        if self.selected_piece_position:\n            self.shift(self.selected_piece_position, position_of_click)\n            self.selected_piece_position = None\n        self.update_highlight_list(position_of_click)\n        self.draw_board()\n        self.draw_all_pieces()\n\n    def shift(self, start_pos, end_pos):\n        selected_piece = self.controller.get_piece_at(start_pos)\n        piece_at_destination = self.controller.get_piece_at(end_pos)\n        if not piece_at_destination or piece_at_destination.color != selected_piece.color:\n            try:\n                self.controller.pre_move_validation(start_pos, end_pos)\n            except exceptions.ChessError as error:\n                self.info_label[\"text\"] = error.__class__.__name__\n            else:\n                self.update_label(selected_piece, start_pos, end_pos)\n\n    def update_label(self, piece, start_pos, end_pos):\n        turn = ('white' if piece.color == 'black' else 'black')\n        self.info_label[\"text\"] = '' + piece.color.capitalize() + \"  :  \" + \\\n            start_pos + end_pos + '    ' + turn.capitalize() + '\\'s turn'\n\n    def update_highlight_list(self, position):\n        self.all_squares_to_be_highlighted = None\n        try:\n            piece = self.controller.get_piece_at(position)\n        except:\n            piece = None\n        if piece and (piece.color == self.controller.player_turn()):\n            self.selected_piece_position = position\n            self.all_squares_to_be_highlighted = list(map(\n                self.controller.get_numeric_notation,\n                self.controller.get_piece_at(position).moves_available(position)))\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def draw_board(self):\n        current_color = BOARD_COLOR_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                if(self.all_squares_to_be_highlighted and (row, col) in self.all_squares_to_be_highlighted):\n                    self.canvas.create_rectangle(\n                        x1, y1, x2, y2,  fill=HIGHLIGHT_COLOR)\n                else:\n                    self.canvas.create_rectangle(\n                        x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def calculate_piece_coordinate(self, row, col):\n        x0 = (col * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        y0 = ((7 - row) * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        return (x0, y0)\n\n    def draw_single_piece(self, position, piece):\n        x, y = self.controller.get_numeric_notation(position)\n        if piece:\n            filename = \"../pieces_image/{}_{}.png\".format(\n                piece.name.lower(), piece.color)\n            if filename not in self.images:\n                self.images[filename] = PhotoImage(file=filename)\n            x0, y0 = self.calculate_piece_coordinate(x, y)\n            self.canvas.create_image(x0, y0, image=self.images[\n                                     filename], tags=(\"occupied\"), anchor=\"c\")\n\n    def draw_all_pieces(self):\n        self.canvas.delete(\"occupied\")\n        for position, piece in self.controller.get_all_peices_on_chess_board():\n            self.draw_single_piece(position, piece)\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n\ndef main(model):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, model)\n    root.mainloop()\n\n\ndef init_new_game():\n    initial_game_data = controller.Controller()\n    main(initial_game_data)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/4.07/chess_options.ini",
    "content": "[chess_colors]\nboard_color_1 = #59a803\nboard_color_2 = #8b83d9\nhighlight_color = #b92129\n\n"
  },
  {
    "path": "Chapter 04/4.07/configurations.py",
    "content": "\"\"\"\nCode illustration: 4.07\n    \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom configparser import ConfigParser\n\nNUMBER_OF_ROWS = 8\nNUMBER_OF_COLUMNS = 8\nDIMENSION_OF_EACH_SQUARE = 64\nX_AXIS_LABELS = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')\nY_AXIS_LABELS = (1, 2, 3, 4, 5, 6, 7, 8)\n\nSTART_PIECES_POSITION = {\n    \"A8\": \"r\", \"B8\": \"n\", \"C8\": \"b\", \"D8\": \"q\", \"E8\": \"k\", \"F8\": \"b\", \"G8\": \"n\", \"H8\": \"r\",\n    \"A7\": \"p\", \"B7\": \"p\", \"C7\": \"p\", \"D7\": \"p\", \"E7\": \"p\", \"F7\": \"p\", \"G7\": \"p\", \"H7\": \"p\",\n    \"A2\": \"P\", \"B2\": \"P\", \"C2\": \"P\", \"D2\": \"P\", \"E2\": \"P\", \"F2\": \"P\", \"G2\": \"P\", \"H2\": \"P\",\n    \"A1\": \"R\", \"B1\": \"N\", \"C1\": \"B\", \"D1\": \"Q\", \"E1\": \"K\", \"F1\": \"B\", \"G1\": \"N\", \"H1\": \"R\"\n}\n\n\nSHORT_NAME = {'R': 'Rook',  'N': 'Knight',  'B': 'Bishop',  'Q': 'Queen',\n              'K': 'King',  'P': 'Pawn'}\n\n\nORTHOGONAL_POSITIONS = ((-1, 0), (0, 1), (1, 0), (0, -1))\nDIAGONAL_POSITIONS = ((-1, -1), (-1, 1), (1, -1), (1, 1))\nKNIGHT_POSITIONS = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),\n                    (1, -2), (1, 2), (2, -1), (2, 1))\n\n\n'''\nUser Modifiable Options\n'''\nconfig = ConfigParser()\nconfig.read('chess_options.ini')\nBOARD_COLOR_1 = config.get('chess_colors', 'board_color_1', fallback=\"#e6a803\")\nBOARD_COLOR_2 = config.get('chess_colors', 'board_color_2', fallback=\"#8b8350\")\nHIGHLIGHT_COLOR = config.get(\n    'chess_colors', 'highlight_color', fallback=\"#2EF70D\")\n"
  },
  {
    "path": "Chapter 04/4.07/controller.py",
    "content": "\"\"\"\nCode illustration: 4.07\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport model\nimport piece\n\n\nclass Controller():\n\n    def __init__(self):\n        self.init_model()\n\n    def init_model(self):\n        self.model = model.Model()\n\n    def reset_game_data(self):\n        self.model.reset_game_data()\n\n    def reset_to_initial_locations(self):\n        self.model.reset_to_initial_locations()\n\n    def get_alphanumeric_position(self, rowcolumntuple):\n        return self.model.get_alphanumeric_position(rowcolumntuple)\n\n    def get_numeric_notation(self, rowcol):\n        return piece.get_numeric_notation(rowcol)\n\n    def get_piece_at(self, position_of_click):\n        return self.model.get_piece_at(position_of_click)\n\n    def pre_move_validation(self, start_pos, end_pos):\n        return self.model.pre_move_validation(start_pos, end_pos)\n\n    def get_all_peices_on_chess_board(self):\n        return self.model.items()\n\n    def player_turn(self):\n        return self.model.player_turn\n\n    def moves_available(self, position):\n        return self.model.moves_available(position)\n"
  },
  {
    "path": "Chapter 04/4.07/exceptions.py",
    "content": "\"\"\"\nCode illustration: 4.07\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nclass ChessError(Exception): pass\nclass Check(ChessError): pass\nclass InvalidMove(ChessError): pass\nclass CheckMate(ChessError): pass\nclass Draw(ChessError): pass\nclass NotYourTurn(ChessError): pass\nclass InvalidCoord(ChessError): pass\n"
  },
  {
    "path": "Chapter 04/4.07/model.py",
    "content": "\"\"\"\nCode illustration: 4.07\n        \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nfrom copy import deepcopy\nimport exceptions\nimport piece\nfrom configurations import *\n\n\nclass Model(dict):\n\n    captured_pieces = {'white': [], 'black': []}\n    player_turn = None\n    halfmove_clock = 0\n    fullmove_number = 1\n    history = []\n\n    def __init__(self):\n        self.reset_to_initial_locations()\n\n    def update_game_statistics(self, piece, dest, p1, p2):\n        if piece.color == 'black':\n            self.fullmove_number += 1\n        self.halfmove_clock += 1\n        abbr = piece.name\n        if abbr == 'pawn':\n            abbr = ''\n            self.halfmove_clock = 0\n        if dest is None:\n            movetext = abbr + p2.lower()\n        else:\n            movetext = abbr + 'x' + p2.lower()\n            self.halfmove_clock = 0\n        self.history.append(movetext)\n\n    def change_player_turn(self, color):\n        enemy = ('white' if color == 'black' else 'black')\n        self.player_turn = enemy\n\n    def pre_move_validation(self, initial_pos, final_pos):\n        initial_pos, final_pos = initial_pos.upper(), final_pos.upper()\n        piece = self.get_piece_at(initial_pos)\n        try:\n            piece_at_destination = self.get_piece_at(final_pos)\n        except:\n            piece_at_destination = None\n        if self.player_turn != piece.color:\n            raise exceptions.NotYourTurn(\"Not \" + piece.color + \"'s turn!\")\n        enemy = ('white' if piece.color == 'black' else 'black')\n        moves_available = piece.moves_available(initial_pos)\n        if final_pos not in moves_available:\n            raise exceptions.InvalidMove\n        if self.get_all_available_moves(enemy):\n            if self.will_move_cause_check(initial_pos, final_pos):\n                raise exceptions.Check\n        if not moves_available and self.is_king_under_check(piece.color):\n            raise exceptions.CheckMate\n        elif not moves_available:\n            raise exceptions.Draw\n        else:\n            self.move(initial_pos, final_pos)\n            self.update_game_statistics(\n                piece, piece_at_destination, initial_pos, final_pos)\n            self.change_player_turn(piece.color)\n\n    def move(self, start_pos, final_pos):\n        self[final_pos] = self.pop(start_pos, None)\n\n    def will_move_cause_check(self, start_position, end_position):\n        tmp = deepcopy(self)\n        tmp.move(start_position, end_position)\n        return tmp.is_king_under_check(self[start_position].color)\n\n    def get_all_available_moves(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece and piece.color == color:\n                moves = piece.moves_available(position)\n                if moves:\n                    result.extend(moves)\n        return result\n\n    def is_king_under_check(self, color):\n        position_of_king = self.get_alphanumeric_position_of_king(color)\n        opponent = ('black' if color == 'white' else 'white')\n        return position_of_king in self.get_all_available_moves(opponent)\n\n    def get_alphanumeric_position_of_king(self, color):\n        for position in self.keys():\n            this_piece = self.get_piece_at(position)\n            if isinstance(this_piece, piece.King) and this_piece.color == color:\n                return position\n\n    def all_positions_occupied_by_color(self, color):\n        result = []\n        for position in self.keys():\n            piece = self.get_piece_at(position)\n            if piece.color == color:\n                result.append(position)\n        return result\n\n    def all_occupied_positions(self):\n        return self.all_positions_occupied_by_color('white') + self.all_positions_occupied_by_color('black')\n\n    def reset_game_data(self):\n        captured_pieces = {'white': [], 'black': []}\n        player_turn = None\n        halfmove_clock = 0\n        fullmove_number = 1\n        history = []\n\n    def reset_to_initial_locations(self):\n        self.clear()\n        for position, value in START_PIECES_POSITION.items():\n            self[position] = piece.create_piece(value)\n            self[position].keep_reference(self)\n        self.player_turn = 'white'\n\n    def get_piece_at(self, position):\n        return self.get(position)\n\n    def get_alphanumeric_position(self, rowcol):\n        if self.is_on_board(rowcol):\n            row, col = rowcol\n            return \"{}{}\".format(X_AXIS_LABELS[col], Y_AXIS_LABELS[row])\n\n    def is_on_board(self, rowcol):\n        row, col = rowcol\n        return 0 <= row <= 7 and 0 <= col <= 7\n"
  },
  {
    "path": "Chapter 04/4.07/piece.py",
    "content": "\"\"\"\nCode illustration: 4.07\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom configurations import *\nimport sys\nimport exceptions\n\n\ndef create_piece(piece, color='white'):\n    if isinstance(piece, str):\n        if piece.upper() in SHORT_NAME.keys():\n            color = \"white\" if piece.isupper() else \"black\"\n            piece = SHORT_NAME[piece.upper()]\n        piece = piece.capitalize()\n        if piece in SHORT_NAME.values():\n            return eval(\"{classname}(color)\".format(classname=piece))\n    raise exceptions.ChessError(\"invalid piece name: '{}'\".format(piece))\n\n\ndef get_numeric_notation(rowcol):\n    row, col = rowcol\n    return int(col) - 1, X_AXIS_LABELS.index(row)\n\n\nclass Piece():\n\n    def __init__(self, color):\n        self.name = self.__class__.__name__.lower()\n        if color == 'black':\n            self.name = self.name.lower()\n        elif color == 'white':\n            self.name = self.name.upper()\n        self.color = color\n\n    def keep_reference(self, model):\n        self.model = model\n\n    def moves_available(self, current_position, directions, distance):\n        model = self.model\n        allowed_moves = []\n        piece = self\n        start_row, start_column = get_numeric_notation(current_position)\n        for x, y in directions:\n            collision = False\n            for step in range(1, distance + 1):\n                if collision:\n                    break\n                destination = start_row + step * x, start_column + step * y\n                if self.possible_position(destination) not in model.all_occupied_positions():\n                    allowed_moves.append(destination)\n                elif self.possible_position(destination) in model.all_positions_occupied_by_color(piece.color):\n                    collision = True\n                else:\n                    allowed_moves.append(destination)\n                    collision = True\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n    def possible_position(self, destination):\n        return self.model.get_alphanumeric_position(destination)\n\n\nclass King(Piece):\n\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 1\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Queen(Piece):\n\n    directions = ORTHOGONAL_POSITIONS + DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Rook(Piece):\n\n    directions = ORTHOGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Bishop(Piece):\n\n    directions = DIAGONAL_POSITIONS\n    max_distance = 8\n\n    def moves_available(self, current_position):\n        return super().moves_available(current_position, self.directions, self.max_distance)\n\n\nclass Knight(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        allowed_moves = []\n        start_col, start_row = get_numeric_notation(current_position)\n        piece = model.get(current_position.upper())\n        for x, y in KNIGHT_POSITIONS:\n            destination = start_col + x, start_row + y\n            if model.get_alphanumeric_position(destination) not in model.all_positions_occupied_by_color(piece.color):\n                allowed_moves.append(destination)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n\n\nclass Pawn(Piece):\n\n    def moves_available(self, current_position):\n        model = self.model\n        piece = self\n        if self.color == 'white':\n            initial_row_position, direction, enemy = 1, 1, 'black'\n        else:\n            initial_row_position, direction, enemy = 6, -1, 'white'\n        allowed_moves = []\n        # Moving\n        prohibited = model.all_occupied_positions()\n        start_col, start_row = get_numeric_notation(current_position)\n        forward = start_col + direction, start_row\n        if model.get_alphanumeric_position(forward) not in prohibited:\n            allowed_moves.append(forward)\n            if start_col == initial_row_position:\n                # If pawn is in starting position allow double moves\n                double_forward = (forward[0] + direction, forward[1])\n                if model.get_alphanumeric_position(double_forward) not in prohibited:\n                    allowed_moves.append(double_forward)\n        # Attacking\n        for a in range(-1, 2, 2):\n            attack = start_col + direction, start_row + a\n            if model.get_alphanumeric_position(attack) in model.all_positions_occupied_by_color(enemy):\n                allowed_moves.append(attack)\n        allowed_moves = filter(model.is_on_board, allowed_moves)\n        return map(model.get_alphanumeric_position, allowed_moves)\n"
  },
  {
    "path": "Chapter 04/4.07/preferenceswindow.py",
    "content": "\"\"\"\nCode illustration: 4.07\n\n    this entire file added here\n    \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nimport sys\nfrom tkinter import *\nfrom tkinter import messagebox\nfrom tkinter.ttk import *\nfrom tkinter.colorchooser import *\nfrom configparser import ConfigParser\nimport configurations\n\n\nclass PreferencesWindow():\n\n    def __init__(self, view):\n        self.parent = view.parent\n        self.fill_preference_colors()\n        self.view = view\n        self.create_prefereces_window()\n\n    def fill_preference_colors(self):\n        self.board_color_1 = configurations.BOARD_COLOR_1\n        self.board_color_2 = configurations.BOARD_COLOR_2\n        self.highlight_color = configurations.HIGHLIGHT_COLOR\n\n    def set_color_1(self):\n        self.board_color_1 = askcolor(initialcolor=self.board_color_1)[-1]\n\n    def set_color_2(self):\n        self.board_color_2 = askcolor(initialcolor=self.board_color_2)[-1]\n\n    def set_highlight_color(self):\n        self.highlight_color = askcolor(initialcolor=self.highlight_color)[-1]\n\n    def create_prefereces_window(self):\n        self.pref_window = Toplevel(self.parent)\n        self.pref_window.title(\"set chess preferences\")\n        self.create_prefereces_list()\n        self.pref_window.transient(self.parent)\n\n    def create_prefereces_list(self):\n        Label(self.pref_window, text=\"Board Color 1\").grid(\n            row=1, sticky=W, padx=5, pady=5)\n        Label(self.pref_window, text=\"Board Color 2\").grid(\n            row=2, sticky=W, padx=5, pady=5)\n        Label(self.pref_window, text=\"Highlight Color\").grid(\n            row=3, sticky=W, padx=5, pady=5)\n        self.board_color_1_button = Button(\n            self.pref_window, text='Select Board Color 1', command=self.set_color_1)\n        self.board_color_1_button.grid(\n            row=1, column=1, columnspan=2, sticky=E, padx=5, pady=5)\n        self.board_color_2_button = Button(\n            self.pref_window, text='Select Board Color 2', command=self.set_color_2)\n        self.board_color_2_button.grid(\n            row=2, column=1, columnspan=2, sticky=E, padx=5, pady=5)\n        self.highlight_color_button = Button(\n            self.pref_window, text='Select Highlight Color', command=self.set_highlight_color)\n        self.highlight_color_button.grid(\n            row=3, column=1, columnspan=2, sticky=E, padx=5, pady=5)\n        Button(self.pref_window, text=\"Save\", command=self.on_save_button_clicked).grid(\n            row=4, column=2, sticky=E, padx=5, pady=5)\n        Button(self.pref_window, text=\"Cancel\", command=self.on_cancel_button_clicked).grid(\n            row=4, column=1, sticky=E, padx=5, pady=5)\n\n    def on_save_button_clicked(self):\n        self.set_new_values()\n        self.pref_window.destroy()\n        self.view.reload_colors(\n            self.board_color_1, self.board_color_2, self.highlight_color)\n\n    def set_new_values(self):\n        config = ConfigParser()\n        config.read('chess_options.ini')\n        config.set('chess_colors', 'board_color_1', self.board_color_1)\n        config.set('chess_colors', 'board_color_2', self.board_color_2)\n        config.set('chess_colors', 'highlight_color', self.highlight_color)\n        configurations.BOARD_COLOR_1 = self.board_color_1\n        configurations.BOARD_COLOR_2 = self.board_color_2\n        configurations.HIGHLIGHT_COLOR = self.highlight_color\n        with open('chess_options.ini', 'w') as config_file:\n            config.write(config_file)\n\n    def on_cancel_button_clicked(self):\n        self.pref_window.destroy()\n"
  },
  {
    "path": "Chapter 04/4.07/view.py",
    "content": "\"\"\"\nCode illustration: 4.07\n\n    new import\n        import preferenceswindow\n\n\n    new attributes added here:\n        board_color_1 = BOARD_COLOR_1\n        board_color_2 = BOARD_COLOR_2\n        highlight_color = HIGHLIGHT_COLOR\n\n    new methods added here:\n        reload_colors(color_1, color_2, highlight_color)\n\n    methods modified here:\n        replaces all color constants with color instance variables in these two methods:\n            draw_board()\n            alternate_color(current_color)\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Menu, Label, Frame, Canvas, RIGHT, PhotoImage, messagebox\nimport controller\nimport exceptions\nfrom configurations import *\nimport preferenceswindow\n\n\nclass View():\n\n    selected_piece_position = None\n    all_squares_to_be_highlighted = []\n    images = {}\n    board_color_1 = BOARD_COLOR_1\n    board_color_2 = BOARD_COLOR_2\n    highlight_color = HIGHLIGHT_COLOR\n\n    def __init__(self, parent, controller):\n        self.controller = controller\n        self.parent = parent\n        self.create_chess_base()\n        self.canvas.bind(\"<Button-1>\", self.on_square_clicked)\n        self.start_new_game()\n\n    def reload_colors(self, color_1, color_2, highlight_color):\n        self.board_color_1 = color_1\n        self.board_color_2 = color_2\n        self.highlight_color = highlight_color\n        self.draw_board()\n        self.draw_all_pieces()\n\n    def on_preference_menu_clicked(self):\n        self.show_preferences_window()\n\n    def show_preferences_window(self):\n        preferenceswindow.PreferencesWindow(self)\n\n    def create_bottom_frame(self):\n        self.bottom_frame = Frame(self.parent, height=64)\n        self.info_label = Label(\n            self.bottom_frame, text=\"   White to Start the Game  \")\n        self.info_label.pack(side=RIGHT, padx=8, pady=5)\n        self.bottom_frame.pack(fill=\"x\", side=\"bottom\")\n\n    def create_top_menu(self):\n        self.menu_bar = Menu(self.parent)\n        self.create_file_menu()\n        self.create_edit_menu()\n        self.create_about_menu()\n\n    def create_file_menu(self):\n        self.file_menu = Menu(self.menu_bar, tearoff=0)\n        self.file_menu.add_command(\n            label=\"New Game\", command=self.on_new_game_menu_clicked)\n        self.menu_bar.add_cascade(label=\"File\", menu=self.file_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_edit_menu(self):\n        self.edit_menu = Menu(self.menu_bar, tearoff=0)\n        self.edit_menu.add_command(\n            label=\"Preferences\", command=self.on_preference_menu_clicked)\n        self.menu_bar.add_cascade(label=\"Edit\", menu=self.edit_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_about_menu(self):\n        self.about_menu = Menu(self.menu_bar, tearoff=0)\n        self.about_menu.add_command(\n            label=\"About\", command=self.on_about_menu_clicked)\n        self.menu_bar.add_cascade(label=\"About\", menu=self.about_menu)\n        self.parent.config(menu=self.menu_bar)\n\n    def create_canvas(self):\n        canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE\n        canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE\n        self.canvas = Canvas(\n            self.parent, width=canvas_width, height=canvas_height)\n        self.canvas.pack(padx=8, pady=8)\n\n    def create_chess_base(self):\n        self.create_top_menu()\n        self.create_canvas()\n        self.draw_board()\n        self.create_bottom_frame()\n\n    def start_new_game(self):\n        self.controller.reset_game_data()\n        self.controller.reset_to_initial_locations()\n        self.draw_all_pieces()\n        self.info_label.config(text=\"   White to Start the Game  \")\n\n    def reset_board_state(self):\n        self.selected_piece_position = None\n        self.all_squares_to_be_highlighted = []\n        self.images = {}\n\n    def on_new_game_menu_clicked(self):\n        self.start_new_game()\n\n    def get_clicked_row_column(self, event):\n        col_size = row_size = DIMENSION_OF_EACH_SQUARE\n        clicked_column = event.x // col_size\n        clicked_row = 7 - (event.y // row_size)\n        return (clicked_row, clicked_column)\n\n    def on_square_clicked(self, event):\n        clicked_row, clicked_column = self.get_clicked_row_column(event)\n        position_of_click = self.controller.get_alphanumeric_position(\n            (clicked_row, clicked_column))\n        # on second click\n        if self.selected_piece_position:\n            self.shift(self.selected_piece_position, position_of_click)\n            self.selected_piece_position = None\n        self.update_highlight_list(position_of_click)\n        self.draw_board()\n        self.draw_all_pieces()\n\n    def shift(self, start_pos, end_pos):\n        selected_piece = self.controller.get_piece_at(start_pos)\n        piece_at_destination = self.controller.get_piece_at(end_pos)\n        if not piece_at_destination or piece_at_destination.color != selected_piece.color:\n            try:\n                self.controller.pre_move_validation(start_pos, end_pos)\n            except exceptions.ChessError as error:\n                self.info_label[\"text\"] = error.__class__.__name__\n            else:\n                self.update_label(selected_piece, start_pos, end_pos)\n\n    def update_label(self, piece, start_pos, end_pos):\n        turn = ('white' if piece.color == 'black' else 'black')\n        self.info_label[\"text\"] = '' + piece.color.capitalize() + \"  :  \" + \\\n            start_pos + end_pos + '    ' + turn.capitalize() + '\\'s turn'\n\n    def update_highlight_list(self, position):\n        self.all_squares_to_be_highlighted = None\n        try:\n            piece = self.controller.get_piece_at(position)\n        except:\n            piece = None\n        if piece and (piece.color == self.controller.player_turn()):\n            self.selected_piece_position = position\n            self.all_squares_to_be_highlighted = list(map(\n                self.controller.get_numeric_notation,\n                self.controller.get_piece_at(position).moves_available(position)))\n\n    def get_x_y_coordinate(self, row, col):\n        x = (col * DIMENSION_OF_EACH_SQUARE)\n        y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)\n        return (x, y)\n\n    def draw_board(self):\n        current_color = self.board_color_2\n        for row in range(NUMBER_OF_ROWS):\n            current_color = self.get_alternate_color(current_color)\n            for col in range(NUMBER_OF_COLUMNS):\n                x1, y1 = self.get_x_y_coordinate(row, col)\n                x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE\n                if(self.all_squares_to_be_highlighted and (row, col) in self.all_squares_to_be_highlighted):\n                    self.canvas.create_rectangle(\n                        x1, y1, x2, y2,  fill=self.highlight_color)\n                else:\n                    self.canvas.create_rectangle(\n                        x1, y1, x2, y2,  fill=current_color)\n                current_color = self.get_alternate_color(current_color)\n\n    def get_alternate_color(self, current_color):\n        if current_color == self.board_color_2:\n            next_color = self.board_color_1\n        else:\n            next_color = self.board_color_2\n        return next_color\n\n    def calculate_piece_coordinate(self, row, col):\n        x0 = (col * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        y0 = ((7 - row) * DIMENSION_OF_EACH_SQUARE) + \\\n            int(DIMENSION_OF_EACH_SQUARE / 2)\n        return (x0, y0)\n\n    def draw_single_piece(self, position, piece):\n        x, y = self.controller.get_numeric_notation(position)\n        if piece:\n            filename = \"../pieces_image/{}_{}.png\".format(\n                piece.name.lower(), piece.color)\n            if filename not in self.images:\n                self.images[filename] = PhotoImage(file=filename)\n            x0, y0 = self.calculate_piece_coordinate(x, y)\n            self.canvas.create_image(x0, y0, image=self.images[\n                                     filename], tags=(\"occupied\"), anchor=\"c\")\n\n    def draw_all_pieces(self):\n        self.canvas.delete(\"occupied\")\n        for position, piece in self.controller.get_all_peices_on_chess_board():\n            self.draw_single_piece(position, piece)\n\n    def on_about_menu_clicked(self):\n        messagebox.showinfo(\"From the Book:\",\n                            \"Tkinter GUI Application\\n Development Blueprints\")\n\n\ndef main(model):\n    root = Tk()\n    root.title(\"Chess\")\n    View(root, model)\n    root.mainloop()\n\n\ndef init_new_game():\n    initial_game_data = controller.Controller()\n    main(initial_game_data)\n\nif __name__ == \"__main__\":\n    init_new_game()\n"
  },
  {
    "path": "Chapter 04/readme.txt",
    "content": "====================================================================\nCode Readme\nTkinter GUI Application Development Blueprints\nChapter 4: Game of Chess\n====================================================================\nList of code samples:\n\nCode 4.01: Defining the file structure and creating the chess Board\nCode 4.02: Defining data structure \nCode 4.03: Adding pieces on board\nCode 4.04: Enforcing rules for pieces\nCode 4.05: Enforcing chess board logic\nCode 4.06: Making the game functional\nCode 4.07: Using ConfigParser to save user preferences\n\n\nDirectory pieces_image contains all images used in the program\n"
  },
  {
    "path": "Chapter 05/5.01/model.py",
    "content": "\"\"\"\nCode illustration: 5.01\n\n@Tkinter GUI Application Development Blueprints\n\"\"\" \n\nclass Model:\n    \n    def __init__(self):\n        pass\n    \n    \n"
  },
  {
    "path": "Chapter 05/5.01/player.py",
    "content": "\"\"\"\nCode illustration: 5.01\n\n@Tkinter GUI Application Development Blueprints\n\"\"\" \n\nimport pyglet\n\nclass Player:\n    \n    def __init__(self):\n        pass        \n   \n    \n"
  },
  {
    "path": "Chapter 05/5.01/view.py",
    "content": "\"\"\"\nCode illustration: 5.01\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\n\nimport model\nimport player\n\n\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_previous_track_button_clicked(self):\n        pass\n\n    def on_rewind_button_clicked(self):\n        pass\n\n    def on_play_stop_button_clicked(self):\n        pass\n\n    def on_pause_unpause_button_clicked(self):\n        pass\n\n    def on_mute_unmute_button_clicked(self):\n        pass\n\n    def on_fast_forward_button_clicked(self):\n        pass\n\n    def on_next_track_button_clicked(self):\n        pass\n\n    def on_volume_scale_changed(self, value):\n        pass\n\n    def on_add_file_button_clicked(self):\n        pass\n\n    def on_remove_selected_button_clicked(self):\n        pass\n\n    def on_add_directory_button_clicked(self):\n        pass\n\n    def on_clear_play_list_button_clicked(self):\n        pass\n\n    def on_remove_selected_context_menu_clicked(self):\n        pass\n\n    def on_play_list_double_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.02/model.py",
    "content": "\"\"\"\nCode illustration: 5.02\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.02/player.py",
    "content": "\"\"\"\nCode illustration: 5.02\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.02/view.py",
    "content": "\"\"\"\nCode illustration: 5.02\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\n\nimport model\nimport player\n\n\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_previous_track_button_clicked(self):\n        pass\n\n    def on_rewind_button_clicked(self):\n        pass\n\n    def on_play_stop_button_clicked(self):\n        pass\n\n    def on_pause_unpause_button_clicked(self):\n        pass\n\n    def on_mute_unmute_button_clicked(self):\n        pass\n\n    def on_fast_forward_button_clicked(self):\n        pass\n\n    def on_next_track_button_clicked(self):\n        pass\n\n    def on_volume_scale_changed(self, value):\n        pass\n\n    def on_add_file_button_clicked(self):\n        pass\n\n    def on_remove_selected_button_clicked(self):\n        pass\n\n    def on_add_directory_button_clicked(self):\n        pass\n\n    def on_clear_play_list_button_clicked(self):\n        pass\n\n    def on_remove_selected_context_menu_clicked(self):\n        pass\n\n    def on_play_list_double_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.03/model.py",
    "content": "\"\"\"\nCode illustration: 5.03\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.03/player.py",
    "content": "\"\"\"\nCode illustration: 5.03\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.03/view.py",
    "content": "\"\"\"\nCode illustration: 5.03\n    \n    New imports here:\n        import os\n    \n    Methods modified here:\n        on_add_file_button_clicked()\n        on_remove_selected_button_clicked()\n        on_add_directory_button_clicked()\n        on_clear_play_list_button_clicked()\n        \n    New methods added here:\n        add_audio_file()\n        remove_selected_files()\n        add_all_audio_files_from_directory() \n        get_all_audio_file_from_directory(directory_path)\n        clear_play_list()\n        \n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\n\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_previous_track_button_clicked(self):\n        pass\n\n    def on_rewind_button_clicked(self):\n        pass\n\n    def on_play_stop_button_clicked(self):\n        pass\n\n    def on_pause_unpause_button_clicked(self):\n        pass\n\n    def on_mute_unmute_button_clicked(self):\n        pass\n\n    def on_fast_forward_button_clicked(self):\n        pass\n\n    def on_next_track_button_clicked(self):\n        pass\n\n    def on_volume_scale_changed(self, value):\n        pass\n\n    def on_play_list_double_clicked(self, event=None):\n        pass\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.04/model.py",
    "content": "\"\"\"\nCode illustration: 5.04\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.04/player.py",
    "content": "\"\"\"\nCode illustration: 5.04\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.04/view.py",
    "content": "\"\"\"\nCode illustration: 5.04\n    \n    New modules imported here:\n        import itertools\n\n    New attributes added here:\n        current_track_index\n        toggle_play_stop\n        toggle_pause_unpause\n        toggle_mute_unmute\n        \n        \n    Methods modified here:\n        on_play_stop_button_clicked()\n        on_pause_unpause_button_clicked()\n        on_mute_unmute_button_clicked()\n        on_previous_track_button_clicked()\n        on_rewind_button_clicked()\n        on_fast_forward_button_clicked()\n        on_next_track_button_clicked()\n        on_volume_scale_changed(value)\n        on_play_list_double_clicked()\n        \n    Methods added here:\n        start_play()\n        stop_play()\n        play_previous_track()\n        play_next_track()\n    \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.05/model.py",
    "content": "\"\"\"\nCode illustration: 5.05\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.05/player.py",
    "content": "\"\"\"\nCode illustration: 5.05\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.05/seekbar.py",
    "content": "\"\"\"\nCode illustration: 5.05\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nimport tkinter as tk\n\nclass Seekbar(tk.Canvas):\n\n    def __init__(self, parent, **options):\n        tk.Canvas.__init__(self, parent, options)\n        self.parent = parent\n        self.width = options['width']\n        self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill=\"red\")\n        self.seekbar_knob_image = tk.PhotoImage(file=\"../icons/seekbar_knob.gif\")\n        self.seekbar_knob = self.create_image(\n            0, 0, image=self.seekbar_knob_image)\n        self.bind_mouse_button()\n\n    def bind_mouse_button(self):\n        self.bind('<Button-1>', self.on_seekbar_clicked)\n        self.bind('<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked)\n\n    def on_seekbar_clicked(self, event=None):\n        if event.x > 0 and event.x < self.width:\n            self.slide_to_position(event.x)\n\n    def slide_to_position(self, new_position):\n        self.coords(self.red_rectangle, 0, 0, new_position, new_position)\n        self.coords(self.seekbar_knob, new_position, 0)\n        self.event_generate(\"<<SeekbarPositionChanged>>\", x=new_position)\n\n\nclass TestSeekBar():\n\n    def __init__(self):\n        root = tk.Tk()\n        root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n        frame = tk.Frame(root)\n        frame.grid(row=1, pady=10, padx=10)\n        c = Seekbar(\n            frame, background=\"blue\", width=360, height=10)\n        c.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        root.mainloop()\n\n    def seek_new_position(self, event):\n        print(\"Dragged to x:\", event.x)\n\nif __name__ == '__main__':\n    TestSeekBar()\n\n"
  },
  {
    "path": "Chapter 05/5.05/view.py",
    "content": "\"\"\"\nCode illustration: 5.05\n    \n    New modules imported here:\n        from seekbar import *\n    \n    New constants added here:\n        SEEKBAR_WIDTH = 360\n        \n    Methods modified here:\n        create_top_display() - added a call to create the newly defined Seekbar widget\n        \n   \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\nfrom seekbar import *\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\nSEEKBAR_WIDTH = 360\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        self.seek_bar = Seekbar(\n            frame, background=\"blue\", width=SEEKBAR_WIDTH, height=10)\n        self.seek_bar.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.06/helpers.py",
    "content": "\"\"\"\nCode illustration: 5.06\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\ndef get_time_in_minute_seconds(time_in_seconds):\n    minutes = int(time_in_seconds / 60)\n    seconds = int(time_in_seconds % 60)\n    return (minutes, seconds)\n\n\ndef truncate_text(text, truncate_length):\n    truncate_length_plus_two = truncate_length + 2  # account for double dots\n    return (text[:truncate_length_plus_two] + '..') if len(text) > truncate_length else text\n"
  },
  {
    "path": "Chapter 05/5.06/model.py",
    "content": "\"\"\"\nCode illustration: 5.06\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.06/player.py",
    "content": "\"\"\"\nCode illustration: 5.06\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.06/seekbar.py",
    "content": "\"\"\"\nCode illustration: 5.06\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\nclass Seekbar(tk.Canvas):\n\n    def __init__(self, parent, **options):\n        tk.Canvas.__init__(self, parent, options)\n        self.parent = parent\n        self.width = options['width']\n        self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill=\"red\")\n        self.seekbar_knob_image = tk.PhotoImage(file=\"../icons/seekbar_knob.gif\")\n        self.seekbar_knob = self.create_image(\n            0, 0, image=self.seekbar_knob_image)\n        self.bind_mouse_button()\n\n    def bind_mouse_button(self):\n        self.bind('<Button-1>', self.on_seekbar_clicked)\n        self.bind('<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked)\n\n    def on_seekbar_clicked(self, event=None):\n        if event.x > 0 and event.x < self.width:\n            self.slide_to_position(event.x)\n\n    def slide_to_position(self, new_position):\n        self.coords(self.red_rectangle, 0, 0, new_position, new_position)\n        self.coords(self.seekbar_knob, new_position, 0)\n        self.event_generate(\"<<SeekbarPositionChanged>>\", x=new_position)\n\n\nclass TestSeekBar():\n\n    def __init__(self):\n        root = tk.Tk()\n        root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n        frame = tk.Frame(root)\n        frame.grid(row=1, pady=10, padx=10)\n        c = Seekbar(\n            frame, background=\"blue\", width=360, height=10)\n        c.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        root.mainloop()\n\n    def seek_new_position(self, event):\n        print(\"Dragged to x:\", event.x)\n\nif __name__ == '__main__':\n    TestSeekBar()\n"
  },
  {
    "path": "Chapter 05/5.06/view.py",
    "content": "\"\"\"\nCode illustration: 5.06\n    \n    New modules imported here:\n        from helpers import *\n    \n\n    Methods added here:\n        manage_one_time_track_updates_on_play_start(self):\n        update_now_playing_text()\n        current_track_position = 0\n        display_track_duration()\n   \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\nfrom seekbar import *\nfrom helpers import *\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\nSEEKBAR_WIDTH = 360\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        self.seek_bar = Seekbar(\n            frame, background=\"blue\", width=SEEKBAR_WIDTH, height=10)\n        self.seek_bar.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n        self.current_track_position = 0\n        self.manage_one_time_track_updates_on_play_start()\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n    def manage_one_time_track_updates_on_play_start(self):\n        self.update_now_playing_text()\n        self.display_track_duration()\n\n    def update_now_playing_text(self):\n        current_track = self.model.play_list[self.current_track_index]\n        file_path, file_name = os.path.split(current_track)\n        truncated_track_name = truncate_text(file_name, 40)\n        self.canvas.itemconfig(self.track_name, text=truncated_track_name)\n\n    def display_track_duration(self):\n        self.track_length = self.player.track_length\n        minutes, seconds = get_time_in_minute_seconds(self.track_length)\n        track_length_string = 'of {0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(\n            self.track_length_text, text=track_length_string)\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.07/helpers.py",
    "content": "\"\"\"\nCode illustration: 5.07\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\ndef get_time_in_minute_seconds(time_in_seconds):\n    minutes = int(time_in_seconds / 60)\n    seconds = int(time_in_seconds % 60)\n    return (minutes, seconds)\n\n\ndef truncate_text(text, truncate_length):\n    truncate_length_plus_two = truncate_length + 2  # account for double dots\n    return (text[:truncate_length_plus_two] + '..') if len(text) > truncate_length else text\n"
  },
  {
    "path": "Chapter 05/5.07/model.py",
    "content": "\"\"\"\nCode illustration: 5.07\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.07/player.py",
    "content": "\"\"\"\nCode illustration: 5.07\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.07/seekbar.py",
    "content": "\"\"\"\nCode illustration: 5.07\n\n    Method modified here:\n        on_seekbar_knob_clicked() - added a call to seek_new_position() from View class\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\nclass Seekbar(tk.Canvas):\n\n    def __init__(self, parent, **options):\n        tk.Canvas.__init__(self, parent, options)\n        self.parent = parent\n        self.width = options['width']\n        self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill=\"red\")\n        self.seekbar_knob_image = tk.PhotoImage(file=\"../icons/seekbar_knob.gif\")\n        self.seekbar_knob = self.create_image(\n            0, 0, image=self.seekbar_knob_image)\n        self.bind_mouse_button()\n\n    def bind_mouse_button(self):\n        self.bind('<Button-1>', self.on_seekbar_clicked)\n        self.bind('<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked)\n\n    def on_seekbar_clicked(self, event=None):\n        self.slide_to_position(event.x)\n\n    def slide_to_position(self, new_position):\n        if 0 <= new_position <= self.width:\n            self.coords(self.red_rectangle, 0, 0, new_position, new_position)\n            self.coords(self.seekbar_knob, new_position, 0)\n            self.event_generate(\"<<SeekbarPositionChanged>>\", x=new_position)\n\n\nclass TestSeekBar():\n\n    def __init__(self):\n        root = tk.Tk()\n        root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n        frame = tk.Frame(root)\n        frame.grid(row=1, pady=10, padx=10)\n        c = Seekbar(\n            frame, background=\"blue\", width=360, height=10)\n        c.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        root.mainloop()\n\n    def seek_new_position(self, event):\n        print(\"Dragged to x:\", event.x)\n\nif __name__ == '__main__':\n    TestSeekBar()\n"
  },
  {
    "path": "Chapter 05/5.07/view.py",
    "content": "\"\"\"\nCode illustration: 5.07\n\n    New methods added here:\n     manage_periodic_updates_during_play()\n     update_clock()\n     update_seek_bar()\n     seek_new_position()\n        \n     \n    Methods modified here:\n        start_play() - added a call to manage_periodic_updates_during_play\n    \n   \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\nfrom seekbar import *\nfrom helpers import *\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\nSEEKBAR_WIDTH = 360\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n        self.root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        self.seek_bar = Seekbar(\n            frame, background=\"blue\", width=SEEKBAR_WIDTH, height=10)\n        self.seek_bar.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n        self.current_track_position = 0\n        self.manage_one_time_track_updates_on_play_start()\n        self.manage_periodic_updates_during_play()\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n    def manage_one_time_track_updates_on_play_start(self):\n        self.update_now_playing_text()\n        self.display_track_duration()\n\n    def update_now_playing_text(self):\n        current_track = self.model.play_list[self.current_track_index]\n        file_path, file_name = os.path.split(current_track)\n        truncated_track_name = truncate_text(file_name, 40)\n        self.canvas.itemconfig(self.track_name, text=truncated_track_name)\n\n    def display_track_duration(self):\n        self.track_length = self.player.track_length\n        minutes, seconds = get_time_in_minute_seconds(self.track_length)\n        track_length_string = 'of {0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(\n            self.track_length_text, text=track_length_string)\n\n    def manage_periodic_updates_during_play(self):\n        self.update_clock()\n        self.update_seek_bar()\n        self.root.after(1000, self.manage_periodic_updates_during_play)\n\n    def update_clock(self):\n        self.elapsed_play_duration = self.player.elapsed_play_duration\n        minutes, seconds = get_time_in_minute_seconds(\n            self.elapsed_play_duration)\n        current_time_string = '{0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(self.clock, text=current_time_string)\n\n    def update_seek_bar(self):\n        seek_bar_position = SEEKBAR_WIDTH * \\\n            self.player.elapsed_play_duration / self.track_length\n        self.seek_bar.slide_to_position(seek_bar_position)\n\n    def seek_new_position(self, event=None):\n        time = self.player.track_length * event.x / SEEKBAR_WIDTH\n        self.player.seek(time)\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.08/helpers.py",
    "content": "\"\"\"\nCode illustration: 5.08\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\ndef get_time_in_minute_seconds(time_in_seconds):\n    minutes = int(time_in_seconds / 60)\n    seconds = int(time_in_seconds % 60)\n    return (minutes, seconds)\n\n\ndef truncate_text(text, truncate_length):\n    truncate_length_plus_two = truncate_length + 2  # account for double dots\n    return (text[:truncate_length_plus_two] + '..') if len(text) > truncate_length else text\n"
  },
  {
    "path": "Chapter 05/5.08/model.py",
    "content": "\"\"\"\nCode illustration: 5.08\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.08/player.py",
    "content": "\"\"\"\nCode illustration: 5.08\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, newvolume_level):\n        self.player.volume = newvolume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.08/seekbar.py",
    "content": "\"\"\"\nCode illustration: 5.08\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\nclass Seekbar(tk.Canvas):\n\n    def __init__(self, parent, **options):\n        tk.Canvas.__init__(self, parent, options)\n        self.parent = parent\n        self.width = options['width']\n        self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill=\"red\")\n        self.seekbar_knob_image = tk.PhotoImage(file=\"../icons/seekbar_knob.gif\")\n        self.seekbar_knob = self.create_image(\n            0, 0, image=self.seekbar_knob_image)\n        self.bind_mouse_button()\n\n    def bind_mouse_button(self):\n        self.bind('<Button-1>', self.on_seekbar_clicked)\n        self.bind('<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked)\n\n    def on_seekbar_clicked(self, event=None):\n        if event.x > 0 and event.x < self.width:\n            self.slide_to_position(event.x)\n\n    def slide_to_position(self, new_position):\n        self.coords(self.red_rectangle, 0, 0, new_position, new_position)\n        self.coords(self.seekbar_knob, new_position, 0)\n        self.event_generate(\"<<SeekbarPositionChanged>>\", x=new_position)\n\n\nclass TestSeekBar():\n\n    def __init__(self):\n        root = tk.Tk()\n        root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n        frame = tk.Frame(root)\n        frame.grid(row=1, pady=10, padx=10)\n        c = Seekbar(\n            frame, background=\"blue\", width=360, height=10)\n        c.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        root.mainloop()\n\n    def seek_new_position(self, event):\n        print(\"Dragged to x:\", event.x)\n\nif __name__ == '__main__':\n    TestSeekBar()\n\n"
  },
  {
    "path": "Chapter 05/5.08/view.py",
    "content": "\"\"\"\nCode illustration: 5.08\n\n    methods modified\n        manage_periodic_updates_during_play()\n        __init__  method - override of close \n        \n    new methods added here:\n        not_to_loop()\n        close_player()\n        \n        \n\n  \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\nimport model\nimport player\nfrom seekbar import *\nfrom helpers import *\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\nSEEKBAR_WIDTH = 360\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n        self.root.protocol('WM_DELETE_WINDOW', self.close_player)\n        self.root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        self.seek_bar = Seekbar(\n            frame, background=\"blue\", width=SEEKBAR_WIDTH, height=10)\n        self.seek_bar.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n        \n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n        self.current_track_position = 0\n        self.manage_one_time_track_updates_on_play_start()\n        self.manage_periodic_updates_during_play()\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n    def manage_one_time_track_updates_on_play_start(self):\n        self.update_now_playing_text()\n        self.display_track_duration()\n\n    def update_now_playing_text(self):\n        current_track = self.model.play_list[self.current_track_index]\n        file_path, file_name = os.path.split(current_track)\n        truncated_track_name = truncate_text(file_name, 40)\n        self.canvas.itemconfig(self.track_name, text=truncated_track_name)\n\n    def display_track_duration(self):\n        self.track_length = self.player.track_length\n        minutes, seconds = get_time_in_minute_seconds(self.track_length)\n        track_length_string = 'of {0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(\n            self.track_length_text, text=track_length_string)\n\n    def update_clock(self):\n        self.elapsed_play_duration = self.player.elapsed_play_duration\n        minutes, seconds = get_time_in_minute_seconds(\n            self.elapsed_play_duration)\n        current_time_string = '{0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(self.clock, text=current_time_string)\n\n    def update_seek_bar(self):\n        seek_bar_position = SEEKBAR_WIDTH * \\\n            self.player.elapsed_play_duration / self.track_length\n        self.seek_bar.slide_to_position(seek_bar_position)\n\n    def seek_new_position(self, event=None):\n        time = self.player.track_length * event.x / SEEKBAR_WIDTH\n        self.player.seek(time)\n\n    def manage_periodic_updates_during_play(self):\n        self.update_clock()\n        self.update_seek_bar()\n        if not self.player.is_playing():\n            if self.not_to_loop(): return\n        self.root.after(1000, self.manage_periodic_updates_during_play)\n\n    def not_to_loop(self):\n        selected_loop_choice = self.loop_value.get()\n        if selected_loop_choice == 1:\n            return True\n        elif selected_loop_choice == 2:\n            self.start_play()\n            return False\n        elif selected_loop_choice == 3:\n            self.play_next_track()\n            return True\n\n    def close_player(self):\n        self.player.stop()\n        self.root.destroy()\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/5.09/helpers.py",
    "content": "\"\"\"\nCode illustration: 5.09\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\ndef get_time_in_minute_seconds(time_in_seconds):\n    minutes = int(time_in_seconds / 60)\n    seconds = int(time_in_seconds % 60)\n    return (minutes, seconds)\n\n\ndef truncate_text(text, truncate_length):\n    truncate_length_plus_two = truncate_length + 2  # account for double dots\n    return (text[:truncate_length_plus_two] + '..') if len(text) > truncate_length else text\n"
  },
  {
    "path": "Chapter 05/5.09/model.py",
    "content": "\"\"\"\nCode illustration: 5.09\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\n\nclass Model:\n\n    def __init__(self):\n        self.__play_list = []\n\n    @property\n    def play_list(self):\n        return self.__play_list\n\n    def get_file_to_play(self, file_index):\n        return self.__play_list[file_index]\n\n    def clear_play_list(self):\n        self.__play_list.clear()\n\n    def add_to_play_list(self, file_name):\n        self.__play_list.append(file_name)\n\n    def remove_item_from_play_list_at_index(self, index):\n        del self.__play_list[index]\n"
  },
  {
    "path": "Chapter 05/5.09/player.py",
    "content": "\"\"\"\nCode illustration: 5.09\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport pyglet\n\nFORWARD_REWIND_JUMP_TIME = 20\n\n\nclass Player:\n\n    def __init__(self):\n        self.player = pyglet.media.Player()\n        self.player.volume = 0.6\n\n    def play_media(self, audio_file):\n        self.reset_player()\n        self.player = pyglet.media.Player()\n        self.source = pyglet.media.load(audio_file)\n        self.player.queue(self.source)\n        self.player.play()\n\n    def reset_player(self):\n        self.player.pause()\n        self.player.delete()\n        \n    def is_playing(self):\n        try:\n            elapsed_time = int(self.player.time)\n            is_playing =  elapsed_time < int(self.track_length)\n        except:\n            is_playing = False\n        return is_playing\n\n    def seek(self, time):\n        try:\n            self.player.seek(time)\n        except AttributeError:\n            pass\n\n    @property\n    def track_length(self):\n        try:\n            return self.source.duration\n        except AttributeError:\n            return 0\n\n    @property\n    def volume(self):\n        return self.player.volume\n\n    @property\n    def elapsed_play_duration(self):\n        return self.player.time\n\n    @volume.setter\n    def volume(self, volume):\n        self.player.volume = volume\n\n    def unpause(self):\n        self.player.play()\n\n    def pause(self):\n        self.player.pause()\n\n    def stop(self):\n        self.reset_player()\n\n    def mute(self):\n        self.player.volume = 0.0\n\n    def unmute(self, new_volume_level):\n        self.player.volume = new_volume_level\n\n    def fast_forward(self):\n        time = self.player.time + FORWARD_REWIND_JUMP_TIME\n        try:\n            if self.source.duration > time:\n                self.seek(time)\n            else:\n                self.seek(self.source.duration)\n        except AttributeError:\n            pass\n\n    def rewind(self):\n        time = self.player.time - FORWARD_REWIND_JUMP_TIME\n        try:\n            self.seek(time)\n        except:\n            self.seek(0)\n"
  },
  {
    "path": "Chapter 05/5.09/pygleterror.py",
    "content": "import pyglet\n\naudio_file = 'test.mp3'\nplayer = pyglet.media.Player()\nsource = pyglet.media.load(audio_file)\nplayer.queue(source)\nplayer.play()\n"
  },
  {
    "path": "Chapter 05/5.09/seekbar.py",
    "content": "\"\"\"\nCode illustration: 5.09\n\n@Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\nclass Seekbar(tk.Canvas):\n\n    def __init__(self, parent, **options):\n        tk.Canvas.__init__(self, parent, options)\n        self.parent = parent\n        self.width = options['width']\n        self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill=\"red\")\n        self.seekbar_knob_image = tk.PhotoImage(file=\"../icons/seekbar_knob.gif\")\n        self.seekbar_knob = self.create_image(\n            0, 0, image=self.seekbar_knob_image)\n        self.bind_mouse_button()\n\n    def bind_mouse_button(self):\n        self.bind('<Button-1>', self.on_seekbar_clicked)\n        self.bind('<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked)\n        self.tag_bind(\n            self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked)\n\n    def on_seekbar_clicked(self, event=None):\n        if event.x > 0 and event.x < self.width:\n            self.slide_to_position(event.x)\n\n    def slide_to_position(self, new_position):\n        self.coords(self.red_rectangle, 0, 0, new_position, new_position)\n        self.coords(self.seekbar_knob, new_position, 0)\n        self.event_generate(\"<<SeekbarPositionChanged>>\", x=new_position)\n\n\nclass TestSeekBar():\n\n    def __init__(self):\n        root = tk.Tk()\n        root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n        frame = tk.Frame(root)\n        frame.grid(row=1, pady=10, padx=10)\n        c = Seekbar(\n            frame, background=\"blue\", width=360, height=10)\n        c.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        root.mainloop()\n\n    def seek_new_position(self, event):\n        print(\"Dragged to x:\", event.x)\n\nif __name__ == '__main__':\n    TestSeekBar()\n\n"
  },
  {
    "path": "Chapter 05/5.09/view.py",
    "content": "\"\"\"\nCode illustration: 5.09\n\n    new imports here:\n        import Pmw\n    \n    methods modifed here:\n        create_gui\n        create_button_frame (added balloon tool tip to all buttons)\n        create_bottom_frame (added baloon tool tip to all buttons)\n\n  \n@Tkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport tkinter.filedialog\nimport tkinter.messagebox\nimport tkinter.ttk\nimport os\n\nimport Pmw\nimport model\nimport player\nfrom seekbar import *\nfrom helpers import *\nimport itertools\nAUDIO_PLAYER_NAME = \"Achtung Baby\"\nSEEKBAR_WIDTH = 360\n\n\nclass View:\n\n    loop_choices = [(\"No Loop\", 1), (\"Loop Current\", 2), (\"Loop All\", 3)]\n    current_track_index = 0\n    toggle_play_stop = itertools.cycle([\"play\", \"stop\"])\n    toggle_pause_unpause = itertools.cycle([\"pause\", \"unpause\"])\n    toggle_mute_unmute = itertools.cycle([\"mute\", \"unmute\"])\n\n    def __init__(self, root, model, player):\n        self.root = root\n        self.model = model\n        self.player = player\n        self.create_gui()\n        self.root.protocol('WM_DELETE_WINDOW', self.close_player)\n        self.root.bind(\"<<SeekbarPositionChanged>>\", self.seek_new_position)\n\n    def create_gui(self):\n        self.root.title(AUDIO_PLAYER_NAME)\n        self.balloon = Pmw.Balloon(self.root)\n        self.create_top_display()\n        self.create_button_frame()\n        self.create_list_box()\n        self.create_bottom_frame()\n        self.create_context_menu()\n\n    def create_top_display(self):\n        frame = tk.Frame(self.root)\n        glass_frame_image = tk.PhotoImage(file='../icons/glass_frame.gif')\n        self.canvas = tk.Canvas(frame, width=370, height=90)\n        self.canvas.image = glass_frame_image\n        self.canvas.grid(row=1)\n        self.console = self.canvas.create_image(\n            0, 10, anchor=tk.NW, image=glass_frame_image)\n        self.clock = self.canvas.create_text(125, 68, anchor=tk.W, fill='#CBE4F6',\n                                             text=\"00:00\")\n        self.track_length_text = self.canvas.create_text(167, 68, anchor=tk.W, fill='#CBE4F6',\n                                                         text=\"of 00:00\")\n        self.track_name = self.canvas.create_text(50, 35, anchor=tk.W, fill='#9CEDAC',\n                                                  text='\\\"Currently playing: none \\\"')\n        self.seek_bar = Seekbar(\n            frame, background=\"blue\", width=SEEKBAR_WIDTH, height=10)\n        self.seek_bar.grid(row=2, columnspan=10, sticky='ew', padx=5)\n        frame.grid(row=1, pady=1, padx=0)\n\n    def create_button_frame(self):\n        frame = tk.Frame(self.root)\n        previous_track_icon = tk.PhotoImage(file='../icons/previous_track.gif')\n        previous_track_button = tk.Button(\n            frame, image=previous_track_icon, borderwidth=0, padx=0, command=self.on_previous_track_button_clicked)\n        previous_track_button.image = previous_track_icon\n        previous_track_button.grid(row=3, column=1, sticky='w')\n        self.balloon.bind(previous_track_button, 'Previous Song')\n\n        rewind_icon = tk.PhotoImage(file='../icons/rewind.gif')\n        rewind_button = tk.Button(\n            frame, image=rewind_icon, borderwidth=0, padx=0, command=self.on_rewind_button_clicked)\n        rewind_button.image = rewind_icon\n        rewind_button.grid(row=3, column=2, sticky='w')\n        self.balloon.bind(rewind_button, 'Rewind')\n\n        self.play_icon = tk.PhotoImage(file='../icons/play.gif')\n        self.stop_icon = tk.PhotoImage(file='../icons/stop.gif')\n        self.play_stop_button = tk.Button(\n            frame, image=self.play_icon, borderwidth=0, padx=0, command=self.on_play_stop_button_clicked)\n        self.play_stop_button.image = self.play_icon\n        self.play_stop_button.grid(row=3, column=3)\n        self.balloon.bind(self.play_stop_button, 'Play/ Stop Song')\n\n        pause_icon = tk.PhotoImage(file='../icons/pause.gif')\n        pause_unpause_button = tk.Button(\n            frame, image=pause_icon, borderwidth=0, padx=0, command=self.on_pause_unpause_button_clicked)\n        pause_unpause_button.image = pause_icon\n        pause_unpause_button.grid(row=3, column=4)\n        self.balloon.bind(pause_unpause_button, 'Pause')\n\n        fast_forward_icon = tk.PhotoImage(file='../icons/fast_forward.gif')\n        fast_forward_button = tk.Button(\n            frame, image=fast_forward_icon, borderwidth=0, padx=0, command=self.on_fast_forward_button_clicked)\n        fast_forward_button.image = fast_forward_icon\n        fast_forward_button.grid(row=3, column=5)\n        self.balloon.bind(fast_forward_button, 'Fast Forward')\n\n        next_track_icon = tk.PhotoImage(file='../icons/next_track.gif')\n        next_track_button = tk.Button(\n            frame, image=next_track_icon, borderwidth=0, padx=0, command=self.on_next_track_button_clicked)\n        next_track_button.image = next_track_icon\n        next_track_button.grid(row=3, column=6)\n        self.balloon.bind(next_track_button, 'Next Track')\n\n        self.mute_icon = tk.PhotoImage(file='../icons/mute.gif')\n        self.unmute_icon = tk.PhotoImage(file='../icons/unmute.gif')\n        self.mute_unmute_button = tk.Button(\n            frame, image=self.unmute_icon, text='unmute', borderwidth=0, padx=0, command=self.on_mute_unmute_button_clicked)\n        self.mute_unmute_button.image = self.unmute_icon\n        self.mute_unmute_button.grid(row=3, column=7)\n        self.balloon.bind(self.mute_unmute_button, 'Mute/Unmute')\n\n        self.volume_scale = tkinter.ttk.Scale(\n            frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)\n        self.volume_scale.set(0.6)\n        self.volume_scale.grid(row=3, column=8, padx=5)\n\n        frame.grid(row=3, columnspan=5, sticky='w', pady=4, padx=5)\n\n    def create_list_box(self):\n        frame = tk.Frame(self.root)\n        self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2',\n                                   bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)\n        self.list_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)\n        self.list_box.bind(\n            \"<Double-Button-1>\", self.on_play_list_double_clicked)\n        self.list_box.bind(\"<Button-3>\", self.show_context_menu)\n        scroll_bar = tk.Scrollbar(frame)\n        scroll_bar.pack(side=tk.RIGHT, fill=tk.BOTH)\n        self.list_box.config(yscrollcommand=scroll_bar.set)\n        scroll_bar.config(command=self.list_box.yview)\n        frame.grid(row=4, padx=5, columnspan=10, sticky='ew')\n\n    def create_bottom_frame(self):\n        frame = tk.Frame(self.root)\n\n        add_file_icon = tk.PhotoImage(file='../icons/add_file.gif')\n        add_file_button = tk.Button(frame, image=add_file_icon, borderwidth=0,\n                                    padx=0, text='Add File', command=self.on_add_file_button_clicked)\n        add_file_button.image = add_file_icon\n        add_file_button.grid(row=5, column=1)\n        self.balloon.bind(add_file_button, 'Add New File')\n\n        remove_selected_icon = tk.PhotoImage(\n            file='../icons/delete_selected.gif')\n        remove_selected_button = tk.Button(\n            frame, image=remove_selected_icon, borderwidth=0, padx=0, text='Delete', command=self.on_remove_selected_button_clicked)\n        remove_selected_button.image = remove_selected_icon\n        remove_selected_button.grid(row=5, column=2)\n        self.balloon.bind(remove_selected_button, 'Remove Selected')\n\n        add_directory_icon = tk.PhotoImage(file='../icons/add_directory.gif')\n        add_directory_button = tk.Button(frame, image=add_directory_icon, borderwidth=0,\n                                         padx=0, text='Add Dir', command=self.on_add_directory_button_clicked)\n        add_directory_button.image = add_directory_icon\n        add_directory_button.grid(row=5, column=3)\n        self.balloon.bind(add_directory_button, 'Add Directory')\n\n        empty_play_list_icon = tk.PhotoImage(\n            file='../icons/clear_play_list.gif')\n        empty_play_list_button = tk.Button(frame, image=empty_play_list_icon, borderwidth=0,\n                                           padx=0, text='Clear All', command=self.on_clear_play_list_button_clicked)\n        empty_play_list_button.image = empty_play_list_icon\n        empty_play_list_button.grid(row=5, column=4)\n        self.balloon.bind(empty_play_list_button, 'Empty play list')\n\n        self.loop_value = tk.IntVar()\n        self.loop_value.set(3)\n        for txt, val in self.loop_choices:\n            tk.Radiobutton(frame, text=txt, variable=self.loop_value, value=val).grid(\n                row=5, column=4 + val, pady=3)\n\n        frame.grid(row=5, sticky='w', padx=5)\n\n    def create_context_menu(self):\n        self.context_menu = tk.Menu(self.list_box, tearoff=0)\n        self.context_menu.add_command(\n            label=\"Delete\", command=self.on_remove_selected_context_menu_clicked)\n\n    def show_context_menu(self, event):\n        self.context_menu.tk_popup(event.x_root, event.y_root)\n\n    def on_add_file_button_clicked(self):\n        self.add_audio_file()\n\n    def on_remove_selected_button_clicked(self):\n        self.remove_selected_files()\n\n    def on_add_directory_button_clicked(self):\n        self.add_all_audio_files_from_directory()\n\n    def on_clear_play_list_button_clicked(self):\n        self.clear_play_list()\n\n    def on_remove_selected_context_menu_clicked(self):\n        self.remove_selected_files()\n\n    def on_play_stop_button_clicked(self):\n        action = next(self.toggle_play_stop)\n        if action == 'play':\n            try:\n                self.current_track_index = self.list_box.curselection()[0]\n            except IndexError:\n                self.current_track_index = 0\n            self.start_play()\n        elif action == 'stop':\n            self.stop_play()\n\n    def on_pause_unpause_button_clicked(self):\n        action = next(self.toggle_pause_unpause)\n        if action == 'pause':\n            self.player.pause()\n        elif action == 'unpause':\n            self.player.unpause()\n\n    def on_mute_unmute_button_clicked(self):\n        action = next(self.toggle_mute_unmute)\n        if action == 'mute':\n            self.volume_at_time_of_mute = self.player.volume\n            self.player.mute()\n            self.volume_scale.set(0)\n            self.mute_unmute_button.config(image=self.mute_icon)\n        elif action == 'unmute':\n            self.player.unmute(self.volume_at_time_of_mute)\n            self.volume_scale.set(self.volume_at_time_of_mute)\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def on_previous_track_button_clicked(self):\n        self.play_previous_track()\n\n    def on_rewind_button_clicked(self):\n        self.player.rewind()\n\n    def on_fast_forward_button_clicked(self):\n        self.player.fast_forward()\n\n    def on_next_track_button_clicked(self):\n        self.play_next_track()\n\n    def on_volume_scale_changed(self, value):\n        self.player.volume = self.volume_scale.get()\n        if self.volume_scale.get() == 0.0:\n            self.mute_unmute_button.config(image=self.mute_icon)\n        else:\n            self.mute_unmute_button.config(image=self.unmute_icon)\n\n    def play_previous_track(self):\n        self.current_track_index = max(0, self.current_track_index - 1)\n        self.start_play()\n\n    def play_next_track(self):\n        self.current_track_index = min(\n            self.list_box.size() - 1, self.current_track_index + 1)\n        self.start_play()\n\n    def start_play(self):\n        try:\n            audio_file = self.model.get_file_to_play(self.current_track_index)\n        except IndexError:\n            return\n        self.play_stop_button.config(image=self.stop_icon)\n        self.player.play_media(audio_file)\n        self.current_track_position = 0\n        self.manage_one_time_track_updates_on_play_start()\n        self.manage_periodic_updates_during_play()\n\n    def stop_play(self):\n        self.play_stop_button.config(image=self.play_icon)\n        self.player.stop()\n\n    def on_play_list_double_clicked(self, event=None):\n        self.current_track_index = int(self.list_box.curselection()[0])\n        self.start_play()\n\n    def add_audio_file(self):\n        audio_file = tkinter.filedialog.askopenfilename(filetypes=[(\n            'All supported', '.mp3 .wav'), ('.mp3 files', '.mp3'), ('.wav files', '.wav')])\n        if audio_file:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def remove_selected_files(self):\n        try:\n            selected_indexes = self.list_box.curselection()\n            for index in reversed(selected_indexes):\n                self.list_box.delete(index)\n                self.model.remove_item_from_play_list_at_index(index)\n        except IndexError:\n            pass\n\n    def add_all_audio_files_from_directory(self):\n        directory_path = tkinter.filedialog.askdirectory()\n        if not directory_path:\n            return\n        audio_files_in_directory = self.get_all_audio_file_from_directory(\n            directory_path)\n        for audio_file in audio_files_in_directory:\n            self.model.add_to_play_list(audio_file)\n            file_path, file_name = os.path.split(audio_file)\n            self.list_box.insert(tk.END, file_name)\n\n    def get_all_audio_file_from_directory(self, directory_path):\n        audio_files_in_directory = []\n        for (dirpath, dirnames, filenames) in os.walk(directory_path):\n            for audio_file in filenames:\n                if audio_file.endswith(\".mp3\") or audio_file.endswith(\".wav\"):\n                    audio_files_in_directory.append(dirpath + \"/\" + audio_file)\n        return audio_files_in_directory\n\n    def clear_play_list(self):\n        self.model.clear_play_list()\n        self.list_box.delete(0, tk.END)\n\n    def manage_one_time_track_updates_on_play_start(self):\n        self.update_now_playing_text()\n        self.display_track_duration()\n\n    def update_now_playing_text(self):\n        current_track = self.model.play_list[self.current_track_index]\n        file_path, file_name = os.path.split(current_track)\n        truncated_track_name = truncate_text(file_name, 40)\n        self.canvas.itemconfig(self.track_name, text=truncated_track_name)\n\n    def display_track_duration(self):\n        self.track_length = self.player.track_length\n        print(self.track_length)\n        minutes, seconds = get_time_in_minute_seconds(self.track_length)\n        track_length_string = 'of {0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(\n            self.track_length_text, text=track_length_string)\n\n    def update_clock(self):\n        self.elapsed_play_duration = self.player.elapsed_play_duration\n        minutes, seconds = get_time_in_minute_seconds(\n            self.elapsed_play_duration)\n        current_time_string = '{0:02d}:{1:02d}'.format(minutes, seconds)\n        self.canvas.itemconfig(self.clock, text=current_time_string)\n\n    def update_seek_bar(self):\n        seek_bar_position = SEEKBAR_WIDTH * \\\n            self.player.elapsed_play_duration / self.track_length\n        self.seek_bar.slide_to_position(seek_bar_position)\n\n    def seek_new_position(self, event=None):\n        time = self.player.track_length * event.x / SEEKBAR_WIDTH\n        self.player.seek(time)\n\n    def manage_periodic_updates_during_play(self):\n        self.update_clock()\n        self.update_seek_bar()\n        if not self.player.is_playing():\n            if self.not_to_loop(): return\n        self.root.after(1000, self.manage_periodic_updates_during_play)\n\n    def not_to_loop(self):\n        selected_loop_choice = self.loop_value.get()\n        if selected_loop_choice == 1:\n            return True\n        elif selected_loop_choice == 2:\n            self.start_play()\n            return False\n        elif selected_loop_choice == 3:\n            self.play_next_track()\n            return True\n\n    def close_player(self):\n        self.player.stop()\n        self.root.destroy()\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    root.resizable(width=False, height=False)\n    model = model.Model()\n    player = player.Player()\n    app = View(root, model, player)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 05/readme.txt",
    "content": "====================================================================\nReadme\nTkinter GUI Application Development Blueprints\nChapter 5: Audio Player\n====================================================================\nDescription:\n\n5.01: Program Structure & Broad View Skeleton\n5.02: Deciding the Data Structure & Player class\n5.03: Adding/ Removing items to the Playlist\n5.04: Playing Audio and Adding Audio Controls\n5.05: Creating the Seekbar (Extending Tkinter Widgets)\n5.06: One Time Updates during audio playback\n5.07: Managing Continuous Updates (Animation Logic)\n5.08: Looping Over Tracks\n5.09: Adding ToolTip (Exploring Tkinter extensions)\n\nDirectory 'icons' contains all images used in the program\n\n@author Bhaskar Chaudhary\n"
  },
  {
    "path": "Chapter 06/6.01.py",
    "content": "\"\"\"\nCode illustration: 6.01\n  \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_drawing_canvas()\n        self.bind_menu_accelrator_keys()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)  # here's our framework in action\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.02.py",
    "content": "\"\"\"\nCode illustration: 6.02\n\n    New attributes defined here:\n        start_x, start_y\n        end_x, end_y\n\n    Methods modified here:\n        __init__ (added a call to bind_mouse)\n    \n    New methods defined here:\n        bind_mouse()\n        on_mouse_button_pressed()\n        on_mouse_button_pressed_motion()\n        on_mouse_button_released()\n        on_mouse_unpressed_motion()\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        print(\"start_x, start_y = \", self.start_x, self.start_y)\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        print(\"end_x, end_y = \", self.end_x, self.end_y)\n\n    def on_mouse_unpressed_motion(self, event):\n        pass\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_drawing_canvas()\n        self.bind_menu_accelrator_keys()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.03.py",
    "content": "\"\"\"\nCode illustration: 6.03\n\n    New methods defined here:\n        create_tool_bar_buttons()\n        on_tool_bar_button_clicked(button_index)\n        display_options_in_the_top_bar(function_name)\n        remove_options_from_top_bar()\n\n    Methods modified here:\n        create_gui() - added a call to create_tool_bar_buttons()\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        pass\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.bind_menu_accelrator_keys()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=\"right\", expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.04.py",
    "content": "\"\"\"\nCode illustration: 6.04\n    \n    New module import here:\n        math\n        cmath\n\n    New attributes added here:\n        current_item\n        fill\n        outline\n        width\n        arrow\n        dash\n\n    New methods defined here:\n        execute_selected_method()\n        draw_line()\n        draw_oval()\n        draw_rectangle()\n        draw_arc()\n        draw_triangle()\n        draw_star()\n        \n    Methods modifed here:\n        on_mouse_button_pressed() : added call to execute_selected_method()\n        on_mouse_button_pressed_motion(): added call to execute_selected_method() and added line to delete the last drawn item.\n\n\n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport cmath\nimport tkinter as tk\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3   # nb of edges in circle\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle)) # x coordinate\n            points.append(self.start_y + radius * math.sin(angle)) # y coordinate\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2 # this ratio is called the spoke ratio and can also be configured by user\n        points = list()\n        for edge in range(self.number_of_spokes):\n            # outer circle angle\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            # x coordinate (outer circle)\n            points.append(self.start_x + radius_out * math.cos(angle))\n            # y coordinate (outer circle)\n            points.append(self.start_y + radius_out * math.sin(angle))\n            # inner circle angle\n            angle += math.pi / self.number_of_spokes\n            # x coordinate (inner circle)\n            points.append(self.start_x + radius_in * math.cos(angle))\n            # y coordinate (inner circle)\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        pass\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.bind_menu_accelrator_keys()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.05.py",
    "content": "\"\"\"\nCode illustration: 6.05\n\n    New imports here:\n        from tkinter import colorchooser\n        \n    New attributes added here:\n        background\n        foreground\n\n    New methods added here:\n        create_color_palette()\n        bind_color_palette()\n        set_foreground_color()\n        set_background_color()\n        create_current_coordinate_label()\n        show_current_coordinates()\n        \n    Methods modified here:\n        create_gui() - added call to create_color_palette() & create_current_coordinate_label()\n        on_mouse_unpressed_motion() - added call to show_current_coordinates()\n \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport cmath\nimport tkinter as tk\nfrom tkinter import colorchooser\n\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n    background = 'white'\n    foreground = 'red'\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def create_color_palette(self):\n        self.color_palette = tk.Canvas(self.tool_bar, height=55, width=55)\n        self.color_palette.grid(row=10, column=1, columnspan=2, pady=5, padx=3)\n        self.background_palette = self.color_palette.create_rectangle(\n            15, 15, 48, 48, outline=self.background, fill=self.background)\n        self.foreground_palette = self.color_palette.create_rectangle(\n            1, 1, 33, 33, outline=self.foreground, fill=self.foreground)\n        self.bind_color_palette()\n\n    def bind_color_palette(self):\n        self.color_palette.tag_bind(\n            self.background_palette, \"<Button-1>\", self.set_background_color)\n        self.color_palette.tag_bind(\n            self.foreground_palette, \"<Button-1>\", self.set_foreground_color)\n\n    def set_foreground_color(self, event=None):\n        self.foreground = colorchooser.askcolor(\n            title=\"select foreground color\")[-1]\n        self.color_palette.itemconfig(\n            self.foreground_palette, outline=self.foreground, fill=self.foreground)\n\n    def set_background_color(self, event=None):\n        x = colorchooser.askcolor(title=\"select background color\")\n        print(x)\n        self.background = x[-1]\n        self.color_palette.itemconfig(\n            self.background_palette, outline=self.background, fill=self.background)\n\n    def create_current_coordinate_label(self):\n        self.current_coordinate_label = tk.Label(\n            self.tool_bar, text='x:0\\ny: 0 ')\n        self.current_coordinate_label.grid(\n            row=13, column=1, columnspan=2, pady=5, padx=1, sticky='w')\n\n    def show_current_coordinates(self, event=None):\n        x_coordinate = event.x\n        y_coordinate = event.y\n        coordinate_string = \"x:{0}\\ny:{1}\".format(x_coordinate, y_coordinate)\n        self.current_coordinate_label.config(text=coordinate_string)\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle))\n            points.append(self.start_y + radius * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2\n        points = list()\n        for edge in range(self.number_of_spokes):\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            points.append(self.start_x + radius_out * math.cos(angle))\n            points.append(self.start_y + radius_out * math.sin(angle))\n            angle += math.pi / self.number_of_spokes\n            points.append(self.start_x + radius_in * math.cos(angle))\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        self.show_current_coordinates(event)\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.create_color_palette()\n        self.create_current_coordinate_label()\n        self.bind_menu_accelrator_keys()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.06.py",
    "content": "\"\"\"\nCode illustration: 6.06\n    \n    New imports here:\n        from tkinter import ttk\n       \n\n    New methods added here:\n        create_fill_options_combobox()\n        create_outline_options_combobox()\n        create_width_options_combobox()\n        create_dash_options_combobox()\n        create_arrow_options_combobox()\n        set_fill()\n        set_outline()\n        set_width()\n        set_dash()\n        set_arrow()\n        draw_line_options()\n        draw_oval_options()\n        draw_rectangle_options()\n        draw_arc_options()\n        draw_triangle_options()\n        draw_star_options()\n        try_to_set_fill_after_palette_change()\n        try_to_set_outline_after_palette_change()\n\n        \n    Methods modified here:\n        display_options_in_the_top_bar (added a dynamic function call)\n        set_background_color()\n        set_foreground_color()\n        create_gui()\n \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport cmath\nimport tkinter as tk\nfrom tkinter import colorchooser\nfrom tkinter import ttk\nimport framework\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n    background = 'white'\n    foreground = 'red'\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def set_foreground_color(self, event=None):\n        self.foreground = self.get_color_from_chooser(\n            self.foreground, \"foreground\")\n        self.color_palette.itemconfig(\n            self.foreground_palette, width=0, fill=self.foreground)\n\n    def set_background_color(self, event=None):\n        self.background = self.get_color_from_chooser(\n            self.background, \"background\")\n        self.color_palette.itemconfig(\n            self.background_palette, width=0, fill=self.background)\n\n    def get_color_from_chooser(self, initial_color, color_type=\"a\"):\n        color = colorchooser.askcolor(\n            color=initial_color,\n            title=\"select {} color\".format(color_type)\n        )[-1]\n        if color:\n            return color\n        # dialog has been cancelled\n        else:\n            return initial_color\n\n    def try_to_set_fill_after_palette_change(self):\n        try:\n            self.set_fill()\n        except:\n            pass\n\n    def try_to_set_outline_after_palette_change(self):\n        try:\n            self.set_outline()\n        except:\n            pass\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n        options_function_name = \"{}_options\".format(self.selected_tool_bar_function)\n        func = getattr(self, options_function_name, self.function_not_defined)\n        func()\n\n    def draw_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n        self.create_arrow_options_combobox()\n        self.create_dash_options_combobox()\n\n    def draw_oval_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_rectangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_arc_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_triangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_star_options(self):\n        self.create_number_of_spokes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_fill_options_combobox(self):\n        tk.Label(self.top_bar, text='Fill:').pack(side=\"left\")\n        self.fill_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.fill_combobox.pack(side=\"left\")\n        self.fill_combobox['values'] = ('none', 'fg', 'bg', 'black', 'white')\n        self.fill_combobox.bind('<<ComboboxSelected>>', self.set_fill)\n        self.fill_combobox.set(self.fill)\n\n    def create_number_of_spokes_options_combobox(self):\n        tk.Label(self.top_bar, text='Number of Edges:').pack(side=\"left\")\n        self.number_of_spokes_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.number_of_spokes_combobox.pack(side=\"left\")\n        self.number_of_spokes_combobox[\n            'values'] = tuple(i for i in range(5, 50))\n        self.number_of_spokes_combobox.bind(\n            '<<ComboboxSelected>>', self.set_number_of_spokes)\n        self.number_of_spokes_combobox.set(self.number_of_spokes)\n\n    def create_outline_options_combobox(self):\n        tk.Label(self.top_bar, text='Outline:').pack(side=\"left\")\n        self.outline_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.outline_combobox.pack(side=\"left\")\n        self.outline_combobox['values'] = (\n            'none', 'fg', 'bg', 'black', 'white')\n        self.outline_combobox.bind('<<ComboboxSelected>>', self.set_outline)\n        self.outline_combobox.set(self.outline)\n\n    def create_width_options_combobox(self):\n        tk.Label(self.top_bar, text='Width:').pack(side=\"left\")\n        self.width_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.width_combobox.pack(side=\"left\")\n        self.width_combobox['values'] = (\n            1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)\n        self.width_combobox.bind('<<ComboboxSelected>>', self.set_width)\n        self.width_combobox.set(self.width)\n\n    def create_dash_options_combobox(self):\n        tk.Label(self.top_bar, text='Dash:').pack(side=\"left\")\n        self.dash_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.dash_combobox.pack(side=\"left\")\n        self.dash_combobox['values'] = ('none', 'small', 'medium', 'large')\n        self.dash_combobox.bind('<<ComboboxSelected>>', self.set_dash)\n        self.dash_combobox.current(0)\n\n    def create_arrow_options_combobox(self):\n        tk.Label(self.top_bar, text='Arrow:').pack(side=\"left\")\n        self.arrow_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.arrow_combobox.pack(side=\"left\")\n        self.arrow_combobox['values'] = ('none', 'first', 'last', 'both')\n        self.arrow_combobox.bind('<<ComboboxSelected>>', self.set_arrow)\n        self.arrow_combobox.current(0)\n\n    def set_fill(self, event=None):\n        fill_color = self.fill_combobox.get()\n        if fill_color == 'none':\n            self.fill = ''  # transparent\n        elif fill_color == 'fg':\n            self.fill = self.foreground\n        elif fill_color == 'bg':\n            self.fill = self.background\n        else:\n            self.fill = fill_color\n\n    def set_outline(self, event=None):\n        outline_color = self.outline_combobox.get()\n        if outline_color == 'none':\n            self.outline = ''  # transparent\n        elif outline_color == 'fg':\n            self.outline = self.foreground\n        elif outline_color == 'bg':\n            self.outline = self.background\n        else:\n            self.outline = outline_color\n\n    def set_width(self, event):\n        self.width = float(self.width_combobox.get())\n\n    def set_number_of_spokes(self, event):\n        self.number_of_spokes = int(self.number_of_spokes_combobox.get())\n\n    def set_arrow(self, event):\n        self.arrow = self.arrow_combobox.get()\n\n    def set_dash(self, event):\n        '''Dash takes value from 1 to 255'''\n        dash_size = self.dash_combobox.get()\n        if dash_size == 'none':\n            self.dash = None\n        elif dash_size == 'small':\n            self.dash = 1\n        elif dash_size == 'medium':\n            self.dash = 15\n        elif dash_size == 'large':\n            self.dash = 100\n\n    def create_color_palette(self):\n        self.color_palette = tk.Canvas(self.tool_bar, height=55, width=55)\n        self.color_palette.grid(row=10, column=1, columnspan=2, pady=5, padx=3)\n        self.background_palette = self.color_palette.create_rectangle(\n            15, 15, 48, 48, outline=self.background, fill=self.background)\n        self.foreground_palette = self.color_palette.create_rectangle(\n            1, 1, 33, 33, outline=self.foreground, fill=self.foreground)\n        self.bind_color_palette()\n\n    def bind_color_palette(self):\n        self.color_palette.tag_bind(\n            self.background_palette, \"<Button-1>\", self.set_background_color)\n        self.color_palette.tag_bind(\n            self.foreground_palette, \"<Button-1>\", self.set_foreground_color)\n\n    def create_current_coordinate_label(self):\n        self.current_coordinate_label = tk.Label(\n            self.tool_bar, text='x:0\\ny: 0 ')\n        self.current_coordinate_label.grid(\n            row=13, column=1, columnspan=2, pady=5, padx=1, sticky='w')\n\n    def show_current_coordinates(self, event=None):\n        x_coordinate = event.x\n        y_coordinate = event.y\n        coordinate_string = \"x:{0}\\ny:{1}\".format(x_coordinate, y_coordinate)\n        self.current_coordinate_label.config(text=coordinate_string)\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle))\n            points.append(self.start_y + radius * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2\n        points = list()\n        for edge in range(self.number_of_spokes):\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            points.append(self.start_x + radius_out * math.cos(angle))\n            points.append(self.start_y + radius_out * math.sin(angle))\n            angle += math.pi / self.number_of_spokes\n            points.append(self.start_x + radius_in * math.cos(angle))\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        self.show_current_coordinates(event)\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.create_color_palette()\n        self.create_current_coordinate_label()\n        self.bind_menu_accelrator_keys()\n        self.show_selected_tool_icon_in_top_bar(\"draw_line\")\n        self.draw_line_options()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.07.py",
    "content": "\"\"\"\nCode illustration: 6.07\n    \n    New imports here:\n        from supershapes import *\n        \n    New attributes added here:\n        selected_super_shape = \"shape 1\"\n        \n    New methods added here:\n        draw_irregular_line()\n        draw_irregular_line_update_x_y()\n        draw_irregular_line_options()\n        draw_super_shape()\n        draw_super_shape_options()\n        create_super_shapes_options_combobox()\n        set_selected_super_shape()\n        get_super_shape_points()\n        float_range()\n\n    \n    Methods modified here:\n        on_tool_bar_button_clicked() - added a call to bind_mouse()\n        \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport cmath\nimport tkinter as tk\nfrom tkinter import colorchooser\nfrom tkinter import ttk\nimport framework\nfrom supershapes import *\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n    background = 'white'\n    foreground = 'red'\n    selected_super_shape = \"shape A\"\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def draw_irregular_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width)\n        self.canvas.bind(\"<B1-Motion>\", self.draw_irregular_line_update_x_y)\n\n    def draw_irregular_line_update_x_y(self, event=None):\n        self.start_x, self.start_y = self.end_x, self.end_y\n        self.end_x, self.end_y = event.x, event.y\n        self.draw_irregular_line()\n\n    def draw_irregular_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n        self.bind_mouse()\n\n    def draw_super_shape(self):\n        points = self.get_super_shape_points(\n            *super_shapes[self.selected_super_shape])\n        self.current_item = self.canvas.create_polygon(points, outline=self.outline,\n                                                       fill=self.fill, width=self.width)\n\n    def draw_super_shape_options(self):\n        self.create_super_shapes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_super_shapes_options_combobox(self):\n        tk.Label(self.top_bar, text='Select shape:').pack(side=\"left\")\n        self.super_shape_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=8)\n        self.super_shape_combobox.pack(side=\"left\")\n        self.super_shape_combobox['values'] = sorted(tuple(\n            shape for shape in super_shapes.keys()))\n        self.super_shape_combobox.bind(\n            '<<ComboboxSelected>>', self.set_selected_super_shape)\n        self.super_shape_combobox.set(self.selected_super_shape)\n\n    def set_selected_super_shape(self, event=None):\n        self.selected_super_shape = self.super_shape_combobox.get()\n\n    def get_super_shape_points(self, a, b, m, n1, n2, n3):\n        # https://en.wikipedia.org/wiki/Superformula\n        points = []\n        for i in self.float_range(0, 2 * math.pi, 0.01):\n            raux = (abs(1 / a * abs(math.cos(m * i / 4))) ** n2 + \\\n                abs(1 / b * abs(math.sin(m * i / 4))) ** n3)\n            r = abs(raux) ** (-1 / n1)\n            x = self.end_x + r * math.cos(i)\n            y = self.end_y + r * math.sin(i)\n            points.extend((x, y))\n        return points\n\n    def float_range(self, x, y, step):\n        while x < y:\n            yield x\n            x += step\n\n    def set_foreground_color(self, event=None):\n        self.foreground = self.get_color_from_chooser(\n            self.foreground, \"foreground\")\n        self.color_palette.itemconfig(\n            self.foreground_palette, width=0, fill=self.foreground)\n\n    def set_background_color(self, event=None):\n        self.background = self.get_color_from_chooser(\n            self.background, \"background\")\n        self.color_palette.itemconfig(\n            self.background_palette, width=0, fill=self.background)\n\n    def get_color_from_chooser(self, initial_color, color_type=\"a\"):\n        color = colorchooser.askcolor(\n            color=initial_color,\n            title=\"select {} color\".format(color_type)\n        )[-1]\n        if color:\n            return color\n        # dialog has been cancelled\n        else:\n            return initial_color\n\n\n    def try_to_set_fill_after_palette_change(self):\n        try:\n            self.set_fill()\n        except:\n            pass\n\n    def try_to_set_outline_after_palette_change(self):\n        try:\n            self.set_outline()\n        except:\n            pass\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n        options_function_name = \"{}_options\".format(self.selected_tool_bar_function)\n        func = getattr(self, options_function_name, self.function_not_defined)\n        func()\n\n    def draw_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n        self.create_arrow_options_combobox()\n        self.create_dash_options_combobox()\n\n    def draw_oval_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_rectangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_arc_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_triangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_star_options(self):\n        self.create_number_of_spokes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_fill_options_combobox(self):\n        tk.Label(self.top_bar, text='Fill:').pack(side=\"left\")\n        self.fill_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.fill_combobox.pack(side=\"left\")\n        self.fill_combobox['values'] = ('none', 'fg', 'bg', 'black', 'white')\n        self.fill_combobox.bind('<<ComboboxSelected>>', self.set_fill)\n        self.fill_combobox.set(self.fill)\n\n    def create_number_of_spokes_options_combobox(self):\n        tk.Label(self.top_bar, text='Number of Edges:').pack(side=\"left\")\n        self.number_of_spokes_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.number_of_spokes_combobox.pack(side=\"left\")\n        self.number_of_spokes_combobox[\n            'values'] = tuple(i for i in range(5, 50))\n        self.number_of_spokes_combobox.bind(\n            '<<ComboboxSelected>>', self.set_number_of_spokes)\n        self.number_of_spokes_combobox.set(self.number_of_spokes)\n\n    def create_outline_options_combobox(self):\n        tk.Label(self.top_bar, text='Outline:').pack(side=\"left\")\n        self.outline_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.outline_combobox.pack(side=\"left\")\n        self.outline_combobox['values'] = (\n            'none', 'fg', 'bg', 'black', 'white')\n        self.outline_combobox.bind('<<ComboboxSelected>>', self.set_outline)\n        self.outline_combobox.set(self.outline)\n\n    def create_width_options_combobox(self):\n        tk.Label(self.top_bar, text='Width:').pack(side=\"left\")\n        self.width_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.width_combobox.pack(side=\"left\")\n        self.width_combobox['values'] = (\n            1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)\n        self.width_combobox.bind('<<ComboboxSelected>>', self.set_width)\n        self.width_combobox.set(self.width)\n\n    def create_dash_options_combobox(self):\n        tk.Label(self.top_bar, text='Dash:').pack(side=\"left\")\n        self.dash_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.dash_combobox.pack(side=\"left\")\n        self.dash_combobox['values'] = ('none', 'small', 'medium', 'large')\n        self.dash_combobox.bind('<<ComboboxSelected>>', self.set_dash)\n        self.dash_combobox.current(0)\n\n    def create_arrow_options_combobox(self):\n        tk.Label(self.top_bar, text='Arrow:').pack(side=\"left\")\n        self.arrow_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.arrow_combobox.pack(side=\"left\")\n        self.arrow_combobox['values'] = ('none', 'first', 'last', 'both')\n        self.arrow_combobox.bind('<<ComboboxSelected>>', self.set_arrow)\n        self.arrow_combobox.current(0)\n\n    def set_fill(self, event=None):\n        fill_color = self.fill_combobox.get()\n        if fill_color == 'none':\n            self.fill = ''  # transparent\n        elif fill_color == 'fg':\n            self.fill = self.foreground\n        elif fill_color == 'bg':\n            self.fill = self.background\n        else:\n            self.fill = fill_color\n\n    def set_outline(self, event=None):\n        outline_color = self.outline_combobox.get()\n        if outline_color == 'none':\n            self.outline = ''  # transparent\n        elif outline_color == 'fg':\n            self.outline = self.foreground\n        elif outline_color == 'bg':\n            self.outline = self.background\n        else:\n            self.outline = outline_color\n\n    def set_width(self, event):\n        self.width = float(self.width_combobox.get())\n\n    def set_number_of_spokes(self, event):\n        self.number_of_spokes = int(self.number_of_spokes_combobox.get())\n\n    def set_arrow(self, event):\n        self.arrow = self.arrow_combobox.get()\n\n    def set_dash(self, event):\n        '''Dash takes value from 1 to 255'''\n        dash_size = self.dash_combobox.get()\n        if dash_size == 'none':\n            self.dash = None\n        elif dash_size == 'small':\n            self.dash = 1\n        elif dash_size == 'medium':\n            self.dash = 15\n        elif dash_size == 'large':\n            self.dash = 100\n\n    def create_color_palette(self):\n        self.color_palette = tk.Canvas(self.tool_bar, height=55, width=55)\n        self.color_palette.grid(row=10, column=1, columnspan=2, pady=5, padx=3)\n        self.background_palette = self.color_palette.create_rectangle(\n            15, 15, 48, 48, outline=self.background, fill=self.background)\n        self.foreground_palette = self.color_palette.create_rectangle(\n            1, 1, 33, 33, outline=self.foreground, fill=self.foreground)\n        self.bind_color_palette()\n\n    def bind_color_palette(self):\n        self.color_palette.tag_bind(\n            self.background_palette, \"<Button-1>\", self.set_background_color)\n        self.color_palette.tag_bind(\n            self.foreground_palette, \"<Button-1>\", self.set_foreground_color)\n\n    def create_current_coordinate_label(self):\n        self.current_coordinate_label = tk.Label(\n            self.tool_bar, text='x:0\\ny: 0 ')\n        self.current_coordinate_label.grid(\n            row=13, column=1, columnspan=2, pady=5, padx=1, sticky='w')\n\n    def show_current_coordinates(self, event=None):\n        x_coordinate = event.x\n        y_coordinate = event.y\n        coordinate_string = \"x:{0}\\ny:{1}\".format(x_coordinate, y_coordinate)\n        self.current_coordinate_label.config(text=coordinate_string)\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle))\n            points.append(self.start_y + radius * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2\n        points = list()\n        for edge in range(self.number_of_spokes):\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            points.append(self.start_x + radius_out * math.cos(angle))\n            points.append(self.start_y + radius_out * math.sin(angle))\n            angle += math.pi / self.number_of_spokes\n            points.append(self.start_x + radius_in * math.cos(angle))\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        self.show_current_coordinates(event)\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.create_color_palette()\n        self.create_current_coordinate_label()\n        self.bind_menu_accelrator_keys()\n        self.show_selected_tool_icon_in_top_bar(\"draw_line\")\n        self.draw_line_options()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.08.py",
    "content": "\"\"\"\nCode illustration: 6.08\n    \n    New methods added here:\n        draw_text()\n        draw_text_options()\n        on_create_text_button_clicked()\n        delete_item()\n        fill_item()\n        fill_item_options()\n        duplicate_item()\n        get_all_configurations_for_item()\n        canvas_function_wrapper()\n        move_to_top()\n        drag_item()\n        drag_item_update_x_y(self, event):\n        enlarge_item_size()\n        reduce_item_size()\n    \n        \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport cmath\nimport tkinter as tk\nfrom tkinter import colorchooser\nfrom tkinter import ttk\nimport framework\nfrom supershapes import *\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n    background = 'white'\n    foreground = 'red'\n    selected_super_shape = \"shape A\"\n\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def draw_text(self):\n        pass\n\n    def draw_text_options(self):\n        tk.Label(self.top_bar, text='Text:').pack(side=\"left\")\n        self.text_entry_widget = tk.Entry(self.top_bar, width=20)\n        self.text_entry_widget.pack(side=\"left\")\n        tk.Label(self.top_bar, text='Font size:').pack(side=\"left\")\n        self.font_size_spinbox = tk.Spinbox(\n            self.top_bar, from_=14, to=100, width=3)\n        self.font_size_spinbox.pack(side=\"left\")\n        self.create_fill_options_combobox()\n        self.create_text_button = tk.Button(\n            self.top_bar, text=\"Go\", command=self.on_create_text_button_clicked)\n        self.create_text_button.pack(side=\"left\", padx=5)\n\n    def on_create_text_button_clicked(self):\n        entered_text = self.text_entry_widget.get()\n        center_x = self.canvas.winfo_width() / 2\n        center_y = self.canvas.winfo_height() / 2\n        font_size = self.font_size_spinbox.get()\n        self.canvas.create_text(\n            center_x, center_y, font=(\"\", font_size), text=entered_text, fill=self.fill)\n\n    def delete_item(self):\n        self.current_item = None\n        self.canvas.delete(\"current\")\n\n    def fill_item(self):\n        try:\n            self.canvas.itemconfig(\n                \"current\", fill=self.fill, outline=self.outline)\n        except TclError:\n            self.canvas.itemconfig(\"current\", fill=self.fill)\n\n    def fill_item_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n\n    def duplicate_item(self):\n        try:\n            function_name = \"create_\" + self.canvas.type(\"current\")\n        except TypeError:\n            return\n        coordinates = tuple(\n            map(lambda i: i + 10, self.canvas.coords(\"current\")))\n        configurations = self.get_all_configurations_for_item()\n        self.canvas_function_wrapper(\n            function_name, coordinates, configurations)\n\n    def get_all_configurations_for_item(self):\n        configuration_dict = {}\n        for key, value in self.canvas.itemconfig(\"current\").items():\n            if value[-1] and value[-1] not in [\"0\", \"0.0\", \"0,0\", \"current\"]:\n                configuration_dict[key] = value[-1]\n        return configuration_dict\n\n    def canvas_function_wrapper(self, function_name, *arg, **kwargs):\n        func = getattr(self.canvas, function_name)\n        func(*arg, **kwargs)\n\n    def move_to_top(self):\n        self.current_item = None\n        self.canvas.tag_raise(\"current\")\n\n    def drag_item(self):\n        self.canvas.move(\n            \"current\", self.end_x - self.start_x, self.end_y - self.start_y)\n        self.canvas.bind(\"<B1-Motion>\", self.drag_item_update_x_y)\n\n    def drag_item_update_x_y(self, event):\n        self.start_x, self.start_y = self.end_x, self.end_y\n        self.end_x, self.end_y = event.x, event.y\n        self.drag_item()\n\n    def enlarge_item_size(self):\n        self.current_item = None\n        if self.canvas.find_withtag(\"current\"):\n            self.canvas.scale(\"current\", self.end_x, self.end_y, 1.2, 1.2)\n            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def reduce_item_size(self):\n        self.current_item = None\n        if self.canvas.find_withtag(\"current\"):\n            self.canvas.scale(\"current\", self.end_x, self.end_y, .8, .8)\n            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def draw_irregular_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width)\n        self.canvas.bind(\"<B1-Motion>\", self.draw_irregular_line_update_x_y)\n\n    def draw_irregular_line_update_x_y(self, event=None):\n        self.start_x, self.start_y = self.end_x, self.end_y\n        self.end_x, self.end_y = event.x, event.y\n        self.draw_irregular_line()\n\n    def draw_irregular_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n        self.bind_mouse()\n\n    def draw_super_shape(self):\n        points = self.get_super_shape_points(\n            *super_shapes[self.selected_super_shape])\n        self.current_item = self.canvas.create_polygon(points, outline=self.outline,\n                                                       fill=self.fill, width=self.width)\n\n    def draw_super_shape_options(self):\n        self.create_super_shapes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_super_shapes_options_combobox(self):\n        tk.Label(self.top_bar, text='Select shape:').pack(side=\"left\")\n        self.super_shape_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=8)\n        self.super_shape_combobox.pack(side=\"left\")\n        self.super_shape_combobox['values'] = tuple(\n            shape for shape in super_shapes.keys())\n        self.super_shape_combobox.bind(\n            '<<ComboboxSelected>>', self.set_selected_super_shape)\n        self.super_shape_combobox.set(self.selected_super_shape)\n\n    def set_selected_super_shape(self, event=None):\n        self.selected_super_shape = self.super_shape_combobox.get()\n\n    def get_super_shape_points(self, a, b, m, n1, n2, n3):\n        # https://en.wikipedia.org/wiki/Superformula\n        points = []\n        for i in self.float_range(0, 2 * math.pi, 0.01):\n            raux = (abs(1 / a * abs(math.cos(m * i / 4))) ** n2 +\n                    abs(1 / b * abs(math.sin(m * i / 4))) ** n3)\n            r = abs(raux) ** (-1 / n1)\n            x = self.end_x + r * math.cos(i)\n            y = self.end_y + r * math.sin(i)\n            points.extend((x, y))\n        return points\n\n    def float_range(self, x, y, step):\n        while x < y:\n            yield x\n            x += step\n\n    def set_foreground_color(self, event=None):\n        self.foreground = self.get_color_from_chooser(\n            self.foreground, \"foreground\")\n        self.color_palette.itemconfig(\n            self.foreground_palette, width=0, fill=self.foreground)\n\n    def set_background_color(self, event=None):\n        self.background = self.get_color_from_chooser(\n            self.background, \"background\")\n        self.color_palette.itemconfig(\n            self.background_palette, width=0, fill=self.background)\n\n    def get_color_from_chooser(self, initial_color, color_type=\"a\"):\n        color = colorchooser.askcolor(\n            color=initial_color,\n            title=\"select {} color\".format(color_type)\n        )[-1]\n        if color:\n            return color\n        # dialog has been cancelled\n        else:\n            return initial_color\n\n    def try_to_set_fill_after_palette_change(self):\n        try:\n            self.set_fill()\n        except:\n            pass\n\n    def try_to_set_outline_after_palette_change(self):\n        try:\n            self.set_outline()\n        except:\n            pass\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n        options_function_name = \"{}_options\".format(\n            self.selected_tool_bar_function)\n        func = getattr(self, options_function_name, self.function_not_defined)\n        func()\n\n    def draw_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n        self.create_arrow_options_combobox()\n        self.create_dash_options_combobox()\n\n    def draw_oval_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_rectangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_arc_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_triangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_star_options(self):\n        self.create_number_of_spokes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_fill_options_combobox(self):\n        tk.Label(self.top_bar, text='Fill:').pack(side=\"left\")\n        self.fill_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.fill_combobox.pack(side=\"left\")\n        self.fill_combobox['values'] = ('none', 'fg', 'bg', 'black', 'white')\n        self.fill_combobox.bind('<<ComboboxSelected>>', self.set_fill)\n        self.fill_combobox.set(self.fill)\n\n    def create_number_of_spokes_options_combobox(self):\n        tk.Label(self.top_bar, text='Number of Edges:').pack(side=\"left\")\n        self.number_of_spokes_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.number_of_spokes_combobox.pack(side=\"left\")\n        self.number_of_spokes_combobox[\n            'values'] = tuple(i for i in range(5, 50))\n        self.number_of_spokes_combobox.bind(\n            '<<ComboboxSelected>>', self.set_number_of_spokes)\n        self.number_of_spokes_combobox.set(self.number_of_spokes)\n\n    def create_outline_options_combobox(self):\n        tk.Label(self.top_bar, text='Outline:').pack(side=\"left\")\n        self.outline_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.outline_combobox.pack(side=\"left\")\n        self.outline_combobox['values'] = (\n            'none', 'fg', 'bg', 'black', 'white')\n        self.outline_combobox.bind('<<ComboboxSelected>>', self.set_outline)\n        self.outline_combobox.set(self.outline)\n\n    def create_width_options_combobox(self):\n        tk.Label(self.top_bar, text='Width:').pack(side=\"left\")\n        self.width_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.width_combobox.pack(side=\"left\")\n        self.width_combobox['values'] = (\n            1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)\n        self.width_combobox.bind('<<ComboboxSelected>>', self.set_width)\n        self.width_combobox.set(self.width)\n\n    def create_dash_options_combobox(self):\n        tk.Label(self.top_bar, text='Dash:').pack(side=\"left\")\n        self.dash_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.dash_combobox.pack(side=\"left\")\n        self.dash_combobox['values'] = ('none', 'small', 'medium', 'large')\n        self.dash_combobox.bind('<<ComboboxSelected>>', self.set_dash)\n        self.dash_combobox.current(0)\n\n    def create_arrow_options_combobox(self):\n        tk.Label(self.top_bar, text='Arrow:').pack(side=\"left\")\n        self.arrow_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.arrow_combobox.pack(side=\"left\")\n        self.arrow_combobox['values'] = ('none', 'first', 'last', 'both')\n        self.arrow_combobox.bind('<<ComboboxSelected>>', self.set_arrow)\n        self.arrow_combobox.current(0)\n\n    def set_fill(self, event=None):\n        fill_color = self.fill_combobox.get()\n        if fill_color == 'none':\n            self.fill = ''  # transparent\n        elif fill_color == 'fg':\n            self.fill = self.foreground\n        elif fill_color == 'bg':\n            self.fill = self.background\n        else:\n            self.fill = fill_color\n\n    def set_outline(self, event=None):\n        outline_color = self.outline_combobox.get()\n        if outline_color == 'none':\n            self.outline = ''  # transparent\n        elif outline_color == 'fg':\n            self.outline = self.foreground\n        elif outline_color == 'bg':\n            self.outline = self.background\n        else:\n            self.outline = outline_color\n\n    def set_width(self, event):\n        self.width = float(self.width_combobox.get())\n\n    def set_number_of_spokes(self, event):\n        self.number_of_spokes = int(self.number_of_spokes_combobox.get())\n\n    def set_arrow(self, event):\n        self.arrow = self.arrow_combobox.get()\n\n    def set_dash(self, event):\n        '''Dash takes value from 1 to 255'''\n        dash_size = self.dash_combobox.get()\n        if dash_size == 'none':\n            self.dash = None\n        elif dash_size == 'small':\n            self.dash = 1\n        elif dash_size == 'medium':\n            self.dash = 15\n        elif dash_size == 'large':\n            self.dash = 100\n\n    def create_color_palette(self):\n        self.color_palette = tk.Canvas(self.tool_bar, height=55, width=55)\n        self.color_palette.grid(row=10, column=1, columnspan=2, pady=5, padx=3)\n        self.background_palette = self.color_palette.create_rectangle(\n            15, 15, 48, 48, outline=self.background, fill=self.background)\n        self.foreground_palette = self.color_palette.create_rectangle(\n            1, 1, 33, 33, outline=self.foreground, fill=self.foreground)\n        self.bind_color_palette()\n\n    def bind_color_palette(self):\n        self.color_palette.tag_bind(\n            self.background_palette, \"<Button-1>\", self.set_background_color)\n        self.color_palette.tag_bind(\n            self.foreground_palette, \"<Button-1>\", self.set_foreground_color)\n\n    def create_current_coordinate_label(self):\n        self.current_coordinate_label = tk.Label(\n            self.tool_bar, text='x:0\\ny: 0 ')\n        self.current_coordinate_label.grid(\n            row=13, column=1, columnspan=2, pady=5, padx=1, sticky='w')\n\n    def show_current_coordinates(self, event=None):\n        x_coordinate = event.x\n        y_coordinate = event.y\n        coordinate_string = \"x:{0}\\ny:{1}\".format(x_coordinate, y_coordinate)\n        self.current_coordinate_label.config(text=coordinate_string)\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle))\n            points.append(self.start_y + radius * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2\n        points = list()\n        for edge in range(self.number_of_spokes):\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            points.append(self.start_x + radius_out * math.cos(angle))\n            points.append(self.start_y + radius_out * math.sin(angle))\n            angle += math.pi / self.number_of_spokes\n            points.append(self.start_x + radius_in * math.cos(angle))\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        self.show_current_coordinates(event)\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.create_color_palette()\n        self.create_current_coordinate_label()\n        self.bind_menu_accelrator_keys()\n        self.show_selected_tool_icon_in_top_bar(\"draw_line\")\n        self.draw_line_options()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n    def on_new_file_menu_clicked(self, event=None):\n        pass\n\n    def on_save_menu_clicked(self, event=None):\n        pass\n\n    def on_save_as_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        pass\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        pass\n\n    def on_close_menu_clicked(self):\n        pass\n\n    def on_undo_menu_clicked(self, event=None):\n        pass\n\n    def on_about_menu_clicked(self, event=None):\n        pass\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/6.09.py",
    "content": "\"\"\"\nCode illustration: 6.09\n    \n    Modules imported here:\n        from tkinter import messagebox\n        from tkinter import filedialog\n    \n    Attributes added here:\n        file_name = \"untitled\"\n    \n    Methods modified here:\n        on_new_file_menu_clicked()\n        on_save_menu_clicked()\n        on_save_as_menu_clicked()\n        on_close_menu_clicked()\n        on_undo_menu_clicked()\n        on_canvas_zoom_in_menu_clicked()\n        on_canvas_zoom_out_menu_clicked()\n        on_about_menu_clicked()\n\n    Methods added here\n        start_new_project()\n        actual_save()\n        close_window()\n        undo()\n        canvas_zoom_in()\n        canvas_zoom_out()\n        \n@ Tkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport tkinter as tk\nfrom tkinter import colorchooser\nfrom tkinter import ttk\nfrom tkinter import messagebox\nfrom tkinter import filedialog\nimport cmath\nimport framework\nfrom supershapes import *\n\n\nclass PaintApplication(framework.Framework):\n\n    start_x, start_y = 0, 0\n    end_x, end_y = 0, 0\n    current_item = None\n    fill = \"red\"\n    outline = \"red\"\n    width = 2.0\n    number_of_spokes = 5\n    arrow = None\n    dash = None\n    background = 'white'\n    foreground = 'red'\n    selected_super_shape = \"shape A\"\n    file_name = \"untitled\"\n    tool_bar_functions = (\n        \"draw_line\", \"draw_oval\", \"draw_rectangle\", \"draw_arc\",\n        \"draw_triangle\", \"draw_star\", \"draw_irregular_line\", \"draw_super_shape\", \"draw_text\", \"delete_item\", \"fill_item\", \"duplicate_item\", \"move_to_top\", \"drag_item\", \"enlarge_item_size\", \"reduce_item_size\"\n    )\n    selected_tool_bar_function = tool_bar_functions[0]\n\n    def on_new_file_menu_clicked(self, event=None):\n        self.start_new_project()\n\n    def start_new_project(self):\n        self.canvas.delete(ALL)\n        self.canvas.config(bg=\"#ffffff\")\n        self.root.title('untitled')\n\n    def on_save_menu_clicked(self, event=None):\n        if self.file_name == 'untitled':\n            self.on_save_as_menu_clicked()\n        else:\n            self.actual_save()\n\n    def on_save_as_menu_clicked(self):\n        file_name = filedialog.asksaveasfilename(\n            master=self.root, filetypes=[('All Files', ('*.ps', '*.ps'))], title=\"Save...\")\n        if not file_name:\n            return\n        self.file_name = file_name\n        self.actual_save()\n\n    def actual_save(self):\n        self.canvas.postscript(file=self.file_name, colormode='color')\n        self.root.title(self.file_name)\n\n    def on_close_menu_clicked(self):\n        self.close_window()\n\n    def close_window(self):\n        if messagebox.askokcancel(\"Quit\", \"Do you really want to quit?\"):\n            self.root.destroy()\n\n    def on_undo_menu_clicked(self, event=None):\n        self.undo()\n\n    def undo(self):\n        items_stack = list(self.canvas.find(\"all\"))\n        try:\n            last_item_id = items_stack.pop()\n        except IndexError:\n            return\n        self.canvas.delete(last_item_id)\n\n    def on_canvas_zoom_in_menu_clicked(self):\n        self.canvas_zoom_in()\n\n    def on_canvas_zoom_out_menu_clicked(self):\n        self.canvas_zoom_out()\n\n    def canvas_zoom_in(self):\n        self.canvas.scale(\"all\", 0, 0, 1.2, 1.2)\n        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def canvas_zoom_out(self):\n        self.canvas.scale(\"all\", 0, 0, .8, .8)\n        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def on_about_menu_clicked(self, event=None):\n        messagebox.showinfo(\n            \"About\", \"Tkinter GUI Application\\n Development Blueprints\")\n\n    def draw_text_options(self):\n        tk.Label(self.top_bar, text='Text:').pack(side=\"left\")\n        self.text_entry_widget = tk.Entry(self.top_bar, width=20)\n        self.text_entry_widget.pack(side=\"left\")\n        tk.Label(self.top_bar, text='Font size:').pack(side=\"left\")\n        self.font_size_spinbox = tk.Spinbox(\n            self.top_bar, from_=14, to=100, width=3)\n        self.font_size_spinbox.pack(side=\"left\")\n        self.create_fill_options_combobox()\n        self.create_text_button = tk.Button(\n            self.top_bar, text=\"Go\", command=self.on_create_text_button_clicked)\n        self.create_text_button.pack(side=\"left\", padx=5)\n\n    def on_create_text_button_clicked(self):\n        entered_text = self.text_entry_widget.get()\n        center_x = self.canvas.winfo_width() / 2\n        center_y = self.canvas.winfo_height() / 2\n        font_size = self.font_size_spinbox.get()\n        self.canvas.create_text(\n            center_x, center_y, font=(\"\", font_size), text=entered_text, fill=self.fill)\n\n    def delete_item(self):\n        self.current_item = None\n        self.canvas.delete(\"current\")\n\n    def fill_item(self):\n        try:\n            self.canvas.itemconfig(\"current\", fill=self.fill, outline=self.outline)\n        except TclError:\n            self.canvas.itemconfig(\"current\", fill=self.fill)\n\n    def fill_item_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n\n    def duplicate_item(self):\n        try:\n            function_name = \"create_\" + self.canvas.type(\"current\")\n        except TypeError:\n            return\n        coordinates = tuple(map(lambda i: i+10, self.canvas.coords(\"current\")))\n        configurations = self.get_all_configurations_for_item()\n        self.canvas_function_wrapper(\n            function_name, coordinates, configurations)\n\n    def get_all_configurations_for_item(self):\n        configuration_dict = {}\n        for key, value in self.canvas.itemconfig(\"current\").items():\n            if value[-1] and value[-1] not in [\"0\", \"0.0\", \"0,0\", \"current\"]:\n                configuration_dict[key] = value[-1]\n        return configuration_dict\n\n    def canvas_function_wrapper(self, function_name, *arg, **kwargs):\n        func = getattr(self.canvas, function_name)\n        func(*arg, **kwargs)\n\n    def move_to_top(self):\n        self.current_item = None\n        self.canvas.tag_raise(\"current\")\n\n    def drag_item(self):\n        self.canvas.move(\n            \"current\", self.end_x - self.start_x, self.end_y - self.start_y)\n        self.canvas.bind(\"<B1-Motion>\", self.drag_item_update_x_y)\n\n    def drag_item_update_x_y(self, event):\n        self.start_x, self.start_y = self.end_x, self.end_y\n        self.end_x, self.end_y = event.x, event.y\n        self.drag_item()\n\n    def enlarge_item_size(self):\n        self.current_item = None\n        if self.canvas.find_withtag(\"current\"):\n            self.canvas.scale(\"current\", self.end_x, self.end_y, 1.2, 1.2)\n            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def reduce_item_size(self):\n        self.current_item = None\n        if self.canvas.find_withtag(\"current\"):\n            self.canvas.scale(\"current\", self.end_x, self.end_y, .8, .8)\n            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))\n\n    def draw_irregular_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width)\n        self.canvas.bind(\"<B1-Motion>\", self.draw_irregular_line_update_x_y)\n\n    def draw_irregular_line_update_x_y(self, event=None):\n        self.start_x, self.start_y = self.end_x, self.end_y\n        self.end_x, self.end_y = event.x, event.y\n        self.draw_irregular_line()\n\n    def draw_irregular_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n\n    def on_tool_bar_button_clicked(self, button_index):\n        self.selected_tool_bar_function = self.tool_bar_functions[button_index]\n        self.remove_options_from_top_bar()\n        self.display_options_in_the_top_bar()\n        self.bind_mouse()\n\n    def draw_super_shape(self):\n        points = self.get_super_shape_points(\n            *super_shapes[self.selected_super_shape])\n        self.current_item = self.canvas.create_polygon(points, outline=self.outline,\n                                                       fill=self.fill, width=self.width)\n\n    def draw_super_shape_options(self):\n        self.create_super_shapes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_super_shapes_options_combobox(self):\n        tk.Label(self.top_bar, text='Select shape:').pack(side=\"left\")\n        self.super_shape_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=8)\n        self.super_shape_combobox.pack(side=\"left\")\n        self.super_shape_combobox['values'] = tuple(\n            shape for shape in super_shapes.keys())\n        self.super_shape_combobox.bind(\n            '<<ComboboxSelected>>', self.set_selected_super_shape)\n        self.super_shape_combobox.set(self.selected_super_shape)\n\n    def set_selected_super_shape(self, event=None):\n        self.selected_super_shape = self.super_shape_combobox.get()\n\n    def get_super_shape_points(self, a, b, m, n1, n2, n3):\n        # https://en.wikipedia.org/wiki/Superformula\n        points = []\n        for i in self.float_range(0, 2 * math.pi, 0.01):\n            raux = (abs(1 / a * abs(math.cos(m * i / 4))) ** n2 + \\\n                abs(1 / b * abs(math.sin(m * i / 4))) ** n3)\n            r = abs(raux) ** (-1 / n1)\n            x = self.end_x + r * math.cos(i)\n            y = self.end_y + r * math.sin(i)\n            points.extend((x, y))\n        return points\n\n    def float_range(self, x, y, step):\n        while x < y:\n            yield x\n            x += step\n\n    def set_foreground_color(self, event=None):\n        self.foreground = self.get_color_from_chooser(\n            self.foreground, \"foreground\")\n        self.color_palette.itemconfig(\n            self.foreground_palette, width=0, fill=self.foreground)\n\n    def set_background_color(self, event=None):\n        self.background = self.get_color_from_chooser(\n            self.background, \"background\")\n        self.color_palette.itemconfig(\n            self.background_palette, width=0, fill=self.background)\n\n    def get_color_from_chooser(self, initial_color, color_type=\"a\"):\n        color = colorchooser.askcolor(\n            color=initial_color,\n            title=\"select {} color\".format(color_type)\n        )[-1]\n        if color:\n            return color\n        # dialog has been cancelled\n        else:\n            return initial_color\n\n    def try_to_set_fill_after_palette_change(self):\n        try:\n            self.set_fill()\n        except:\n            pass\n\n    def try_to_set_outline_after_palette_change(self):\n        try:\n            self.set_outline()\n        except:\n            pass\n\n    def display_options_in_the_top_bar(self):\n        self.show_selected_tool_icon_in_top_bar(\n            self.selected_tool_bar_function)\n        options_function_name = \"{}_options\".format(self.selected_tool_bar_function)\n        func = getattr(self, options_function_name, self.function_not_defined)\n        func()\n\n    def draw_line_options(self):\n        self.create_fill_options_combobox()\n        self.create_width_options_combobox()\n        self.create_arrow_options_combobox()\n        self.create_dash_options_combobox()\n\n    def draw_oval_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_rectangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_arc_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_triangle_options(self):\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def draw_star_options(self):\n        self.create_number_of_spokes_options_combobox()\n        self.create_fill_options_combobox()\n        self.create_outline_options_combobox()\n        self.create_width_options_combobox()\n\n    def create_fill_options_combobox(self):\n        tk.Label(self.top_bar, text='Fill:').pack(side=\"left\")\n        self.fill_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.fill_combobox.pack(side=\"left\")\n        self.fill_combobox['values'] = ('none', 'fg', 'bg', 'black', 'white')\n        self.fill_combobox.bind('<<ComboboxSelected>>', self.set_fill)\n        self.fill_combobox.set(self.fill)\n\n    def create_outline_options_combobox(self):\n        tk.Label(self.top_bar, text='Outline:').pack(side=\"left\")\n        self.outline_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.outline_combobox.pack(side=\"left\")\n        self.outline_combobox['values'] = (\n            'none', 'fg', 'bg', 'black', 'white')\n        self.outline_combobox.bind('<<ComboboxSelected>>', self.set_outline)\n        self.outline_combobox.set(self.outline)\n\n    def create_number_of_spokes_options_combobox(self):\n        tk.Label(self.top_bar, text='Number of Edges:').pack(side=\"left\")\n        self.number_of_spokes_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.number_of_spokes_combobox.pack(side=\"left\")\n        self.number_of_spokes_combobox[\n            'values'] = tuple(i for i in range(5, 50))\n        self.number_of_spokes_combobox.bind(\n            '<<ComboboxSelected>>', self.set_number_of_spokes)\n        self.number_of_spokes_combobox.set(self.number_of_spokes)\n\n    def create_width_options_combobox(self):\n        tk.Label(self.top_bar, text='Width:').pack(side=\"left\")\n        self.width_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=3)\n        self.width_combobox.pack(side=\"left\")\n        self.width_combobox['values'] = (\n            1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)\n        self.width_combobox.bind('<<ComboboxSelected>>', self.set_width)\n        self.width_combobox.set(self.width)\n\n    def create_dash_options_combobox(self):\n        tk.Label(self.top_bar, text='Dash:').pack(side=\"left\")\n        self.dash_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.dash_combobox.pack(side=\"left\")\n        self.dash_combobox['values'] = ('none', 'small', 'medium', 'large')\n        self.dash_combobox.bind('<<ComboboxSelected>>', self.set_dash)\n        self.dash_combobox.current(0)\n\n    def create_arrow_options_combobox(self):\n        tk.Label(self.top_bar, text='Arrow:').pack(side=\"left\")\n        self.arrow_combobox = ttk.Combobox(\n            self.top_bar, state='readonly', width=5)\n        self.arrow_combobox.pack(side=\"left\")\n        self.arrow_combobox['values'] = ('none', 'first', 'last', 'both')\n        self.arrow_combobox.bind('<<ComboboxSelected>>', self.set_arrow)\n        self.arrow_combobox.current(0)\n\n    def set_fill(self, event=None):\n        fill_color = self.fill_combobox.get()\n        if fill_color == 'none':\n            self.fill = ''  # transparent\n        elif fill_color == 'fg':\n            self.fill = self.foreground\n        elif fill_color == 'bg':\n            self.fill = self.background\n        else:\n            self.fill = fill_color\n\n    def set_outline(self, event=None):\n        outline_color = self.outline_combobox.get()\n        if outline_color == 'none':\n            self.outline = ''  # transparent\n        elif outline_color == 'fg':\n            self.outline = self.foreground\n        elif outline_color == 'bg':\n            self.outline = self.background\n        else:\n            self.outline = outline_color\n\n    def set_width(self, event):\n        self.width = float(self.width_combobox.get())\n\n    def set_number_of_spokes(self, event):\n        self.number_of_spokes = int(self.number_of_spokes_combobox.get())\n\n    def set_arrow(self, event):\n        self.arrow = self.arrow_combobox.get()\n\n    def set_dash(self, event):\n        '''Dash takes value from 1 to 255'''\n        dash_size = self.dash_combobox.get()\n        if dash_size == 'none':\n            self.dash = None\n        elif dash_size == 'small':\n            self.dash = 1\n        elif dash_size == 'medium':\n            self.dash = 15\n        elif dash_size == 'large':\n            self.dash = 100\n\n    def create_color_palette(self):\n        self.color_palette = tk.Canvas(self.tool_bar, height=55, width=55)\n        self.color_palette.grid(row=10, column=1, columnspan=2, pady=5, padx=3)\n        self.background_palette = self.color_palette.create_rectangle(\n            15, 15, 48, 48, outline=self.background, fill=self.background)\n        self.foreground_palette = self.color_palette.create_rectangle(\n            1, 1, 33, 33, outline=self.foreground, fill=self.foreground)\n        self.bind_color_palette()\n\n    def bind_color_palette(self):\n        self.color_palette.tag_bind(\n            self.background_palette, \"<Button-1>\", self.set_background_color)\n        self.color_palette.tag_bind(\n            self.foreground_palette, \"<Button-1>\", self.set_foreground_color)\n\n    def create_current_coordinate_label(self):\n        self.current_coordinate_label = tk.Label(\n            self.tool_bar, text='x:0\\ny: 0 ')\n        self.current_coordinate_label.grid(\n            row=13, column=1, columnspan=2, pady=5, padx=1, sticky='w')\n\n    def show_current_coordinates(self, event=None):\n        x_coordinate = event.x\n        y_coordinate = event.y\n        coordinate_string = \"x:{0}\\ny:{1}\".format(x_coordinate, y_coordinate)\n        self.current_coordinate_label.config(text=coordinate_string)\n\n    def function_not_defined(self):\n        pass\n\n    def execute_selected_method(self):\n        self.current_item = None\n        func = getattr(\n            self, self.selected_tool_bar_function, self.function_not_defined)\n        func()\n\n    def draw_line(self):\n        self.current_item = self.canvas.create_line(\n            self.start_x, self.start_y, self.end_x, self.end_y, fill=self.fill, width=self.width, arrow=self.arrow, dash=self.dash)\n\n    def draw_oval(self):\n        self.current_item = self.canvas.create_oval(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_rectangle(self):\n        self.current_item = self.canvas.create_rectangle(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_arc(self):\n        self.current_item = self.canvas.create_arc(\n            self.start_x, self.start_y, self.end_x, self.end_y, outline=self.outline, fill=self.fill, width=self.width)\n\n    def draw_triangle(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius, angle0 = cmath.polar(z)\n        edges = 3\n        points = list()\n        for edge in range(edges):\n            angle = angle0 + edge * (2 * math.pi) / edges\n            points.append(self.start_x + radius * math.cos(angle))\n            points.append(self.start_y + radius * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def draw_star(self):\n        dx = self.end_x - self.start_x\n        dy = self.end_y - self.start_y\n        z = complex(dx, dy)\n        radius_out, angle0 = cmath.polar(z)\n        radius_in = radius_out / 2\n        points = list()\n        for edge in range(self.number_of_spokes):\n            angle = angle0 + edge * (2 * math.pi) / self.number_of_spokes\n            points.append(self.start_x + radius_out * math.cos(angle))\n            points.append(self.start_y + radius_out * math.sin(angle))\n            angle += math.pi / self.number_of_spokes\n            points.append(self.start_x + radius_in * math.cos(angle))\n            points.append(self.start_y + radius_in * math.sin(angle))\n        self.current_item = self.canvas.create_polygon(\n            points, outline=self.outline, fill=self.fill,\n            width=self.width)\n\n    def create_tool_bar_buttons(self):\n        for index, name in enumerate(self.tool_bar_functions):\n            icon = tk.PhotoImage(file='icons/' + name + '.gif')\n            self.button = tk.Button(\n                self.tool_bar, image=icon, command=lambda index=index: self.on_tool_bar_button_clicked(index))\n            self.button.grid(\n                row=index // 2, column=1 + index % 2, sticky='nsew')\n            self.button.image = icon\n\n    def remove_options_from_top_bar(self):\n        for child in self.top_bar.winfo_children():\n            child.destroy()\n\n    def show_selected_tool_icon_in_top_bar(self, function_name):\n        display_name = function_name.replace(\"_\", \" \").capitalize() + \":\"\n        tk.Label(self.top_bar, text=display_name).pack(side=\"left\")\n        photo = tk.PhotoImage(\n            file='icons/' + function_name + '.gif')\n        label = tk.Label(self.top_bar, image=photo)\n        label.image = photo\n        label.pack(side=\"left\")\n\n    def bind_mouse(self):\n        self.canvas.bind(\"<Button-1>\", self.on_mouse_button_pressed)\n        self.canvas.bind(\n            \"<Button1-Motion>\", self.on_mouse_button_pressed_motion)\n        self.canvas.bind(\n            \"<Button1-ButtonRelease>\", self.on_mouse_button_released)\n        self.canvas.bind(\"<Motion>\", self.on_mouse_unpressed_motion)\n\n    def on_mouse_button_pressed(self, event):\n        self.start_x = self.end_x = self.canvas.canvasx(event.x)\n        self.start_y = self.end_y = self.canvas.canvasy(event.y)\n        self.execute_selected_method()\n\n    def on_mouse_button_pressed_motion(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n        self.canvas.delete(self.current_item)\n        self.execute_selected_method()\n\n    def on_mouse_button_released(self, event):\n        self.end_x = self.canvas.canvasx(event.x)\n        self.end_y = self.canvas.canvasy(event.y)\n\n    def on_mouse_unpressed_motion(self, event):\n        self.show_current_coordinates(event)\n\n    def __init__(self, root):\n        super().__init__(root)\n        self.create_gui()\n        self.bind_mouse()\n\n    def create_gui(self):\n        self.create_menu()\n        self.create_top_bar()\n        self.create_tool_bar()\n        self.create_tool_bar_buttons()\n        self.create_drawing_canvas()\n        self.create_color_palette()\n        self.create_current_coordinate_label()\n        self.bind_menu_accelrator_keys()\n        self.show_selected_tool_icon_in_top_bar(\"draw_line\")\n        self.draw_line_options()\n\n    def create_menu(self):\n        self.menubar = tk.Menu(self.root)\n        menu_definitions = (\n            'File- &New/Ctrl+N/self.on_new_file_menu_clicked, Save/Ctrl+S/self.on_save_menu_clicked, SaveAs/ /self.on_save_as_menu_clicked, sep, Exit/Alt+F4/self.on_close_menu_clicked',\n            'Edit- Undo/Ctrl+Z/self.on_undo_menu_clicked, sep',\n            'View- Zoom in//self.on_canvas_zoom_in_menu_clicked,Zoom Out//self.on_canvas_zoom_out_menu_clicked',\n            'About- About/F1/self.on_about_menu_clicked'\n        )\n        self.build_menu(menu_definitions)\n\n    def create_top_bar(self):\n        self.top_bar = tk.Frame(self.root, height=25, relief=\"raised\")\n        self.top_bar.pack(fill=\"x\", side=\"top\", pady=2)\n\n    def create_tool_bar(self):\n        self.tool_bar = tk.Frame(self.root, relief=\"raised\", width=50)\n        self.tool_bar.pack(fill=\"y\", side=\"left\", pady=3)\n\n    def create_drawing_canvas(self):\n        self.canvas_frame = tk.Frame(self.root, width=900, height=900)\n        self.canvas_frame.pack(side=\"right\", expand=\"yes\", fill=\"both\")\n        self.canvas = tk.Canvas(self.canvas_frame, background=\"white\",\n                                width=500, height=500, scrollregion=(0, 0, 800, 800))\n        self.create_scroll_bar()\n        self.canvas.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)\n\n    def create_scroll_bar(self):\n        x_scroll = tk.Scrollbar(self.canvas_frame, orient=\"horizontal\")\n        x_scroll.pack(side=\"bottom\", fill=\"x\")\n        x_scroll.config(command=self.canvas.xview)\n        y_scroll = tk.Scrollbar(self.canvas_frame, orient=\"vertical\")\n        y_scroll.pack(side=\"right\", fill=\"y\")\n        y_scroll.config(command=self.canvas.yview)\n        self.canvas.config(\n            xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)\n\n    def bind_menu_accelrator_keys(self):\n        self.root.bind('<KeyPress-F1>', self.on_about_menu_clicked)\n        self.root.bind('<Control-N>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-n>', self.on_new_file_menu_clicked)\n        self.root.bind('<Control-s>', self.on_save_menu_clicked)\n        self.root.bind('<Control-S>', self.on_save_menu_clicked)\n        self.root.bind('<Control-z>', self.on_undo_menu_clicked)\n        self.root.bind('<Control-Z>', self.on_undo_menu_clicked)\n\n\nif __name__ == '__main__':\n    root = tk.Tk()\n    app = PaintApplication(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/framework.py",
    "content": "\"\"\"\n    Chapter 6: Paint Application\n        Developing a Tiny Framework\n\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\n\n\nclass Framework():\n\n    \"\"\"\n    GUIFramework is a class that provides a higher level of abstraction for\n    the development of Tkinter graphic user interfaces (GUIs).\n    Every class that uses this GUI framework must inherit from this class\n    and should pass the root window as an argument to this class by calling \n    the super method as follows:\n        super().__init__(root)\n\n    Building Menus:\n    To build a menu, call build_menu() method with one argument for\n    menu_definition, where menu_definition is a tuple where each item is a string of the\n    format:\n        'Top Level Menu Name - MenuItemName/Accelrator/Commandcallback/Underlinenumber'.\n\n        MenuSeparator is denoted by a string 'sep'.\n\n    For instance, passing this tuple as an argument to this method\n\n        menu_definition = (\n                      'File - &New/Ctrl+N/new_file, &Open/Ctrl+O/openfile, &Save/Ctrl+S/save, Save&As//saveas, sep, Exit/Alt+F4/close', \n                      'Edit - Cut/Ctrl+X/cut, Copy/Ctrl+C/copy, Paste/Ctrl+V/paste, Sep',\n                      )\n\n    will generate a File and Edit Menu Buttons with listed menu items for each of the buttons.\n    \"\"\"\n    menu_items = None\n\n    def __init__(self, root):\n        self.root = root\n\n    def build_menu(self, menu_definitions):\n        menu_bar = tk.Menu(self.root)\n        for definition in menu_definitions:\n            menu = tk.Menu(menu_bar, tearoff=0)\n            top_level_menu, pull_down_menus = definition.split('-')\n            menu_items = map(str.strip, pull_down_menus.split(','))\n            for item in menu_items:\n                self._add_menu_command(menu, item)\n            menu_bar.add_cascade(label=top_level_menu, menu=menu)\n        self.root.config(menu=menu_bar)\n\n    def _add_menu_command(self, menu, item):\n        if item == 'sep':\n            menu.add_separator()\n        else:\n            menu_label, accelrator_key, command_callback = item.split('/')\n            try:\n                underline = menu_label.index('&')\n                menu_label = menu_label.replace('&', '', 1)\n            except ValueError:\n                underline = None\n            menu.add_command(label=menu_label, underline=underline,\n                             accelerator=accelrator_key, command=eval(command_callback))\n\n\nclass TestThisFramework(Framework):\n\n    def new_file(self):\n        print('new tested OK')\n\n    def open_file(self):\n        print ('open tested OK')\n\n    def undo(self):\n        print ('undo tested OK')\n\n    def options(self):\n        print ('options tested OK')\n\n    def about(self):\n        print ('about tested OK')\n\nif __name__ == '__main__':\n\n    root = tk.Tk()\n    menu_items = (\n        'File- &New/Ctrl+N/self.new_file, &Open/Ctrl+O/self.open_file',\n        'Edit- Undo/Ctrl+Z/self.undo, sep, Options/Ctrl+T/self.options',\n        'About- About//self.about'\n    )\n    app = TestThisFramework(root)\n    app.build_menu(menu_items)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 06/supershapes.py",
    "content": "super_shapes = {\n    \"shape A\": (1.5, 1.5, 5, 2, 7, 7),\n    \"shape B\": (1.5, 1.5, 3, 5, 18, 18),\n    \"shape C\": (1.4, 1.4, 4, 2, 4, 13),\n    \"shape D\": (1.6, 1.6, 7, 3, 4, 17),\n    \"shape E\": (1.9, 1.9, 7, 3, 6, 6),\n    \"shape F\": (4, 4, 19, 9, 14, 11),\n    \"shape G\": (12, 12, 1, 15, 20, 3),\n    \"shape H\": (1.5, 1.5, 8, 1, 1, 8),\n    \"shape I\": (1.2, 1.2, 8, 1, 5, 8),\n    \"shape J\": (8, 8, 3, 6, 6, 6),\n    \"shape K\": (8, 8, 2, 1, 1, 1),\n    \"shape L\": (1.1, 1.1, 16, 0.5, 0.5, 16)\n\n}\n"
  },
  {
    "path": "Chapter 07/7.01/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 80\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n"
  },
  {
    "path": "Chapter 07/7.01/view.py",
    "content": "'''\nChapter 7: Piano Tutor\nTkinter GUI Application Development Blueprints\n\n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk\nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT, background='mint cream')\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(\n            row=0,\n            column=1,\n            columnspan=3,\n            padx=10,\n            pady=10,\n            sticky='nsew',\n            )\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT,\n                                    background='cornsilk3')\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        Label(self.keyboard_frame, text='placeholder for keyboard',\n              background='LavenderBlush2').grid()\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='SlateBlue3')\n        Label(self.scales_frame, text='placeholder for scales frame'\n              ).grid(row=1, column=1)\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='cornsilk4')\n        self.chords_frame.grid_propagate(False)\n        Label(self.chords_frame, text='placeholder for chords frame'\n              ).grid(row=1, column=1)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT,\n                bg='plum2')\n        self.progressions_frame.grid_propagate(False)\n        Label(self.progressions_frame,\n              text='placeholder for progression frame').grid(row=1,\n                column=1)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n\n    def on_mode_changed(self, event):\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.02/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 80\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n"
  },
  {
    "path": "Chapter 07/7.02/view.py",
    "content": "'''\nCode 7.02.py\n\n      Adding the piano keyboard\n\nattribute added here:\n\n   self.keys = []\n\nnew methods added here\n      create_key\n      on_key_pressesed\n      on_key_released\n\nmethod modified here\n      build_keyboard_frame\n\n\n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk\nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT, background='mint cream')\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(\n            row=0,\n            column=1,\n            columnspan=3,\n            padx=10,\n            pady=10,\n            sticky='nsew',\n            )\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT,\n                                    background='cornsilk3')\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='SlateBlue3')\n        Label(self.scales_frame, text='placeholder for scales frame'\n              ).grid(row=1, column=1)\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='cornsilk4')\n        self.chords_frame.grid_propagate(False)\n        Label(self.chords_frame, text='placeholder for chords frame'\n              ).grid(row=1, column=1)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT,\n                bg='plum2')\n        self.progressions_frame.grid_propagate(False)\n        Label(self.progressions_frame,\n              text='placeholder for progression frame').grid(row=1,\n                column=1)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n\n    def on_mode_changed(self, event):\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        print (event.widget.name + ' pressed')\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        print (event.widget.name + ' released')\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.03/audio.py",
    "content": "import simpleaudio as sa\nfrom _thread import start_new_thread\nimport time\n\ndef play_note(note_name):\n  wave_obj = sa.WaveObject.from_wave_file('../sounds/' + note_name + '.wav')\n  wave_obj.play()\n\ndef play_scale(scale):\n  for note in scale:\n    play_note(note)\n    time.sleep(0.5)\n\ndef play_scale_in_new_thread(scale):\n  start_new_thread(play_scale,(scale,))\n\ndef play_chord(scale):\n  for note in scale:\n    play_note(note)\n\ndef play_chord_in_new_thread(chord):\n  start_new_thread(play_chord,(chord,))\n"
  },
  {
    "path": "Chapter 07/7.03/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 80\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n"
  },
  {
    "path": "Chapter 07/7.03/view.py",
    "content": "'''\nCode 7.03.py\n\n      Playing Audio\n\nnew import here:\nfrom audio import play_note    \n\nmethod modified here\n      on_key_pressed\n\n\n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk\n    \nfrom audio import play_note    \nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT, background='mint cream')\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(\n            row=0,\n            column=1,\n            columnspan=3,\n            padx=10,\n            pady=10,\n            sticky='nsew',\n            )\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT,\n                                    background='cornsilk3')\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='SlateBlue3')\n        Label(self.scales_frame, text='placeholder for scales frame'\n              ).grid(row=1, column=1)\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT,\n                                  bg='cornsilk4')\n        self.chords_frame.grid_propagate(False)\n        Label(self.chords_frame, text='placeholder for chords frame'\n              ).grid(row=1, column=1)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT,\n                bg='plum2')\n        self.progressions_frame.grid_propagate(False)\n        Label(self.progressions_frame,\n              text='placeholder for progression frame').grid(row=1,\n                column=1)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n\n    def on_mode_changed(self, event):\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        play_note(event.widget.name)\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        print (event.widget.name + ' released')\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.04/audio.py",
    "content": "import simpleaudio as sa\nfrom _thread import start_new_thread\nimport time\n\ndef play_note(note_name):\n  wave_obj = sa.WaveObject.from_wave_file('../sounds/' + note_name + '.wav')\n  wave_obj.play()\n\ndef play_scale(scale):\n  for note in scale:\n    play_note(note)\n    time.sleep(0.5)\n\ndef play_scale_in_new_thread(scale):\n  start_new_thread(play_scale,(scale,))\n\ndef play_chord(scale):\n  for note in scale:\n    play_note(note)\n\ndef play_chord_in_new_thread(chord):\n  start_new_thread(play_chord,(chord,))\n"
  },
  {
    "path": "Chapter 07/7.04/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 80\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nALL_KEYS = ['C1','C#1','D1','D#1','E1','F1','F#1','G1','G#1','A1', \\\n            'A#1','B1', 'C2','C#2','D2','D#2','E2','F2','F#2','G2',\\\n            'G#2','A2','A#2','B2']\nKEYS = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n\nSCALES_JSON_FILE = '../json/scales.json'\n"
  },
  {
    "path": "Chapter 07/7.04/view.py",
    "content": "'''\n7.04\n\n    Implementing the Scales Tutor\n\nnew imports here:\n import json\n from collections import OrderedDict\n from audio import play_scale_in_new_thread\nmethod modified here\n    __init___  - added call to self.load_json_files()\n    build_scales_frame - added two combobox\n\nmethods defined here:\n    on_scale_changed\n    on_scale_key_changed\n    find_scale\n    highlight_list_of_keys\n    \n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk\nimport json    \nfrom collections import OrderedDict\nfrom audio import play_note, play_scale_in_new_thread    \nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.load_json_files()\n        self.keys_to_highlight = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n        self.find_scale()\n\n    def load_json_files(self):\n      with open(SCALES_JSON_FILE, 'r') as f:\n        self.scales = json.load(f, object_pairs_hook=OrderedDict)\n\n\n    def on_scale_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_scale(event)\n      \n    def on_scale_key_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_scale(event)\n\n    def find_scale(self, event=None):\n      self.selected_scale = self.scale_selector.get()\n      self.scale_selected_key = self.scale_key_selector.get()\n      index_of_selected_key = KEYS.index(self.scale_selected_key)\n      self.keys_to_highlight = [ ALL_KEYS[i+index_of_selected_key] \\\n                            for i in self.scales[self.selected_scale]]\n      self.highlight_list_of_keys(self.keys_to_highlight)\n      play_scale_in_new_thread(self.keys_to_highlight)\n\n    def highlight_list_of_keys(self, key_names):\n      for key in key_names:\n        self.highlight_key(key)\n\t\n    def highlight_key(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n          if widget.name == key_name:\n            widget.configure(image=key_img)\n            widget.image = key_img\n      \n    def remove_key_highlight(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n          if widget.name == key_name:\n            widget.configure(image=key_img)\n            widget.image = key_img\n      \n    def remove_all_key_highlights(self):\n      for key in self.keys_to_highlight:\n        self.remove_key_highlight(key)\n      self.keys_to_highlight = [] \n\n\n\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT)\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(\n            row=0,\n            column=1,\n            columnspan=3,\n            padx=10,\n            pady=10,\n            sticky='nsew',\n            )\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT)\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT\n                                  )\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.scales_frame, text='Select scale').grid(row=0, \\\n                                column=1, sticky='w', padx=10,pady=1)\n        self.scale_selector = ttk.Combobox(self.scales_frame, \\\n                                values=[k for k in self.scales.keys()])\n        self.scale_selector.current(0)\n        self.scale_selector.bind(\"<<ComboboxSelected>>\", \\\n                                            self.on_scale_changed)\n        self.scale_selector.grid(row=1, column=1, sticky='e', padx=10,\\\n                                                                pady=10)\n        Label(self.scales_frame, text='in the key of').grid(row=0, \\\n                                column=2, sticky='w', padx=10,pady=1)\n        self.scale_key_selector = ttk.Combobox(self.scales_frame, \\\n                                    values=[k for k in KEYS])\n        self.scale_key_selector.current(0)\n        self.scale_key_selector.bind(\"<<ComboboxSelected>>\", \\\n                                    self.on_scale_key_changed)\n        self.scale_key_selector.grid(row=1, column=2, sticky='e', \\\n                                    padx=10, pady=10)\n\n\n\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT\n                                  )\n        self.chords_frame.grid_propagate(False)\n        Label(self.chords_frame, text='placeholder for chords frame'\n              ).grid(row=1, column=1)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT)\n        self.progressions_frame.grid_propagate(False)\n        Label(self.progressions_frame,\n              text='placeholder for progression frame').grid(row=1,\n                column=1)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n\n    def on_mode_changed(self, event):\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        play_note(event.widget.name)\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        print (event.widget.name + ' released')\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.05/audio.py",
    "content": "import simpleaudio as sa\nfrom _thread import start_new_thread\nimport time\n\ndef play_note(note_name):\n  wave_obj = sa.WaveObject.from_wave_file('../sounds/' + note_name + '.wav')\n  wave_obj.play()\n\ndef play_scale(scale):\n  for note in scale:\n    play_note(note)\n    time.sleep(0.5)\n\ndef play_scale_in_new_thread(scale):\n  start_new_thread(play_scale,(scale,))\n\ndef play_chord(scale):\n  for note in scale:\n    play_note(note)\n\ndef play_chord_in_new_thread(chord):\n  start_new_thread(play_chord,(chord,))\n"
  },
  {
    "path": "Chapter 07/7.05/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 80\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nALL_KEYS = ['C1','C#1','D1','D#1','E1','F1','F#1','G1','G#1','A1', \\\n            'A#1','B1', 'C2','C#2','D2','D#2','E2','F2','F#2','G2',\\\n            'G#2','A2','A#2','B2']\nKEYS = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n\nSCALES_JSON_FILE = '../json/scales.json'\nCHORDS_JSON_FILE = '../json/chords.json'\n"
  },
  {
    "path": "Chapter 07/7.05/view.py",
    "content": "'''\n7.05\n\n    Implementing the Chords TUtor\n\nnew imports here:\n    from audio import play_chord_in_new_thread\n method modified here\n    load_json_files() # read the chords.json file in self.chords variable\n    build_chords_frame()  # build the GUI component - added combobox for\n        selecting chord and its key\n    on_mode_changed - added call to self.remove_all_key_highlights() and\n                        self.find_chord()\n\nmethods defined here:\n    on_chords_key_changed\n    on_chord_changed\n    find_chord\n\n    \n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk\nimport json    \nfrom collections import OrderedDict\nfrom audio import play_note, play_scale_in_new_thread, \\\n        play_chord_in_new_thread\nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.load_json_files()\n        self.keys_to_highlight = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n        self.find_scale()\n\n    def load_json_files(self):\n      with open(SCALES_JSON_FILE, 'r') as f:\n        self.scales = json.load(f, object_pairs_hook=OrderedDict)\n      with open(CHORDS_JSON_FILE, 'r') as f:\n        self.chords = json.load(f, object_pairs_hook=OrderedDict)\n\n    def on_chord_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_chord(event)\n    \n    def on_chords_key_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_chord(event)\n\n    def find_chord(self, event=None):\n      self.selected_chord = self.chords_selector.get()\n      self.chords_selected_key = self.chords_key_selector.get()\n      index_of_selected_key = KEYS.index(self.chords_selected_key)\n      self.keys_to_highlight = [ ALL_KEYS[i+index_of_selected_key] for \\\n                            i in self.chords[self.selected_chord]]\n      self.highlight_list_of_keys(self.keys_to_highlight)\n      play_chord_in_new_thread(self.keys_to_highlight)\n\n\n\n    def on_scale_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_scale(event)\n      \n    def on_scale_key_changed(self, event):\n      self.remove_all_key_highlights()\n      self.find_scale(event)\n\n    def find_scale(self, event=None):\n      self.selected_scale = self.scale_selector.get()\n      self.scale_selected_key = self.scale_key_selector.get()\n      index_of_selected_key = KEYS.index(self.scale_selected_key)\n      self.keys_to_highlight = [ ALL_KEYS[i+index_of_selected_key] \\\n                            for i in self.scales[self.selected_scale]]\n      self.highlight_list_of_keys(self.keys_to_highlight)\n      play_scale_in_new_thread(self.keys_to_highlight)\n\n    def highlight_list_of_keys(self, key_names):\n      for key in key_names:\n        self.highlight_key(key)\n\t\n    def highlight_key(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n          if widget.name == key_name:\n            widget.configure(image=key_img)\n            widget.image = key_img\n      \n    def remove_key_highlight(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n          if widget.name == key_name:\n            widget.configure(image=key_img)\n            widget.image = key_img\n      \n    def remove_all_key_highlights(self):\n      for key in self.keys_to_highlight:\n        self.remove_key_highlight(key)\n      self.keys_to_highlight = [] \n\n\n\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT)\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(\n            row=0,\n            column=1,\n            columnspan=3,\n            padx=10,\n            pady=10,\n            sticky='nsew',\n            )\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT)\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT\n                                  )\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.scales_frame, text='Select scale').grid(row=0, \\\n                                column=1, sticky='w', padx=10,pady=1)\n        self.scale_selector = ttk.Combobox(self.scales_frame, \\\n                                values=[k for k in self.scales.keys()])\n        self.scale_selector.current(0)\n        self.scale_selector.bind(\"<<ComboboxSelected>>\", \\\n                                            self.on_scale_changed)\n        self.scale_selector.grid(row=1, column=1, sticky='e', padx=10,\\\n                                                                pady=10)\n        Label(self.scales_frame, text='in the key of').grid(row=0, \\\n                                column=2, sticky='w', padx=10,pady=1)\n        self.scale_key_selector = ttk.Combobox(self.scales_frame, \\\n                                    values=[k for k in KEYS])\n        self.scale_key_selector.current(0)\n        self.scale_key_selector.bind(\"<<ComboboxSelected>>\", \\\n                                    self.on_scale_key_changed)\n        self.scale_key_selector.grid(row=1, column=2, sticky='e', \\\n                                    padx=10, pady=10)\n\n\n\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT\n                                  )\n        self.chords_frame.grid_propagate(False)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.chords_frame, text='Select Chord').grid(row=0, \\\n                            column=1, sticky='w', padx=10,pady=1)\n        self.chords_selector = ttk.Combobox(self.chords_frame, \\\n                            values=[k for k in self.chords.keys()])\n        self.chords_selector.current(0)\n        self.chords_selector.bind(\"<<ComboboxSelected>>\", \\\n                                    self.on_chord_changed)\n        self.chords_selector.grid(row=1, column=1, sticky='e', \\\n                                        padx=10, pady=10)\n        Label(self.chords_frame, text='in the key of').grid(row=0, \\\n                                column=2, sticky='w', padx=10,pady=1)\n        self.chords_key_selector = ttk.Combobox(self.chords_frame, \\\n                                        values=[k for k in KEYS])\n        self.chords_key_selector.current(0)\n        self.chords_key_selector.bind(\"<<ComboboxSelected>>\", \\\n                                    self.on_chords_key_changed)\n        self.chords_key_selector.grid(row=1, column=2, sticky='e', \n                            padx=10, pady=10)\n        \n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT)\n        self.progressions_frame.grid_propagate(False)\n        Label(self.progressions_frame,\n              text='placeholder for progression frame').grid(row=1,\n                column=1)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n\n    def on_mode_changed(self, event):\n        self.remove_all_key_highlights()\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n            self.find_scale()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n            self.find_chord()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        play_note(event.widget.name)\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        print (event.widget.name + ' released')\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.06/audio.py",
    "content": "import simpleaudio as sa\nfrom _thread import start_new_thread\nimport time\n\ndef play_note(note_name):\n  wave_obj = sa.WaveObject.from_wave_file('../sounds/' + note_name + '.wav')\n  wave_obj.play()\n\ndef play_scale(scale):\n  for note in scale:\n    play_note(note)\n    time.sleep(0.5)\n\ndef play_scale_in_new_thread(scale):\n  start_new_thread(play_scale,(scale,))\n\ndef play_chord(scale):\n  for note in scale:\n    play_note(note)\n\ndef play_chord_in_new_thread(chord):\n  start_new_thread(play_chord,(chord,))\n"
  },
  {
    "path": "Chapter 07/7.06/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 100\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nALL_KEYS = ['C1','C#1','D1','D#1','E1','F1','F#1','G1','G#1','A1', \\\n            'A#1','B1', 'C2','C#2','D2','D#2','E2','F2','F#2','G2',\\\n            'G#2','A2','A#2','B2']\nKEYS = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n\nSCALES_JSON_FILE = '../json/scales.json'\nCHORDS_JSON_FILE = '../json/chords.json'\nPROGRESSIONS_JSON_FILE = '../json/progressions.json'\n\nROMAN_TO_NUMBER = { 'I':0, 'II': 2, 'III':4, 'IV':5, 'V': 7, 'VI':9, 'VII': 11,\n'i':0, 'ii': 2, 'iii':4, 'iv':5, 'v': 7, 'vi':9, 'vii': 11\n}\t\n"
  },
  {
    "path": "Chapter 07/7.06/view.py",
    "content": "'''\n7.06\n\n    Implementing the Chord Progression tutor\n\nnew imports here:\n    import math\n    from functools import partial\n\nnew attributes here:\n    self.progression_buttons\n    \nmethod modified here\n    load_json_files() # read the progressions.json file in self.chords variable\n    build_progressions_frame() - added three combobox to the layout\n    on_mode_changed added call to show_progression_buttons()\n    \nmethods defined here:\n    on_progression_scale_changed\n    on_progression_key_changed\n    on_progression_changed\n    destroy_current_progression_buttons\n    show_progression_buttons\n    on_progression_button_clicked\n    \n'''\n#!/usr/bin/python\n# -*- coding: utf-8 -*-\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk, font\nimport math\nfrom functools import partial\nimport json\nfrom collections import OrderedDict\nfrom audio import play_note, play_scale_in_new_thread, \\\n    play_chord_in_new_thread\nfrom constants import *\n\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.progression_buttons = []\n        self.load_json_files()\n        self.keys_to_highlight = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n        self.find_scale()\n\n    def load_json_files(self):\n        with open(SCALES_JSON_FILE, 'r') as f:\n            self.scales = json.load(f, object_pairs_hook=OrderedDict)\n        with open(CHORDS_JSON_FILE, 'r') as f:\n            self.chords = json.load(f, object_pairs_hook=OrderedDict)\n        with open(PROGRESSIONS_JSON_FILE, 'r') as f:\n            self.progressions = json.load(f,\n                    object_pairs_hook=OrderedDict)\n\n    def on_progression_scale_changed(self, event):\n        selected_progression_scale = \\\n            self.progression_scale_selector.get()\n        progressions = [k for k in\n                        self.progressions[selected_progression_scale].keys()]\n        self.progression_selector['values'] = progressions\n        self.progression_selector.current(0)\n        self.show_progression_buttons()\n\n    def on_progression_key_changed(self, event):\n        self.show_progression_buttons()\n\n    def on_progression_changed(self, event):\n        self.show_progression_buttons()\n\n    def destroy_current_progression_buttons(self):\n        for buttons in self.progression_buttons:\n            buttons.destroy()\n\n    def show_progression_buttons(self):\n        self.destroy_current_progression_buttons()\n        selected_progression_scale = \\\n            self.progression_scale_selector.get()\n        selected_progression = self.progression_selector.get().split('-'\n                )\n        self.progression_buttons = []\n        for i in range(len(selected_progression)):\n            self.progression_buttons.append(Button(self.progressions_frame,\n                    text=selected_progression[i],\n                    command=partial(self.on_progression_button_clicked,\n                    i)))\n            sticky = ('W' if i == 0 else 'E')\n            col = (i if i > 1 else 1)\n            self.progression_buttons[i].grid(column=col, row=2,\n                    sticky=sticky, padx=10)\n\n    def on_progression_button_clicked(self, i):\n        self.remove_all_key_highlights()\n        selected_progression = self.progression_selector.get().split('-'\n                )[i]\n        if any(x.isupper() for x in selected_progression):\n            selected_chord = 'Major'\n        else:\n            selected_chord = 'Minor'\n        key_offset = ROMAN_TO_NUMBER[selected_progression]\n        selected_key = self.progression_key_selector.get()\n        index_of_selected_key = (KEYS.index(selected_key) + key_offset) \\\n            % 12\n        self.keys_to_highlight = [ALL_KEYS[j + index_of_selected_key]\n                                  for j in self.chords[selected_chord]]\n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_chord_in_new_thread(self.keys_to_highlight)\n\n    def on_chord_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_chord(event)\n\n    def on_chords_key_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_chord(event)\n\n    def find_chord(self, event=None):\n        self.selected_chord = self.chords_selector.get()\n        self.chords_selected_key = self.chords_key_selector.get()\n        index_of_selected_key = KEYS.index(self.chords_selected_key)\n        self.keys_to_highlight = [ALL_KEYS[i + index_of_selected_key]\n                                  for i in\n                                  self.chords[self.selected_chord]]\n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_chord_in_new_thread(self.keys_to_highlight)\n\n    def on_scale_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_scale(event)\n\n    def on_scale_key_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_scale(event)\n\n    def find_scale(self, event=None):\n        self.selected_scale = self.scale_selector.get()\n        self.scale_selected_key = self.scale_key_selector.get()\n        index_of_selected_key = KEYS.index(self.scale_selected_key)\n        self.keys_to_highlight = [ALL_KEYS[i + index_of_selected_key]\n                                  for i in\n                                  self.scales[self.selected_scale]]\n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_scale_in_new_thread(self.keys_to_highlight)\n\n    def highlight_list_of_keys(self, key_names):\n        for key in key_names:\n            self.highlight_key(key)\n\n    def highlight_key(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n            if widget.name == key_name:\n                widget.configure(image=key_img)\n                widget.image = key_img\n\n    def remove_key_highlight(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n            if widget.name == key_name:\n                widget.configure(image=key_img)\n                widget.image = key_img\n\n    def remove_all_key_highlights(self):\n        for key in self.keys_to_highlight:\n            self.remove_key_highlight(key)\n        self.keys_to_highlight = []\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT)\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(row=0, column=1, columnspan=3,\n            padx=10, pady=10, sticky='nsew')\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT, background='SteelBlue1')\n        self.score_sheet_frame.grid_propagate(False)\n\n        Label(self.score_sheet_frame, text='placeholder for score sheet'\n              , background='SteelBlue1').grid(row=1, column=1)\n        self.score_sheet_frame.grid(row=1, column=0)\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT)\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT)\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.scales_frame, text='Select scale').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        self.scale_selector = ttk.Combobox(self.scales_frame, values=[k\n                for k in self.scales.keys()])\n        self.scale_selector.current(0)\n        self.scale_selector.bind('<<ComboboxSelected>>',\n                                 self.on_scale_changed)\n        self.scale_selector.grid(row=1, column=1, sticky='e', padx=10,\n                                 pady=10)\n        Label(self.scales_frame, text='in the key of').grid(row=0,\n                column=2, sticky='w', padx=10, pady=1)\n        self.scale_key_selector = ttk.Combobox(self.scales_frame,\n                values=[k for k in KEYS])\n        self.scale_key_selector.current(0)\n        self.scale_key_selector.bind('<<ComboboxSelected>>',\n                self.on_scale_key_changed)\n        self.scale_key_selector.grid(row=1, column=2, sticky='e',\n                padx=10, pady=10)\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT)\n        self.chords_frame.grid_propagate(False)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.chords_frame, text='Select Chord').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        self.chords_selector = ttk.Combobox(self.chords_frame,\n                values=[k for k in self.chords.keys()])\n        self.chords_selector.current(0)\n        self.chords_selector.bind('<<ComboboxSelected>>',\n                                  self.on_chord_changed)\n        self.chords_selector.grid(row=1, column=1, sticky='e', padx=10,\n                                  pady=10)\n        Label(self.chords_frame, text='in the key of').grid(row=0,\n                column=2, sticky='w', padx=10, pady=1)\n        self.chords_key_selector = ttk.Combobox(self.chords_frame,\n                values=[k for k in KEYS])\n        self.chords_key_selector.current(0)\n        self.chords_key_selector.bind('<<ComboboxSelected>>',\n                self.on_chords_key_changed)\n        self.chords_key_selector.grid(row=1, column=2, sticky='e',\n                padx=10, pady=10)\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT)\n        self.progressions_frame.grid_propagate(False)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.progressions_frame, text='Select Scale').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        Label(self.progressions_frame, text='Select Progression'\n              ).grid(row=0, column=2, sticky='w', padx=10, pady=1)\n        Label(self.progressions_frame, text='in the Key of'\n              ).grid(row=0, column=3, sticky='w', padx=10, pady=1)\n\n        self.progression_scale_selector = \\\n            ttk.Combobox(self.progressions_frame, values=[k for k in\n                         self.progressions.keys()], width=18)\n        self.progression_scale_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_scale_changed)\n        self.progression_scale_selector.current(0)\n        self.progression_scale_selector.grid(row=1, column=1, sticky='w'\n                , padx=10, pady=10)\n\n        self.progression_selector = \\\n            ttk.Combobox(self.progressions_frame, values=[k for k in\n                         self.progressions['Major'].keys()], width=18)\n        self.progression_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_changed)\n        self.progression_selector.current(0)\n        self.progression_selector.grid(row=1, column=2, sticky='w',\n                padx=10, pady=10)\n\n        self.progression_key_selector = \\\n            ttk.Combobox(self.progressions_frame, values=KEYS, width=18)\n        self.progression_key_selector.current(0)\n        self.progression_key_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_key_changed)\n        self.progression_key_selector.grid(row=1, column=3, sticky='w',\n                padx=10, pady=10)\n\n    def on_mode_changed(self, event):\n        self.remove_all_key_highlights()\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n            self.find_scale()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n            self.find_chord()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n            self.show_progression_buttons()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        play_note(event.widget.name)\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/7.07/audio.py",
    "content": "import simpleaudio as sa\nfrom _thread import start_new_thread\nimport time\n\ndef play_note(note_name):\n  wave_obj = sa.WaveObject.from_wave_file('../sounds/' + note_name + '.wav')\n  wave_obj.play()\n\ndef play_scale(scale):\n  for note in scale:\n    play_note(note)\n    time.sleep(0.5)\n\ndef play_scale_in_new_thread(scale):\n  start_new_thread(play_scale,(scale,))\n\ndef play_chord(scale):\n  for note in scale:\n    play_note(note)\n\ndef play_chord_in_new_thread(chord):\n  start_new_thread(play_chord,(chord,))\n"
  },
  {
    "path": "Chapter 07/7.07/constants.py",
    "content": "WINDOW_WIDTH = 560\nMODE_SELECTOR_HEIGHT = 50\nCONTROLS_FRAME_HEIGHT = 100\nKEYBOARD_HEIGHT = 160\nSCORE_DISPLAY_HEIGHT = 110\nWINDOW_HEIGHT = KEYBOARD_HEIGHT + CONTROLS_FRAME_HEIGHT + \\\n                MODE_SELECTOR_HEIGHT  + SCORE_DISPLAY_HEIGHT\n\nCHOICES = ['Scales','Chords','Chord Progressions']\n\nWHITE_KEY_IMAGE = '../pictures/white_key.gif'\nWHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'\nBLACK_KEY_IMAGE = '../pictures/black_key.gif'\nBLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'\n\nALL_KEYS = ['C1','C#1','D1','D#1','E1','F1','F#1','G1','G#1','A1', \\\n            'A#1','B1', 'C2','C#2','D2','D#2','E2','F2','F#2','G2',\\\n            'G#2','A2','A#2','B2']\nKEYS = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']\n\nWHITE_KEY_NAMES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', \\\n                  'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n\nBLACK_KEY_NAMES = ['C#1', 'D#1', 'F#1', 'G#1', 'A#1', 'C#2', 'D#2', \\\n                                      'F#2', 'G#2', 'A#2']\n\nWHITE_KEY_X_COORDINATES = [0,40, 80,120, 160, 200, 240,280, 320, 360, \\\n                                                    400, 440, 480,520]\nBLACK_KEY_X_COORDINATES = [30,70,150,190, 230, 310, 350, 430,470, 510]\n\nSCALES_JSON_FILE = '../json/scales.json'\nCHORDS_JSON_FILE = '../json/chords.json'\nPROGRESSIONS_JSON_FILE = '../json/progressions.json'\n\nROMAN_TO_NUMBER = { 'I':0, 'II': 2, 'III':4, 'IV':5, 'V': 7, 'VI':9, 'VII': 11,\n'i':0, 'ii': 2, 'iii':4, 'iv':5, 'v': 7, 'vi':9, 'vii': 11\n}\t\n"
  },
  {
    "path": "Chapter 07/7.07/score_maker.py",
    "content": "from tkinter import *\nimport itertools\n\nclass ScoreMaker:\n\n  NOTES = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', 'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n  \n\n  def __init__(self, container):\n    self.canvas = Canvas(container,  width=500, height = 110)\n    self.canvas.grid(row=0, column = 1)\n    container.update_idletasks() \n    self.canvas_width = self.canvas.winfo_width()\n    self.sharp_image = PhotoImage(file='../pictures/sharp.gif')\n    self.treble_clef_image = PhotoImage(file='../pictures/treble-clef.gif')\n    self.x_counter = itertools.count(start=50, step=30)\n    \n    \n  def _clean_score_sheet(self):\n    self.x_counter = itertools.count(start=50, step=30)\n    self.canvas.delete(\"all\")\n    \n  \n  def _create_treble_staff(self):\n    self._draw_five_lines()\n    self.canvas.create_image(10, 20, image=self.treble_clef_image, anchor=NW)\n    \n\n  def draw_chord(self, chord):\n    self._clean_score_sheet()\n    self._create_treble_staff()\n    for note in chord:\n      self._draw_single_note(note, is_in_chord=True)\n\n    \n  def _draw_five_lines(self):\n    w = self.canvas_width\n    self.canvas.create_line(0,40,w,40, fill=\"#555\")\n    self.canvas.create_line(0,50,w,50, fill=\"#555\")\n    self.canvas.create_line(0,60,w,60, fill=\"#555\")\n    self.canvas.create_line(0,70,w,70, fill=\"#555\")\n    self.canvas.create_line(0,80,w,80, fill=\"#555\")\n      \n\n  def draw_notes(self, notes):\n    self._clean_score_sheet()\n    self._create_treble_staff()\n    for note in notes:\n      self._draw_single_note(note)\n\n  def _draw_single_note(self, note, is_in_chord=False):\n    is_sharp = \"#\" in note   \n    note = note.replace(\"#\",\"\")\n    radius = 9\n    if is_in_chord:\n      x = 75\n    else:  \n      x = next(self.x_counter)\n    i =  self.NOTES.index(note)\n    y = 85-(5*i)\n    self.canvas.create_oval(x,y,x+radius, y+ radius, fill=\"#555\")\n    if is_sharp:\n      self.canvas.create_image(x-10,y, image=self.sharp_image, anchor=NW)\n    if note==\"C1\":\n       self.canvas.create_line(x-5,90,x+15, 90, fill=\"#555\")\n    elif note==\"G2\":\n       self.canvas.create_line(x-5,35,x+15, 35, fill=\"#555\")\n    elif note==\"A2\":\n       self.canvas.create_line(x-5,35,x+15, 35, fill=\"#555\")\n    elif note==\"B2\":\n       self.canvas.create_line(x-5,35,x+15, 35, fill=\"#555\")\n       self.canvas.create_line(x-5,25,x+15, 25, fill=\"#555\") \n\n\n\nif __name__ == \"__main__\":\n  root = Tk()\n  s = ScoreMaker(root)\n  #notes = ['C1','D1', 'E1', 'F1', 'G1','A1', 'B1', 'C2','D2', 'E2', 'F2', 'G2','A2', 'B2']\n  #s.draw_notes(notes)\n  chord = ['C1', 'E1', 'G1', ]\n  s.draw_chord(chord)\n  root.mainloop()\n"
  },
  {
    "path": "Chapter 07/7.07/view.py",
    "content": "'''\n7.07\n\n    Implementing the Score Maker\n\nnew imports here:\n    from score_maker import ScoreMaker\n    \n   \nmethods modified here\n    build_score_sheet_frame  # instantiated ScoreMaker\n    on_progression_button_clicked\n    find_chord\n    find_scale\n\n    \n'''\nfrom tkinter import Tk, Frame, Button, BOTH, Label, PhotoImage, \\\n    StringVar, OptionMenu, ttk, font\nfrom functools import partial\nimport json\nfrom collections import OrderedDict\nfrom audio import play_note, play_scale_in_new_thread, \\\n    play_chord_in_new_thread\nfrom constants import *\nfrom score_maker import ScoreMaker\n\nclass PianoTutor:\n\n    def __init__(self, root):\n        self.root = root\n        self.root.resizable(False, False)\n        self.root.title('Piano Tutor')\n        self.keys = []\n        self.progression_buttons = []\n        self.load_json_files()\n        self.keys_to_highlight = []\n        self.build_mode_selector_frame()\n        self.build_score_sheet_frame()\n        self.build_controls_frame()\n        self.build_keyboard_frame()\n        self.build_chords_frame()\n        self.build_progressions_frame()\n        self.build_scales_frame()\n        self.find_scale()\n\n    def load_json_files(self):\n        with open(SCALES_JSON_FILE, 'r') as f:\n            self.scales = json.load(f, object_pairs_hook=OrderedDict)\n        with open(CHORDS_JSON_FILE, 'r') as f:\n            self.chords = json.load(f, object_pairs_hook=OrderedDict)\n        with open(PROGRESSIONS_JSON_FILE, 'r') as f:\n            self.progressions = json.load(f,\n                    object_pairs_hook=OrderedDict)\n\n    def on_progression_scale_changed(self, event):\n        selected_progression_scale = \\\n            self.progression_scale_selector.get()\n        progressions = [k for k in\n                        self.progressions[selected_progression_scale].keys()]\n        self.progression_selector['values'] = progressions\n        self.progression_selector.current(0)\n        self.show_progression_buttons()\n\n    def on_progression_key_changed(self, event):\n        self.show_progression_buttons()\n\n    def on_progression_changed(self, event):\n        self.show_progression_buttons()\n\n    def destroy_current_progression_buttons(self):\n        for buttons in self.progression_buttons:\n            buttons.destroy()\n\n    def show_progression_buttons(self):\n        self.destroy_current_progression_buttons()\n        selected_progression_scale = \\\n            self.progression_scale_selector.get()\n        selected_progression = self.progression_selector.get().split('-'\n                )\n        self.progression_buttons = []\n        for i in range(len(selected_progression)):\n            self.progression_buttons.append(Button(self.progressions_frame,\n                    text=selected_progression[i],\n                    command=partial(self.on_progression_button_clicked,\n                    i)))\n            sticky = ('W' if i == 0 else 'E')\n            col = (i if i > 1 else 1)\n            self.progression_buttons[i].grid(column=col, row=2,\n                    sticky=sticky, padx=10)\n\n    def on_progression_button_clicked(self, i):\n        self.remove_all_key_highlights()\n        selected_progression = self.progression_selector.get().split('-'\n                )[i]\n        if any(x.isupper() for x in selected_progression):\n            selected_chord = 'Major'\n        else:\n            selected_chord = 'Minor'\n        key_offset = ROMAN_TO_NUMBER[selected_progression]\n        selected_key = self.progression_key_selector.get()\n        index_of_selected_key = (KEYS.index(selected_key) + key_offset) \\\n            % 12\n        self.keys_to_highlight = [ALL_KEYS[j + index_of_selected_key]\n                                  for j in self.chords[selected_chord]]\n        self.score_maker.draw_chord(self.keys_to_highlight)                                  \n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_chord_in_new_thread(self.keys_to_highlight)\n\n    def on_chord_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_chord(event)\n\n    def on_chords_key_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_chord(event)\n\n    def find_chord(self, event=None):\n        self.selected_chord = self.chords_selector.get()\n        self.chords_selected_key = self.chords_key_selector.get()\n        index_of_selected_key = KEYS.index(self.chords_selected_key)\n        self.keys_to_highlight = [ALL_KEYS[i + index_of_selected_key]\n                                  for i in\n                                  self.chords[self.selected_chord]]\n        self.score_maker.draw_chord(self.keys_to_highlight)                                  \n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_chord_in_new_thread(self.keys_to_highlight)\n\n    def on_scale_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_scale(event)\n\n    def on_scale_key_changed(self, event):\n        self.remove_all_key_highlights()\n        self.find_scale(event)\n\n    def find_scale(self, event=None):\n        self.selected_scale = self.scale_selector.get()\n        self.scale_selected_key = self.scale_key_selector.get()\n        index_of_selected_key = KEYS.index(self.scale_selected_key)\n        self.keys_to_highlight = [ALL_KEYS[i + index_of_selected_key]\n                                  for i in\n                                  self.scales[self.selected_scale]]\n        self.score_maker.draw_notes(self.keys_to_highlight)                                  \n        self.highlight_list_of_keys(self.keys_to_highlight)\n        play_scale_in_new_thread(self.keys_to_highlight)\n\n    def highlight_list_of_keys(self, key_names):\n        for key in key_names:\n            self.highlight_key(key)\n\n    def highlight_key(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n            if widget.name == key_name:\n                widget.configure(image=key_img)\n                widget.image = key_img\n\n    def remove_key_highlight(self, key_name):\n        if len(key_name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(key_name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        for widget in self.keys:\n            if widget.name == key_name:\n                widget.configure(image=key_img)\n                widget.image = key_img\n\n    def remove_all_key_highlights(self):\n        for key in self.keys_to_highlight:\n            self.remove_key_highlight(key)\n        self.keys_to_highlight = []\n\n    def build_mode_selector_frame(self):\n        self.mode_selector_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=MODE_SELECTOR_HEIGHT)\n        self.mode_selector_frame.grid_propagate(False)\n        self.mode_selector = ttk.Combobox(self.mode_selector_frame,\n                values=CHOICES)\n        self.mode_selector.bind('<<ComboboxSelected>>',\n                                self.on_mode_changed)\n        self.mode_selector.current(0)\n        self.mode_selector.grid(row=0, column=1, columnspan=3,\n            padx=10, pady=10, sticky='nsew')\n        self.mode_selector_frame.grid(row=0, column=0)\n\n    def build_score_sheet_frame(self):\n        self.score_sheet_frame = Frame(self.root, width=WINDOW_WIDTH,\n                height=SCORE_DISPLAY_HEIGHT)\n        self.score_sheet_frame.grid_propagate(False)\n        self.score_sheet_frame.grid(row=1, column=0)\n        self.score_maker = ScoreMaker(self.score_sheet_frame) \n\n\n\n    def build_controls_frame(self):\n        self.controls_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=CONTROLS_FRAME_HEIGHT)\n        self.controls_frame.grid_propagate(False)\n        self.controls_frame.grid(row=2, column=0)\n\n    def build_keyboard_frame(self):\n        self.keyboard_frame = Frame(self.root, width=WINDOW_WIDTH,\n                                    height=KEYBOARD_HEIGHT,\n                                    background='LavenderBlush2')\n        self.keyboard_frame.grid_propagate(False)\n        self.keyboard_frame.grid(row=4, column=0, sticky='nsew')\n        for (index, key) in enumerate(WHITE_KEY_NAMES):\n            x = WHITE_KEY_X_COORDINATES[index]\n            self.create_key(WHITE_KEY_IMAGE, key, x)\n        for (index, key) in enumerate(BLACK_KEY_NAMES):\n            x = BLACK_KEY_X_COORDINATES[index]\n            self.create_key(BLACK_KEY_IMAGE, key, x)\n\n    def build_scales_frame(self):\n        self.scales_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT)\n        self.scales_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.scales_frame, text='Select scale').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        self.scale_selector = ttk.Combobox(self.scales_frame, values=[k\n                for k in self.scales.keys()])\n        self.scale_selector.current(0)\n        self.scale_selector.bind('<<ComboboxSelected>>',\n                                 self.on_scale_changed)\n        self.scale_selector.grid(row=1, column=1, sticky='e', padx=10,\n                                 pady=10)\n        Label(self.scales_frame, text='in the key of').grid(row=0,\n                column=2, sticky='w', padx=10, pady=1)\n        self.scale_key_selector = ttk.Combobox(self.scales_frame,\n                values=[k for k in KEYS])\n        self.scale_key_selector.current(0)\n        self.scale_key_selector.bind('<<ComboboxSelected>>',\n                self.on_scale_key_changed)\n        self.scale_key_selector.grid(row=1, column=2, sticky='e',\n                padx=10, pady=10)\n\n    def build_chords_frame(self):\n        self.chords_frame = Frame(self.controls_frame,\n                                  width=WINDOW_WIDTH,\n                                  height=CONTROLS_FRAME_HEIGHT)\n        self.chords_frame.grid_propagate(False)\n        self.chords_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.chords_frame, text='Select Chord').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        self.chords_selector = ttk.Combobox(self.chords_frame,\n                values=[k for k in self.chords.keys()])\n        self.chords_selector.current(0)\n        self.chords_selector.bind('<<ComboboxSelected>>',\n                                  self.on_chord_changed)\n        self.chords_selector.grid(row=1, column=1, sticky='e', padx=10,\n                                  pady=10)\n        Label(self.chords_frame, text='in the key of').grid(row=0,\n                column=2, sticky='w', padx=10, pady=1)\n        self.chords_key_selector = ttk.Combobox(self.chords_frame,\n                values=[k for k in KEYS])\n        self.chords_key_selector.current(0)\n        self.chords_key_selector.bind('<<ComboboxSelected>>',\n                self.on_chords_key_changed)\n        self.chords_key_selector.grid(row=1, column=2, sticky='e',\n                padx=10, pady=10)\n\n    def build_progressions_frame(self):\n        self.progressions_frame = Frame(self.controls_frame,\n                width=WINDOW_WIDTH, height=CONTROLS_FRAME_HEIGHT)\n        self.progressions_frame.grid_propagate(False)\n        self.progressions_frame.grid(row=1, column=0, sticky='nsew')\n        Label(self.progressions_frame, text='Select Scale').grid(row=0,\n                column=1, sticky='w', padx=10, pady=1)\n        Label(self.progressions_frame, text='Select Progression'\n              ).grid(row=0, column=2, sticky='w', padx=10, pady=1)\n        Label(self.progressions_frame, text='in the Key of'\n              ).grid(row=0, column=3, sticky='w', padx=10, pady=1)\n\n        self.progression_scale_selector = \\\n            ttk.Combobox(self.progressions_frame, values=[k for k in\n                         self.progressions.keys()], width=18)\n        self.progression_scale_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_scale_changed)\n        self.progression_scale_selector.current(0)\n        self.progression_scale_selector.grid(row=1, column=1, sticky='w'\n                , padx=10, pady=10)\n\n        self.progression_selector = \\\n            ttk.Combobox(self.progressions_frame, values=[k for k in\n                         self.progressions['Major'].keys()], width=18)\n        self.progression_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_changed)\n        self.progression_selector.current(0)\n        self.progression_selector.grid(row=1, column=2, sticky='w',\n                padx=10, pady=10)\n\n        self.progression_key_selector = \\\n            ttk.Combobox(self.progressions_frame, values=KEYS, width=18)\n        self.progression_key_selector.current(0)\n        self.progression_key_selector.bind('<<ComboboxSelected>>',\n                self.on_progression_key_changed)\n        self.progression_key_selector.grid(row=1, column=3, sticky='w',\n                padx=10, pady=10)\n\n    def on_mode_changed(self, event):\n        self.remove_all_key_highlights()\n        selected_mode = self.mode_selector.get()\n        if selected_mode == 'Scales':\n            self.show_scales_frame()\n            self.find_scale()\n        elif selected_mode == 'Chords':\n            self.show_chords_frame()\n            self.find_chord()\n        elif selected_mode == 'Chord Progressions':\n            self.show_progressions_frame()\n            self.show_progression_buttons()\n\n    def show_scales_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid()\n\n    def show_chords_frame(self):\n        self.chords_frame.grid()\n        self.progressions_frame.grid_remove()\n        self.scales_frame.grid_remove()\n\n    def show_progressions_frame(self):\n        self.chords_frame.grid_remove()\n        self.progressions_frame.grid()\n        self.scales_frame.grid_remove()\n\n    def create_key(self, img, key_name, x_coordinate):\n        key_image = PhotoImage(file=img)\n        label = Label(self.keyboard_frame, image=key_image, border=0)\n        label.image = key_image\n        label.place(x=x_coordinate, y=0)\n        label.name = key_name\n        label.bind('<Button-1>', self.on_key_pressed)\n        label.bind('<ButtonRelease-1>', self.on_key_released)\n        self.keys.append(label)\n        return label\n\n    def change_image_to_pressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_PRESSED_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_PRESSED_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def change_image_to_unpressed(self, event):\n        if len(event.widget.name) == 2:\n            img = WHITE_KEY_IMAGE\n        elif len(event.widget.name) == 3:\n            img = BLACK_KEY_IMAGE\n        key_img = PhotoImage(file=img)\n        event.widget.configure(image=key_img)\n        event.widget.image = key_img\n\n    def on_key_pressed(self, event):\n        play_note(event.widget.name)\n        self.change_image_to_pressed(event)\n\n    def on_key_released(self, event):\n        self.change_image_to_unpressed(event)\n\n\ndef run():\n    root = Tk()\n    SCREEN_WIDTH = root.winfo_screenwidth()\n    SCREEN_HEIGHT = root.winfo_screenheight()\n    SCREEN_X_CENTER = (SCREEN_WIDTH - WINDOW_WIDTH) / 2\n    SCREEN_Y_CENTER = (SCREEN_HEIGHT - WINDOW_HEIGHT) / 2\n    root.geometry('%dx%d+%d+%d' % (WINDOW_WIDTH, WINDOW_HEIGHT,\n                  SCREEN_X_CENTER, SCREEN_Y_CENTER))\n    root.resizable(False, False)\n    PianoTutor(root)\n    root.mainloop()\n\n\nif __name__ == '__main__':\n    run()\n\n\n\t\t\t\n"
  },
  {
    "path": "Chapter 07/handle_widget_resize.py",
    "content": "'''\n\nChapter 7\n\nHandling Widget Resize\n\n\n'''\n\n\nfrom tkinter import Tk, Label, Pack\n\nroot= Tk()\n\nlabel  = Label(root, text = 'I am a Frame', bg='red')\nlabel.pack(fill='both', expand=True)\n\n\ndef on_label_resized(event):\n    print('New Width', label.winfo_width())\n    print('New Height', label.winfo_height())\n\n\nlabel.bind(\"<Configure>\", on_label_resized)\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 07/json/chords.json",
    "content": "{ \n\"Major\" \t: [0, 4, 7],\n\"Minor\"\t\t: [0, 3, 7],\n\"Sus4\"\t\t: [0, 5, 7],\n\"5\" \t\t: [0, 4, 6],\n\"Diminished\"\t: [0, 3, 6],\n\"Augmented\"\t: [0, 4, 8],\n\"Major6\"\t: [0, 4, 7, 9],\n\"Minor6\"\t: [0, 3, 7, 8],\n\"9 or dom7\"\t: [0, 4, 7, 9],\n\"7sus4\"\t\t: [0, 5, 7, 9],\n\"Minor7\"\t: [0, 3, 7, 9],\n\"Major7\"\t: [0, 4, 7, 10],\n\"Major7#4\"\t: [0, 4, 8, 10],\n\"MinMaj7\"\t: [0, 3, 7, 10],\n\"7b5\"\t\t: [0, 4, 6, 9],\n\"Minor7b5\"\t: [0, 3, 6, 9],\n\"Aug7\"\t\t: [0, 4, 8, 10],\n\"Dim7\"\t\t: [0, 3, 6, 9]\n}\n"
  },
  {
    "path": "Chapter 07/json/progressions.json",
    "content": "{\n  \"Major\": {\n    \"I-IV-V\": [ \"0\", \"5\", \"7\"  ],\n    \"ii-V-I\": [ \"2\", \"7\", \"0\"  ],\n    \"I-V-vi-IV\": [ \"0\", \"7\", \"9\", \"5\" ],\n    \"vi-V-IV-V\": [ \"9\", \"7\", \"5\", \"7\" ],\n    \"I-vi-IV-V\": [ \"0\", \"9\", \"5\", \"7\" ],\n    \"I-IV-vi-V\": [ \"0\", \"5\",\"9\", \"7\" ],\n    \"I-V-IV-V\": [ \"0\", \"7\", \"5\", \"7\" ],\n    \"vi-ii-v-I\": [ \"9\", \"2\", \"7\",\"0\" ],\n    \"I-vi-ii-V\": [ \"0\",\"9\", \"2\", \"7\" ],\n    \"vi-IV-I-V\": [ \"9\",\"5\",\"0\", \"7\" ],\n    \"i-VI-III-VII\": [ \"0\", \"9\",\"4\",\"11\"],\n    \"I-IV-ii-V\": [\"0\", \"5\",\"2\",\"7\" ],\n    \"vi-V-IV-iii\": [\"9\",\"7\", \"5\",\"4\"],\n    \"IV-I-V-iv\": [\"5\", \"0\",\"7\",\"5\"],\n    \"I-ii-vi-IV\": [\"0\",\"2\",\"9\",\"5\"],\n    \"I-iii-vi-IV\": [ \"0\", \"4\",\"9\",\"5\"],\n    \"I-V-ii-IV\": [\"0\",  \"7\", \"2\", \"5\" ],\n    \"ii-IV-I-V\": [\"2\", \"5\", \"0\",  \"7\" ]\n  },\n  \"Minor\": {\n    \"i-VI-VII\": [ \"0\", \"9\", \"11\"],\n    \"i-iv-VII\": [ \"0\",  \"5\", \"11\"],\n    \"i-iv-v\": [ \"0\", \"5\", \"7\" ],\n    \"i-VI-III-VII\": [ \"0\", \"9\", \"4\",\"11\" ],\n    \"ii-v-i\": [ \"2\",\"7\", \"0\" ],\n    \"i-iv-v-i\": [\"0\", \"5\", \"7\", \"0\" ],\n    \"VI-VII-i-i\": [ \"9\", \"11\", \"0\", \"0\" ],\n    \"i-VII-VI-VII\": [\"0\", \"11\",\"9\", \"11\" ],\n    \"i-iv-i\": [\"0\", \"5\", \"0\"]\n  }\n}\n"
  },
  {
    "path": "Chapter 07/json/scales.json",
    "content": "{\n  \"Major\": [ 0, 2, 4, 5, 7, 9, 11 ],\n  \"Minor\": [ 0, 2, 3, 5, 7, 8, 10  ],\n  \"Harmonic minor\": [ 0, 2, 3, 5, 7, 8, 11 ],\n  \"Melodic minor\": [  0, 2, 3, 5, 7, 9, 11  ],\n  \"Major blues\": [ 0, 2, 3, 4, 7, 9 ],\n  \"Minor blues\": [ 0, 3, 5, 6, 7, 10 ],\n  \"Major pentatonic\": [ 0, 2, 4, 7,  9 ],\n  \"Minor pentatonic\": [ 0, 3, 5, 7, 10 ],\n  \"Lydian\": [ 0, 2, 4, 6, 7, 9, 11 ],\n  \"Phyrgian\": [ 0, 1, 3, 5, 7, 8, 10  ],\n  \"Arabic\": [ 0, 1, 4, 5, 7, 8, 11  ],\n  \"Aeolian\": [ 0, 2, 3, 5, 7, 8, 10 ],\n  \"Dorian\": [ 0, 2, 3, 5, 7, 9, 10 ],\n  \"Enigmatic\": [ 0, 1, 4, 6, 8, 10, 11 ],\n  \"Locrian\": [0, 1, 3, 5, 6, 8, 10 ],\n  \"Mixolydian\": [ 0, 2, 4, 5, 7, 9, 10],\n  \"Whole tone\": [0, 2, 4,6, 8, 10]\n}\n"
  },
  {
    "path": "Chapter 07/nonresponsive.py",
    "content": "'''\nChapter 7\nA note on responsiveness\n\nThis is an example of nonresponsive widgets\nRun this program and resize the window. \nNotice that the buttons remain fixed in size.\nIf the window size is made smaller, some of the buttons disappear from view\n\n'''\nfrom tkinter import Tk, Button\n\nroot = Tk()\n\nfor x in range(10):\n    btn = Button(root, text=x )\n    btn.grid(column=x, row=1, sticky='nsew')\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 07/responsive.py",
    "content": "'''\n\nChapter 7\n\nA demonstration of a responsive window\nusing Grid.rowconfigure and Grid.columnconfigure\n\n'''\nfrom tkinter import Tk, Button, Grid\n\nroot = Tk()\n\nfor x in range(10):\n    btn = Button(root, text=x )\n    btn.grid(column=x, row=1, sticky='nsew')\n    Grid.rowconfigure(root, 2, weight=x)\n    Grid.columnconfigure(root, 2, weight=x)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.01_screensaver.py",
    "content": "\"\"\"\nCode illustration: 8.01\n    Screensaver\nTkinter GUI Application Development Blueprints\n\"\"\"\n\n\nfrom tkinter import Tk, Canvas, BOTH\nfrom random import randint\n\n\nclass RandomBall:\n\n    def __init__(self, canvas):\n        self.canvas = canvas\n        self.screen_width = canvas.winfo_screenwidth()\n        self.screen_height = canvas.winfo_screenheight()\n        self.create_ball()\n\n    def create_ball(self):\n        self.generate_random_attributes()\n        self.create_oval()\n\n    def generate_random_attributes(self):\n        self.radius = r = randint(40, 70)\n        self.x_coordinate = randint(r, self.screen_width - r)\n        self.y_coordinate = randint(r, self.screen_height - r)\n        self.x_velocity = randint(6, 12)\n        self.y_velocity = randint(6, 12)\n        self.color = self.generate_random_color()\n\n    def generate_random_color(self):\n        r = lambda: randint(0, 0xffff)\n        return '#{:04x}{:04x}{:04x}'.format(r(), r(), r())\n\n    def create_oval(self):\n        x1 = self.x_coordinate - self.radius\n        y1 = self.y_coordinate - self.radius\n        x2 = self.x_coordinate + self.radius\n        y2 = self.y_coordinate + self.radius\n        self.ball = self.canvas.create_oval(\n            x1, y1, x2, y2, fill=self.color, outline=self.color)\n\n    def move_ball(self):\n        self.check_screen_bounds()\n        self.x_coordinate += self.x_velocity\n        self.y_coordinate += self.y_velocity\n        self.canvas.move(self.ball, self.x_velocity, self.y_velocity)\n\n    def check_screen_bounds(self):\n        r = self.radius\n        if not r < self.y_coordinate < self.screen_height - r:\n            self.y_velocity = -self.y_velocity\n        if not r < self.x_coordinate < self.screen_width - r:\n            self.x_velocity = -self.x_velocity\n\n\nclass ScreenSaver:\n\n    balls = []\n\n    def __init__(self, number_of_balls):\n        self.root = Tk()\n        self.number_of_balls = number_of_balls\n        self.root.attributes('-fullscreen', True)\n        self.root.attributes('-alpha', 0.1)\n        self.root.wm_attributes('-alpha',0.1)\n        self.quit_on_interaction()\n        self.create_screensaver()\n        self.root.mainloop()\n\n    def create_screensaver(self):\n        self.create_canvas()\n        self.add_balls_to_canvas()\n        self.animate_balls()\n\n    def create_canvas(self):\n        self.canvas = Canvas(self.root)\n        self.canvas.pack(expand=1, fill=BOTH)\n\n    def add_balls_to_canvas(self):\n        for i in range(self.number_of_balls):\n            self.balls.append(RandomBall(self.canvas))\n\n    def quit_on_interaction(self):\n        for seq in ('<Any-KeyPress>', '<Any-Button>', '<Motion>'):\n            self.root.bind(seq, self.quit_screensaver)\n\n    def animate_balls(self):\n        for ball in self.balls:\n            ball.move_ball()\n        self.root.after(30, self.animate_balls)\n\n    def quit_screensaver(self, event):\n        self.root.destroy()\n\nif __name__ == \"__main__\":\n    ScreenSaver(number_of_balls=18)\n"
  },
  {
    "path": "Chapter 08/8.02_pie_chart.py",
    "content": "\"\"\"\nCode illustration: 8.02\n    Pie chart\nTkinter GUI Application Development Blueprints\n\"\"\"\n\n\nimport tkinter\n\nroot = tkinter.Tk()\ntotal_value_to_represent_by_pie_chart = 1000\n\n\ndef angle(n):\n    return 360.0 * n / total_value_to_represent_by_pie_chart\n\ntkinter.Label(root, text='Pie Chart').pack()\n\ncanvas = tkinter.Canvas(width=154, height=154)\ncanvas.pack()\n\ncanvas.create_arc((2, 2, 152, 152), fill=\"#FAF402\",\n                  outline=\"#FAF402\", start=angle(0), extent=angle(200))\ncanvas.create_arc((2, 2, 152, 152), fill=\"#00AC36\",\n                  outline=\"#00AC36\", start=angle(200), extent=angle(300))\ncanvas.create_arc((2, 2, 152, 152), fill=\"#7A0871\",\n                  outline=\"#7A0871\", start=angle(500), extent=angle(150))\ncanvas.create_arc((2, 2, 152, 152), fill=\"#E00022\",\n                  outline=\"#E00022\", start=angle(650), extent=angle(200))\ncanvas.create_arc((2, 2, 152, 152), fill=\"#294994\",\n                  outline=\"#294994\",  start=angle(850), extent=angle(150))\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.03_bar_graph.py",
    "content": "\"\"\"\nCode illustration: 8.03 \n    Bar graph\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter\nimport random\n\nroot = tkinter.Tk()\n\ncanvas_width = 250\ncanvas_height = 220\nbar_width = 20\n\ncanv = tkinter.Canvas(\n    root, width=canvas_width, height=canvas_height, bg='white')\ncanv.pack()\n\nplot_data = [random.randint(75, 200) for r in range(12)]\n\nfor x, y in enumerate(plot_data):\n    x1 = x + x * bar_width\n    y1 = canvas_height - y\n    x2 = x + x * bar_width + bar_width\n    y2 = canvas_height\n    canv.create_rectangle(x1, y1, x2, y2, fill=\"blue\")\n    canv.create_text(x1 + 3, y1, font=(\"\", 6), text=str(y), anchor='sw')\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.04_scatter_plot.py",
    "content": "\"\"\"\nCode illustration: 8.04\n    Scatter Plot\n\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter\nimport random\nroot = tkinter.Tk()\n\n\ndef motion(event):\n    x, y = event.x, event.y\n    print(\"canvas x,y\", '{}, {}'.format(x, y))\n    print(\"plot xy\", '{}, {}'.format(x - 50, 250 - y))\n\nroot.bind('<Motion>', motion)\n\nc = tkinter.Canvas(root, width=350, height=280, bg='white')\nc.grid()\n\n# create x-axis\nc.create_line(50, 250, 300, 250, width=3)\nfor i in range(12):\n    x = 50 + (i * 20)\n    c.create_text(x, 255, font=(\"\", 6), anchor='n', text='{}'.format(20 * i))\n\n\n# y-axis\nc.create_line(50, 250, 50, 20, width=3)\nfor i in range(12):\n    y = 250 - (i * 20)\n    c.create_text(45, y, font=(\"\", 6), anchor='e', text='{}'.format(20 * i))\n\n\n# create scatter plots from random x-y values\nfor i in range(35):\n    x, y = random.randint(0, 160) + 50, 250 - random.randint(50, 220)\n    c.create_oval(x - 3, y - 3, x + 3, y + 3, width=1, fill='red')\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.05_matplotlib_embedding_graphs.py",
    "content": "\"\"\"\nCode illustration: 8.05\n    Embedding Matplotlib graph on tkinter\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\nfrom numpy import arange, sin, pi\nfrom matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg\nfrom matplotlib.figure import Figure\n\nroot = tk.Tk()\n\n# creating the graph\nf = Figure(figsize=(5, 4), dpi=100)\na = f.add_subplot(111)\nt = arange(-1.0, 1.0, 0.001)\ns = t * sin(1 / t)\na.plot(t, s)\n\n# embedding matplotlib figure f on a tk.DrawingArea\ncanvas = FigureCanvasTkAgg(f, master=root)\ncanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)\n\n# creating toolbar\ntoolbar = NavigationToolbar2TkAgg(canvas, root)\ntoolbar.update()\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.06_polar_plot.py",
    "content": "\"\"\"\nCode illustration: 8.06\n    Polar Plot\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Canvas, W\nimport math\n\nwidth = 400\nheight = 400\nx_center = width //2\ny_center = height//2\nscaling_factor  = 60\n\ndef polar_to_cartesian(r, theta, scaling_factor, x_center, y_center):\n  x = r * math.cos(theta) * scaling_factor + x_center\n  y = r * math.sin(theta) * scaling_factor + y_center\n  return(x, y)\n\nroot = Tk()\nroot.title(\"Polar Plot Demo\")\nc = Canvas(width=width, height=height, bg='white')\nc.pack()\n\n# draw radial lines at interval of 15 degrees\nfor theta in range(0,360,15):\n  r = 180\n  x, y = x_center + math.cos(math.radians(theta))*r, \\\n         y_center - math.sin(math.radians(theta)) *r\n  c.create_line(x_center, y_center, x, y, fill='green', dash=(2, 4),\\\n                activedash=(6, 5, 2, 4) )\n  c.create_text(x, y, anchor=W, font=\"Purisa 8\", text=str(theta) + '°')\n\n# draw concentric_circles\nfor radius in range(1,4):\n   x_max = x_center + radius * scaling_factor\n   x_min = x_center - radius * scaling_factor\n   y_max = y_center + radius * scaling_factor\n   y_min = y_center - radius * scaling_factor\n   c.create_oval(x_max, y_max, x_min, y_min, width=1, outline='grey', \\\n                 dash=(2, 4), activedash=(6, 5, 2, 4))\n\n\nfor theta in range(0, 3000):\n  r = 2*math.sin(2*theta)\n  # a few equations that look good on polar plot -\n  # uncomment one line at a time to see the individual plots\n  # also change parameters of equations to see their effect on the plots\n  # r = 0.0006 * theta\n  #r = 1 + 2*math.cos(theta)\n  #r = 3 * math.cos(theta)\n  #r = 2*math.sin(5*theta)\n  #r = 2 * math.cos(3*theta)\n  #r = 2 * math.sin(theta)**2\n  #r = (4 * math.sin(2*theta))**1/2\n  #r = (4 * math.cos(2*theta))**1/2\n  x, y = polar_to_cartesian(r, theta, scaling_factor, x_center, y_center)\n  c.create_oval(x, y, x, y, width=1, outline='navy')\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.07_gravity_simulation.py",
    "content": "\"\"\"\nCode illustration: 8.07\n    Gravity Simulation\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport math\nimport tkinter as tk\n\nw = 700\nh = 700\n\nroot = tk.Tk()\nroot.geometry('{}x{}'.format(w, h))\ncanvas = tk.Canvas(root, height=h, width=w, bg='black')\ncanvas.pack()\nroot.update_idletasks()\n\n\nclass Planet:\n  sun_mass = 1.989 * math.pow(10, 30)\n  G = 6.67 * math.pow(10, -11)\n\n  def __init__(self, name, mass, distance, radius, color, canvas):\n    self.name = name\n    self.mass = mass\n    self.distance = distance\n    self.radius = radius\n    self.canvas = canvas\n    self.color = color\n    self.angular_velocity = -math.sqrt(self.gravitational_force() /\n                                      (self.mass * self.distance))\n    self.oval_id = self.draw_initial_planet()\n    self.scaled_radius = self.radius_scaler(self.radius)\n    self.scaled_distance = self.distance_scaler(self.distance)\n\n  def distance_scaler(self, value):\n    #[57.91, 4497.1] scaled to [0, self.canvas.winfo_width()/2]\n    return (self.canvas.winfo_width() / 2 - 1) * (value - 1e10) / (\n        2.27e11 - 1e10) + 1\n\n  def radius_scaler(self, value):\n    #[2439, 6051.8] scaled to [0, self.canvas.winfo_width()/2]\n    return (16 * (value - 2439) / (6052 - 2439)) + 2\n\n  def draw_initial_planet(self):\n    screen_dim = self.canvas.winfo_width()\n    scaled_distance = self.distance_scaler(self.distance)\n    scaled_radius = self.radius_scaler(self.radius)\n    y = screen_dim / 2\n    x = screen_dim / 2 + scaled_distance\n    oval_id = self.canvas.create_oval(\n        x - scaled_radius,\n        y - scaled_radius,\n        x + scaled_radius,\n        y + scaled_radius,\n        fill=self.color,\n        outline=self.color)\n    return oval_id\n\n  def gravitational_force(self):\n    f = self.G * (self.mass * self.sun_mass) / math.pow(self.distance, 2)\n    return f\n\n  def angular_position(self, t):\n    theta = (0 + self.angular_velocity * t)\n    return theta\n\n  def coordinates(self, theta):\n    screen_dim = self.canvas.winfo_width()\n    y = self.scaled_distance * math.sin(theta) + screen_dim / 2\n    x = self.scaled_distance * math.cos(theta) + screen_dim / 2\n    return (x, y)\n\n  def update_location(self, t):\n    theta = self.angular_position(t)\n    x, y = self.coordinates(theta)\n    scaled_radius = self.scaled_radius\n    self.canvas.create_rectangle(x, y, x, y, outline=\"grey\")\n    self.canvas.coords(self.oval_id, x - scaled_radius, y - scaled_radius,\n                       x + scaled_radius, y + scaled_radius)\n\n\nclass Moon(Planet):\n  earth_mass = 5.973 * math.pow(10, 24)\n\n  def __init__(self, name, mass, distance, radius, color, canvas, earth):\n    super().__init__(name, mass, distance, radius, color, canvas)\n    self.angular_velocity = -math.sqrt(self.gravitational_force() /\n                                      (self.mass * self.distance))\n    self.earth = earth\n    self.scaled_distance = 25  # since distance scaling was based on distance from sun\n    self.scaled_radius = 2  # since moon's scaled radius was getting negative\n\n  def gravitational_force(self):\n    f = self.G * (self.mass * self.earth_mass) / math.pow(self.distance, 2)\n    return f\n\n  def coordinates(self, t):\n    theta = self.angular_position(t)\n    earth_x, earth_y = self.earth.coordinates(self.earth.angular_position(t))\n    dist = self.scaled_distance\n    x = earth_x + dist * math.cos(theta)\n    y = earth_y + dist * math.sin(theta)\n    return (x, y)\n\n  def update_location(self, t):\n    x, y = self.coordinates(t)\n    scaled_radius = self.scaled_radius\n    self.canvas.create_rectangle(x, y, x, y, outline=\"red\")\n    self.canvas.coords(self.oval_id, x - scaled_radius, y - scaled_radius,\n                       x + scaled_radius, y + scaled_radius)\n\n\n#name,mass,distance,radius, color, canvas\nmercury = Planet(\"Mercury\", 3.302e23, 5.7e10, 2439.7, 'red2', canvas)\nvenus = Planet(\"Venus\", 4.8685e24, 1.08e11, 6051.8, 'CadetBlue1', canvas)\nearth = Planet(\"Earth\", 5.973e24, 1.49e11, 6378, 'RoyalBlue1', canvas)\nmars = Planet(\"Mars\", 6.4185e23, 2.27e11, 3396, 'tomato2', canvas)\nplanets = [mercury, venus, earth, mars]\nmoon = Moon(\"Moon\", 7.347e22, 3.844e5, 173, 'white', canvas, earth)\n\ntime = 0\ntime_step = 100000\n\n\ndef update_bodies_position():\n  global time, time_step\n  for planet in planets:\n    planet.update_location(time)\n  moon.update_location(time)\n  time = time + time_step\n  root.after(100, update_bodies_position)\n\n\nupdate_bodies_position()\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.08_Mandelbrot.py",
    "content": "\"\"\"\nCode illustration: 8.08\n    Mandelbrot Set\n    *** This may take some time to compute ***\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Canvas\nimport math\n\nimage_width = 512\nimage_height = 512\nmax_number_of_iterations = 50\nmin_real, max_real, min_imaginary, max_imaginary = -1.5, 0.7, -1.0, 1.0\n\nroot = Tk()\ncanvas = Canvas(root, height=image_height, width=image_width)\ncanvas.pack()\n\ndef mandelbrot_set_check(real, imaginary):\n  iteration_count = 0\n  z_real = 0.0\n  z_imaginary = 0.0\n  while iteration_count < max_number_of_iterations and \\\n        z_real * z_real + z_imaginary * z_imaginary < 4.0:\n    temp = z_real * z_real - z_imaginary * z_imaginary + real\n    z_imaginary = 2.0 * z_real * z_imaginary + imaginary\n    z_real = temp\n    iteration_count += 1\n  return iteration_count\n\n\ndef get_color(num_iterations):\n  if num_iterations == max_number_of_iterations:\n    r,g,b = (0, 0, 0)\n  elif num_iterations < max_number_of_iterations//8:\n    r,g,b = (num_iterations * 2)%255, 0, 0\n  elif num_iterations < max_number_of_iterations//7:\n    r,g,b = (num_iterations * 4) % 255, 0, 0\n  elif num_iterations < max_number_of_iterations//6:\n    r,g,b = (num_iterations * 8) % 255, 0, 0\n  elif (num_iterations < max_number_of_iterations//5):\n    r,g,b = 255, (num_iterations * 16) % 255 , 0\n  elif (num_iterations < max_number_of_iterations//4):\n    r,g,b = 255, (num_iterations * 64) % 255, 0\n  elif (num_iterations < max_number_of_iterations//3):\n    r,g,b = 255, (num_iterations * 128) % 255, 0\n  elif (num_iterations < max_number_of_iterations//2):\n    r,g,b = (255, (num_iterations * 256) % 255 , 0)\n  else:\n    r, g, b = (255, 255, 0)\n  rgb = '#%02x%02x%02x' % (r, g, b)\n  return rgb\n\n\ndef map_pixels_to_real(x):\n  real_range = max_real - min_real\n  return x * (real_range / image_width) + min_real\n\n\ndef map_pixels_to_imaginary(y):\n  imaginary_range = max_imaginary - min_imaginary\n  return y * (imaginary_range / image_height) + min_imaginary\n\n\nfor y in range(image_height):\n  for x in range(image_width):\n    real = map_pixels_to_real(x)\n    imaginary = map_pixels_to_imaginary(y)\n    num_iterations = mandelbrot_set_check(real, imaginary)\n    rgb = get_color(num_iterations)\n    canvas.create_rectangle([x, y, x, y], fill=rgb, width=0)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.09_vornoi_diagram.py",
    "content": "\"\"\"\nCode illustration: 8.09\n    Vornoi Diagrams\n     *** Warnig - this code takes up to a few minutes to compute ***\n\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Canvas\nimport random\nimport math\n\nwidth = 800\nheight = 500\nnumber_of_attractor_points = 125\n\n\ndef create_voronoi_diagram(canvas, w, h, number_of_attractor_points):\n  attractor_points = []\n  colors = []\n  for i in range(number_of_attractor_points):\n    attractor_points.append((random.randrange(w), random.randrange(h)))\n    colors.append('#%02x%02x%02x' % (random.randrange(256),\n                                     random.randrange(256),\n                                     random.randrange(256)))\n  for y in range(h):\n    for x in range(w):\n      minimum_distance = math.hypot(w , h )\n      index_of_nearest_attractor_point = -1\n      for i in range(number_of_attractor_points):\n        distance = math.hypot(attractor_points[i][0] - x, attractor_points[i][1] - y)\n        if distance < minimum_distance:\n          minimum_distance = distance\n          index_of_nearest_attractor_point = i\n      canvas.create_rectangle([x, y, x, y],\n                        fill=colors[index_of_nearest_attractor_point], width=0)\n  for point in attractor_points:\n    x, y = point\n    dot = [x - 1, y - 1, x + 1, y + 1]\n    canvas.create_rectangle(dot, fill='blue', width=1)\n\n\nroot = Tk()\ncanvas = Canvas(root, height=height, width=width)\ncanvas.pack()\ncreate_voronoi_diagram(canvas, width, height, number_of_attractor_points)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.10_spring_pendulum.py",
    "content": "\"\"\"\nCode illustration: 8.10\n    Spring Pendulum Simulation\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Canvas\nimport numpy as np\nfrom scipy.integrate import odeint\n\nUNSTRETCHED_SPRING_LENGHT = 30\nSPRING_CONSTANT = 0.1\nMASS = 0.3\nGRAVITY = 9.8\nNUMBER_OF_STEPS_IN_SIMULATION = 500\n\nstate_vector = [1, 1, 2, 1]\n# 4 values represent 'l', 'dl/dt', 'θ', 'dθ/dt' respectively\n# i;e 'spring_length', 'dl/dt - velocity', 'angle', 'anglular velocity'\n\n\ndef differential_functions(state_vector, time):\n  func1 = state_vector[1]\n  func2 = (UNSTRETCHED_SPRING_LENGHT + state_vector[0]\n           ) * state_vector[3]**2 - (SPRING_CONSTANT / MASS * state_vector[0]\n                                     ) + GRAVITY * np.cos(state_vector[2])\n  func3 = state_vector[3]\n  func4 = -(GRAVITY * np.sin(state_vector[2]) +\n            2.0 * state_vector[1] * state_vector[3]) / (\n                UNSTRETCHED_SPRING_LENGHT + state_vector[0])\n  return np.array([func1, func2, func3, func4])\n\n\ntime = np.linspace(0, 37, NUMBER_OF_STEPS_IN_SIMULATION)\node_solution = odeint(differential_functions, state_vector, time)\n\nx_coordinates = (UNSTRETCHED_SPRING_LENGHT + ode_solution[:, 0]) * np.sin(\n    ode_solution[:, 2])\ny_coordinates = (UNSTRETCHED_SPRING_LENGHT + ode_solution[:, 0]) * np.cos(\n    ode_solution[:, 2])\n\n\nw = 250\nh = 300\nplot_step = 0\n\nroot = Tk()\ncanvas = Canvas(root, bg=\"LemonChiffon3\", height=h, width=w)\ncanvas.pack(side='left')\n\n\ndef update_graph():\n  global plot_step\n  if plot_step == NUMBER_OF_STEPS_IN_SIMULATION: # simulation ended\n    plot_step = 0 # repeat the simulation\n  x, y = int(\n      x_coordinates[plot_step]) + w / 2, int(y_coordinates[plot_step] + h / 2)\n  canvas.delete('all')\n  canvas.create_line(w / 2, 0, x, y, dash=(2, 1), width=1, fill=\"gold4\")\n  canvas.create_oval(\n      x - 10, y - 10, x + 10, y + 10, outline=\"gold4\", fill=\"lavender\")\n  plot_step = plot_step + 1\n  root.after(15, update_graph)\n\n\nupdate_graph()\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.11_chaos_game.py",
    "content": "\"\"\"\nCode illustration: 8.11\n    Chaos Game\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport random\nfrom tkinter import Tk, Canvas\nimport math\n\n\nWIDTH = 800\nHEIGHT = 500\n\nv1 = (float(WIDTH/2), 0.0)\nv2 = (0.00, float(HEIGHT))\nv3 = (float(WIDTH), float(HEIGHT))\n\n\nlast_point = None\n\nroot = Tk()\ncanvas = Canvas(root, background=\"#660099\", width = WIDTH, height = HEIGHT)\ncanvas.pack()\n\ndef midway_point(p1, p2):\n    x = p1[0] + (p2[0] - p1[0]) //2\n    y = p1[1] + (p2[1] - p1[1]) //2\n    return (x,y)\n\n\ndef random_point_inside_triangle(v1, v2, v3):\n    a = random.random()\n    b = random.random()\n    if a + b > 1:\n        a = 1-a\n        b = 1-b\n    c = 1 - a -b\n    x = (a*v1[0])+(b*v2[0])+(c*v3[0]);\n    y = (a*v1[1])+(b*v2[1])+(c*v3[1]);\n    return (x,y)\n\nlast_point = random_point_inside_triangle(v1, v2, v3)\n\ndef get_next_point():\n    global last_point\n    roll = random.choice(range(6))+1\n    mid_point = None\n    if roll == 1 or roll == 2:\n      mid_point = midway_point(last_point, v1)\n    elif roll == 3 or roll == 4:\n      mid_point = midway_point(last_point, v2)\n    elif roll == 5 or roll == 6:\n      mid_point = midway_point(last_point, v3)\n    last_point = mid_point\n    return mid_point\n\ndef update():\n   x,y  = get_next_point()\n   canvas.create_rectangle(x, y, x, y, outline=\"#FFFF33\")\n   root.after(1, update)\n\nupdate()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.12_phyllotaxis.py",
    "content": "\"\"\"\nCode illustration: 8.12\n    Screensaver\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Canvas\nimport numpy as np\nimport random\n\nwidth = 500\nheight = 500\nnumber_of_dots = 2000\nangle = 137.5\nscaling_factor = 4\ndot_size = 4\nn = np.arange(number_of_dots)\nr = np.zeros(number_of_dots)\nphi = np.zeros(number_of_dots)\nx = np.zeros(number_of_dots)\ny = np.zeros(number_of_dots)\ndots = []\ncolors = []\n\nroot = Tk()\ncanvas = Canvas(root, width=width, height=height, bg='grey6')\ncanvas.pack()\n\nfor i in n:\n  r = (scaling_factor * np.sqrt(i) * 6) % 256\n  color = '#%02x%02x%02x' % (int(r), 0, 0)\n  colors.append(color)\n  dots.append(\n      canvas.create_oval(\n          x[i] - dot_size,\n          y[i] - dot_size,\n          x[i] + dot_size,\n          y[i] + dot_size,\n          fill=color))\n\n\ndef update():\n  global angle\n  angle += 0.000001\n  phi = angle * n\n  r = scaling_factor * np.sqrt(n)\n  x = r * np.cos(phi) + width / 2\n  y = r * np.sin(phi) + height / 2\n  for i in n:\n    canvas.coords(dots[i], x[i] - dot_size, y[i] - dot_size, x[i] + dot_size,\n                  y[i] + dot_size)\n  root.after(15, update)\n\n\nupdate()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 08/8.13_3D_graphics.py",
    "content": "\"\"\"\nCode illustration: 8.13_3D_graphics\n    3D Graphics\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Canvas, BOTH, YES,ALL\nfrom math import *\n\n\nclass MatrixHelpers:\n  def transpose_matrix(self, matrix):\n    return list(zip(*matrix))\n\n  def translate_vector(self, x, y, dx, dy):\n    return x + dx, y + dy\n\n  def matrix_multiply(self, matrix_a, matrix_b):\n    zip_b = list(zip(*matrix_b))\n    return [[\n        sum(ele_a * ele_b for ele_a, ele_b in zip(row_a, col_b))\n        for col_b in zip_b\n    ] for row_a in matrix_a]\n\n  def rotate_along_x(self, x, shape):\n    return self.matrix_multiply(\n        [[1, 0, 0], [0, cos(x), -sin(x)], [0, sin(x), cos(x)]], shape)\n\n  def rotate_along_y(self, y, shape):\n    return self.matrix_multiply(\n        [[cos(y), 0, sin(y)], [0, 1, 0], [-sin(y), 0, cos(y)]], shape)\n\n  def rotate_along_z(self, z, shape):\n    return self.matrix_multiply(\n        [[cos(z), sin(z), 0], [-sin(z), cos(z), 0], [0, 0, 1]], shape)\n\n\nclass Cube(MatrixHelpers):\n\n  last_x = 0\n  last_y = 0\n  fg_color = 'red'\n  bg_color = 'khaki'\n\n  def __init__(self, root):\n    self.root = root\n    self.init_data()\n    self.create_canvas()\n    self.draw_cube()\n    self.bind_mouse_buttons()\n    self.continually_rotate()\n    self.epsilon = lambda d: d * 0.01\n\n  def init_data(self):\n    self.cube = self.transpose_matrix([[-100, -100, -100], [-100, 100, -100], [\n        -100, -100, 100\n    ], [-100, 100, 100], [100, -100, -100], [100, 100, -100], [100, -100, 100],\n                                       [100, 100, 100]])\n\n  def create_canvas(self):\n    self.canvas = Canvas(\n        self.root, width=400, height=400, background=self.bg_color)\n    self.canvas.pack(fill=BOTH, expand=YES)\n\n  def bind_mouse_buttons(self):\n    self.canvas.bind(\"<Button-1>\", self.on_mouse_clicked)\n    self.canvas.bind(\"<B1-Motion>\", self.on_mouse_motion)\n\n  def draw_cube(self):\n    cube_points = [[0, 1, 2, 4], [3, 1, 2, 7], [5, 1, 4, 7], [6, 2, 4, 7]]\n    w = self.canvas.winfo_width() / 2\n    h = self.canvas.winfo_height() / 2\n    self.canvas.delete(ALL)\n    for i in cube_points:\n      for j in i:\n        self.canvas.create_line(\n            self.translate_vector(self.cube[0][i[0]], self.cube[1][i[0]], w,\n                                  h),\n            self.translate_vector(self.cube[0][j], self.cube[1][j], w, h),\n            fill=self.fg_color)\n\n  def continually_rotate(self):\n    self.cube = self.rotate_along_x(0.01, self.cube)\n    self.cube = self.rotate_along_y(0.01, self.cube)\n    self.cube = self.rotate_along_z(0.01, self.cube)\n    self.draw_cube()\n    self.root.after(15, self.continually_rotate)\n\n  def on_mouse_clicked(self, event):\n    self.last_x = event.x\n    self.last_y = event.y\n\n  def on_mouse_motion(self, event):\n    dx = self.last_y - event.y\n    self.cube = self.rotate_along_x(self.epsilon(-dx), self.cube)\n    dy = self.last_x - event.x\n    self.cube = self.rotate_along_y(self.epsilon(dy), self.cube)\n    self.draw_cube()\n    self.on_mouse_clicked(event)\n\n\ndef main():\n  root = Tk()\n  Cube(root)\n  root.mainloop()\n\n\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "Chapter 09/9.01_race_condition.py",
    "content": "\"\"\"\nCode illustration: 9.01\n    Race Condition Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport threading\n\n\nclass RaceConditionDemo:\n\n    def __init__(self):\n        self.shared_var = 0\n        self.total_count = 100000\n        self.demo_of_race_condition()\n\n    def increment(self):\n        for i in range(self.total_count):\n            self.shared_var += 1\n\n    def decrement(self):\n        for i in range(self.total_count):\n            self.shared_var -= 1\n\n    def demo_of_race_condition(self):\n        t1 = threading.Thread(target=self.increment)\n        t2 = threading.Thread(target=self.decrement)\n        t1.start()\n        t2.start()\n        t1.join()\n        t2.join()\n        print(\"value of shared_var after all increments & decrements :\",\n              self.shared_var)\n\nif __name__ == \"__main__\":\n    for i in range(100):\n        RaceConditionDemo()\n"
  },
  {
    "path": "Chapter 09/9.02_lock_demo.py",
    "content": "\"\"\"\nCode illustration: 9.02\n    Lock Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport threading\n\n\nclass LockDemo():\n\n    def __init__(self):\n        self.shared_var = 0\n        self.total_count = 100000\n        self.lock = threading.Lock()\n        self.demo_of_lock_to_avoid_race_condition()\n\n    def increment(self):\n        for i in range(self.total_count):\n            self.lock.acquire()\n            self.shared_var += 1\n            self.lock.release()\n\n    def decrement(self):\n        for i in range(self.total_count):\n            self.lock.acquire()\n            self.shared_var -= 1\n            self.lock.release()\n\n    def demo_of_lock_to_avoid_race_condition(self):\n        t1 = threading.Thread(target=self.increment)\n        t2 = threading.Thread(target=self.decrement)\n        t1.start()\n        t2.start()\n        t1.join()\n        t2.join()\n        print(\"value of shared_var after all increments & decrements :\",\n              self.shared_var)\n\nif __name__ == \"__main__\":\n    for i in range(100):\n        LockDemo()\n"
  },
  {
    "path": "Chapter 09/9.03_threading_with queue.py",
    "content": "\"\"\"\nCode illustration: 9.03\n    Threading with Queue Simple Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport queue\nimport threading\n\n\nclass Consumer(threading.Thread):\n\n    def __init__(self, queue):\n        threading.Thread.__init__(self)\n        self.queue = queue\n\n    def run(self):\n        while True:\n            job = self.queue.get()\n            self.do_task(job)\n\n    def do_task(self, task):\n        print ('doing task{}'.format(task))\n        self.queue.task_done()\n\n\ndef producer(tasks):\n    my_queque = queue.Queue()\n    # populate queue with tasks\n    for task in tasks:\n        my_queque.put(task)\n    # create 6 threads and pass the queue as its argument\n    for i in range(6):\n        my_thread = Consumer(my_queque)\n        my_thread.daemon = True\n        my_thread.start()\n\n    # wait for the queue to finish\n    my_queque.join()\n    print ('all tasks completed')\n\nif __name__ == \"__main__\":\n    tasks = 'A B C D E F'.split()\n    producer(tasks)\n"
  },
  {
    "path": "Chapter 09/9.04_game_of_ snake.py",
    "content": "\"\"\"\nCode illustration: 9.04\n    Game of Snake\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport threading\nimport queue\nimport random\nimport time\nfrom tkinter import Tk, Canvas, Button\n\n\nclass View(Tk):\n\n    def __init__(self, queue):\n        Tk.__init__(self)\n        self.queue = queue\n        self.create_gui()\n        self.queue_handler()\n\n    def create_gui(self):\n        self.canvas = Canvas(self, width=495, height=305, bg='#FF75A0')\n        self.canvas.pack()\n        self.snake = self.canvas.create_line(\n            (0, 0), (0, 0), fill='#FFCC4C', width=10)\n        self.food = self.canvas.create_rectangle(\n            0, 0, 0, 0, fill='#FFCC4C', outline='#FFCC4C')\n        self.points_earned = self.canvas.create_text(\n            455, 15, fill='white', text='Score: 0')\n\n    def queue_handler(self):\n        try:\n            while True:\n                task = self.queue.get_nowait()\n                if 'game_over' in task:\n                    self.game_over()\n                elif 'move' in task:\n                    points = [x for point in task['move'] for x in point]\n                    self.canvas.coords(self.snake, *points)\n                elif 'food' in task:\n                    self.canvas.coords(self.food, *task['food'])\n                elif 'points_earned' in task:\n                    self.canvas.itemconfigure(\n                        self.points_earned, text='Score: {}'.format(task['points_earned']))\n                self.queue.task_done()\n        except queue.Empty:\n            self.after(100, self.queue_handler)\n\n    def game_over(self):\n        self.canvas.create_text(200, 150, fill='white', text='Game Over')\n        quit_button = Button(self, text='Quit', command=self.destroy)\n        self.canvas.create_window(200, 180, anchor='nw', window=quit_button)\n\n\nclass Food:\n\n    def __init__(self, queue):\n        self.queue = queue\n        self.generate_food()\n\n    def generate_food(self):\n        x = random.randrange(5, 480, 10)\n        y = random.randrange(5, 295, 10)\n        self.position = (x, y)\n        rectangle_position = (x - 5, y - 5, x + 5, y + 5)\n        self.queue.put({'food': rectangle_position})\n\n\nclass Snake(threading.Thread):\n    is_game_over = False\n\n    def __init__(self, queue):\n        threading.Thread.__init__(self)\n        self.queue = queue\n        self.daemon = True\n        self.points_earned = 0\n        self.snake_points = [\n            (495, 55), (485, 55), (475, 55), (465, 55), (455, 55)]\n        self.food = Food(queue)\n        self.direction = 'Left'\n        self.start()\n\n    def run(self):\n        while not self.is_game_over:\n            self.queue.put({'move': self.snake_points})\n            time.sleep(0.1)\n            self.move()\n\n    def on_keypress(self, e):\n        self.direction = e.keysym\n\n    def move(self):\n        new_snake_point = self.calculate_new_coordinates()\n        if self.food.position == new_snake_point:\n            self.points_earned += 1\n            self.queue.put({'points_earned': self.points_earned})\n            self.food.generate_food()\n        else:\n            self.snake_points.pop(0)\n        self.check_game_over(new_snake_point)\n        self.snake_points.append(new_snake_point)\n\n    def calculate_new_coordinates(self):\n        last_x, last_y = self.snake_points[-1]\n        if self.direction == 'Up':\n            new_snake_point = (last_x, last_y - 10)\n        elif self.direction == 'Down':\n            new_snake_point = (last_x, last_y + 10)\n        elif self.direction == 'Left':\n            new_snake_point = (last_x - 10, last_y)\n        elif self.direction == 'Right':\n            new_snake_point = (last_x + 10, last_y)\n        return new_snake_point\n\n    def check_game_over(self, snake_point):\n        x, y = snake_point\n        if not -5 < x < 505 or not -5 < y < 315 or snake_point in self.snake_points:\n            self.is_game_over = True\n            self.queue.put({'game_over': True})\n\n\ndef main():\n    q = queue.Queue()\n    gui = View(q)\n    snake = Snake(q)\n    for key in (\"Left\", \"Right\", \"Up\", \"Down\"):\n        gui.bind(\"<Key-{}>\".format(key), snake.on_keypress)\n    gui.mainloop()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "Chapter 09/9.05_urllib_demo.py",
    "content": "\"\"\"\nCode illustration: 9.05\n    urllib demo\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport urllib.request\nwith urllib.request.urlopen('http://www.packtpub.com/') as f:\n    print(f.read())\n"
  },
  {
    "path": "Chapter 09/9.06_weather_ reporter.py",
    "content": "\"\"\"\nCode illustration: 9.06\n    Weather reporter\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport sys\nimport json\nimport datetime\nfrom tkinter import Tk, Canvas, Entry, Button, Frame, Label, StringVar, ALL\nfrom tkinter import ttk\nfrom tkinter import messagebox\nimport urllib.request\nimport urllib.parse\n\n\nclass WeatherReporter:\n\n    weather_data = None\n    APIKEY = 'ENTER_YOUR_API_KEY_HERE'\n\n    def __init__(self, root):\n        self.root = root\n        self.create_top_frame()\n        self.create_weather_display_frame()\n\n    def create_top_frame(self):\n        frame = Frame(self.root)\n        frame.pack(side=\"top\")\n        Label(frame, text='Enter Location').pack(side=\"left\")\n        self.location = StringVar()\n        Entry(frame, textvariable=self.location).pack(side=\"left\")\n        ttk.Button(frame, text='Go', command=self.on_show_weather_button_clicked).pack(\n            side=\"left\")\n\n    def create_weather_display_frame(self):\n        self.canvas = Canvas(\n            self.root, height='425', width='340', background='black')\n        self.canvas.create_rectangle(10, 10, 330, 415, fill='#F6AF06')\n        self.canvas.pack(side=\"bottom\")\n\n    def on_show_weather_button_clicked(self):\n        if not self.location.get():\n            return\n        self.clear_canvas()\n        self.get_weather_data()\n        self.format_data()\n        self.display_data()\n\n    def get_weather_data(self):\n        self.weather_data = self.get_data_from_url()\n        self.weather_data = self.json_to_dict(self.weather_data)\n\n    def clear_canvas(self):\n        self.canvas.delete(ALL)\n        self.canvas.create_rectangle(10, 10, 330, 415, fill='#F6AF06')\n\n    def format_data(self):\n        data = self.weather_data\n        self.name = data['name']\n        self.latitude = self.str2num(data['lat'], 3)\n        self.longitude = self.str2num(data['lon'], 3)\n        self.country = data['country']\n        self.time_now = self.time_stamp_to_data(data['dt'])\n        self.description = data['description']\n        self.icon_name = \"weatherimages/{}.png\".format(data['icon'].lower())\n        self.clouds = data['all'] + ' %'\n        self.sunrise_time = self.time_stamp_to_time(data['sunrise'])\n        self.sunset_time = self.time_stamp_to_time(data['sunset'])\n        self.temp_now_in_celcius = self.str2num(\n            self.kelvin_to_celsius(float(data['temp'])), 2) + u' \\u2103'\n        self.temp_now_in_fahrenheit = self.str2num(\n            self.kelvin_to_fahrenheit(float(data['temp'])), 2) + u' \\u2109'\n        self.temp_min_in_celcius = self.str2num(\n            self.kelvin_to_celsius(float(data['temp_min'])), 2) + u' \\u2103'\n        self.temp_max_in_celcius = self.str2num(\n            self.kelvin_to_celsius(float(data['temp_max'])), 2) + u' \\u2103'\n\n    def kelvin_to_celsius(self, k):\n        return k - 273.15\n\n    def kelvin_to_fahrenheit(self, k):\n        return (k * 9 / 5 - 459.67)\n\n    def str2num(self, string, precision):\n        return \"%0.*f\" % (precision, float(string))\n\n    def display_data(self):\n        if not self.weather_data:\n            messagebox.showerror(\n                'Name not found', 'Unable to fetch record - Name not found')\n            return\n        data = self.weather_data\n        opts = {'fill': 'white', 'font': 'Helvetica 12'}\n        self.canvas.create_text(52, 30, text=self.name, **opts)\n        self.canvas.create_text(\n            245, 35, text='Latitude    :' + self.latitude, **opts)\n        self.canvas.create_text(\n            245, 53, text='Longitude: ' + self.longitude, **opts)\n        self.canvas.create_text(\n            55, 50, text='Country : ' + self.country, **opts)\n        self.canvas.create_text(155, 80, text=self.time_now, **opts)\n        self.canvas.create_text(85, 105, text='NOW', **opts)\n        self.img = PhotoImage(file=self.icon_name)\n        self.canvas.create_image(140, 105, image=self.img)\n        self.canvas.create_text(240, 105, text=self.description, **opts)\n        self.canvas.create_text(85, 155, text='Temperature', **opts)\n        self.canvas.create_text(\n            87, 175, text=self.temp_min_in_celcius + ' ~ ' + self.temp_max_in_celcius, **opts)\n        self.canvas.create_text(\n            225, 140, text=self.temp_now_in_celcius, **opts)\n        self.canvas.create_text(\n            225, 180, text=self.temp_now_in_fahrenheit, **opts)\n        self.canvas.create_text(95, 215, text='Relative Humidity', **opts)\n        self.canvas.create_text(198, 215, text=data['humidity'] + ' %', **opts)\n        self.canvas.create_text(77, 235, text='Wind Speed', **opts)\n        self.canvas.create_text(205, 235, text=data['speed'] + ' m/s ', **opts)\n        self.canvas.create_text(80, 255, text='Wind Degree', **opts)\n        self.canvas.create_text(\n            223, 255, text=data['deg'] + ' degrees', **opts)\n        self.canvas.create_text(80, 275, text='Pressure(at.)', **opts)\n        self.canvas.create_text(\n            225, 275, text=data['pressure'] + ' millibars', **opts)\n        if '3h' in data:\n            self.canvas.create_text(83, 293, text='Rain (Last 3h)', **opts)\n            self.canvas.create_text(\n                200, 293, text=data['3h'] + ' mm', **opts)  # rain\n        self.canvas.create_text(58, 310, text='Clouds', **opts)\n        self.canvas.create_text(200, 310, text=self.clouds, **opts)  # clouds\n        self.canvas.create_text(60, 328, text='Sunrise', **opts)\n        self.canvas.create_text(200, 328, text=self.sunrise_time, **opts)\n        self.canvas.create_text(59, 343, text='Sunset', **opts)\n        self.canvas.create_text(200, 343, text=self.sunset_time, **opts)\n        self.canvas.create_text(159, 378, text='Powered by:', **opts)\n        self.canvas.create_text(\n            159, 398, text='www.openweathermap.org', **opts)\n\n    def time_stamp_to_time(self, ts):\n        return (datetime.datetime.fromtimestamp(int(ts)).strftime('%H:%M:%S'))\n\n    def time_stamp_to_data(self, ts):\n        return (datetime.datetime.fromtimestamp(int(ts)).strftime('%Y-%m-%d %H:%M:%S'))\n\n    def get_data_from_url(self):\n        try:\n            params = urllib.parse.urlencode(\n                {'q': self.location.get(), 'APPID': self.APIKEY}, encoding=\"utf-8\")\n            api_url = (\n                'http://api.openweathermap.org/data/2.5/weather?{}'\n                .format(params)\n            )\n            with urllib.request.urlopen(api_url) as f:\n                json_data = f.read()\n                return json_data\n        except IOError as e:\n            messagebox.showerror(\n                'Unable to connect', 'Unable to connect %s' % e)\n            sys.exit(1)\n\n    def json_to_dict(self, json_data):\n        decoder = json.JSONDecoder()\n        decoded_json_data = decoder.decode(json_data.decode(\"utf-8\"))\n        flattened_dict = {}\n        for key, value in decoded_json_data.items():\n            if key == 'weather':\n                for ke, va in value[0].items():\n                    flattened_dict[str(ke)] = str(va).upper()\n                continue\n            try:\n                for k, v in value.items():\n                    flattened_dict[str(k)] = str(v).upper()\n            except:\n                flattened_dict[str(key)] = str(value).upper()\n        return flattened_dict\n\n\ndef main():\n    root = Tk()\n    WeatherReporter(root)\n    root.mainloop()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "Chapter 09/9.07_socket_demo.py",
    "content": "\"\"\"\nCode illustration: 7.08\n    Socket Programming Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport socket\nimport sys\n\ntry:\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\nexcept socket.error:\n    print( 'Failed to create socket')\n    sys.exit()\nprint ('Socket Created')\nhost = 'effbot.org'\nport = 80\ntry:\n    ip = socket.gethostbyname( host )\n\nexcept socket.gaierror:\n    print('Could not resolve Hostname')\n    sys.exit()\n\n#Connect to remote server\ns.connect((ip , port))\nprint ('Socket Connected to ', host, ' on ip ', ip)\n#Send some data to remote server\nmessage = \"GET / HTTP/1.1 \\r\\nHost:\" + host + \"\\r\\n\\r\\nAccept: text/html\\r\\n\\r\\n\"\ntry :\n    #send the message\n    s.sendall(message.encode('utf-8'))\nexcept socket.error:\n    print('Send failed')\n    sys.exit()\n\nprint('Message send successfully')\n#Now receive data\nreceived_message = s.recv(4098)\nprint (received_message )\n"
  },
  {
    "path": "Chapter 09/9.08_port_scanner.py",
    "content": "\"\"\"\nCode illustration: 7.09\n    Port Scanner\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport socket\nfrom tkinter import Tk, Label, Entry, Button, Frame, Scrollbar, W, EW, E, Text, \\\n    DISABLED, Y, BOTH, NORMAL, END\nfrom threading import Thread\n\n\nclass PortScanner():\n\n    stop = False\n    url = \"google.com\"\n    start_port = 70\n    end_port = 85\n\n    def __init__(self, root):\n        self.root = root\n        self.create_gui()\n\n    def on_scan_button_clicked(self):\n        self.empty_console()\n        self.scan_in_a_new_thread()\n\n    def empty_console(self):\n        self.console_text.config(state=NORMAL)\n        self.console_text.delete(\"1.0\", END)\n        self.console_text.config(state=DISABLED)\n\n    def scan_in_a_new_thread(self):\n        url = self.host_entry.get()\n        start_port = int(self.start_port_entry.get())\n        end_port = int(self.end_port_entry.get())\n        thread = Thread(target=self.start_scan,\n                        args=(url, start_port, end_port))\n        thread.start()\n\n    def start_scan(self, url, start_port, end_port):\n        for port in range(start_port, end_port + 1):\n            if not self.stop:\n                self.output_to_console(\"Scanning port {}\".format(port))\n                if self.is_port_open(url, port):\n                    self.output_to_console(\" -- Port {} open \\n\".format(port))\n                else:\n                    self.output_to_console(\"-- Port {} closed \\n\".format(port))\n\n    def is_port_open(self, url, port):\n        try:\n            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            s.settimeout(1)\n            s.connect((socket.gethostbyname(url), port))\n            s.close()\n            return True\n        except:\n            return False\n\n    def on_stop_button_clicked(self):\n        self.stop = True\n\n    def output_to_console(self, new_text):\n        self.console_text.config(state=NORMAL)\n        self.console_text.insert(END, new_text)\n        self.console_text.see(END)\n        self.console_text.config(state=DISABLED)\n\n    def create_gui(self):\n        Label(self.root, text='Host :').grid(row=\"1\", column=\"1\", sticky=W)\n        self.host_entry = Entry(self.root)\n        self.host_entry.insert(0, self.url)\n        self.host_entry.grid(row=\"1\", column=\"2\", sticky=EW)\n        Label(self.root, text='Start Port :').grid(\n            row=\"2\", column=\"1\", sticky=W)\n        self.start_port_entry = Entry(self.root)\n        self.start_port_entry.insert(0, self.start_port)\n        self.start_port_entry.grid(row=\"2\", column=\"2\", sticky=EW)\n        Label(self.root, text='End Port :').grid(row=\"3\", column=\"1\", sticky=W)\n        self.end_port_entry = Entry(self.root)\n        self.end_port_entry.insert(0, self.end_port)\n        self.end_port_entry.grid(row=\"3\", column=\"2\", sticky=EW)\n        Button(self.root, text='Scan', command=self.on_scan_button_clicked).grid(\n            row=\"4\", column=\"2\", sticky=E)\n        Button(self.root, text='Stop', command=self.on_stop_button_clicked).grid(\n            row=\"4\", column=\"2\", sticky=W)\n        Label(self.root, text='Scan Result :').grid(\n            row=\"5\", column=\"1\", sticky=W)\n        console_frame = Frame(self.root)\n        console_frame.grid(row=\"6\", column=\"1\", columnspan=\"2\")\n        self.console_text = Text(\n            console_frame, fg=\"green\", bg=\"black\", state=DISABLED)\n        scrollbar = Scrollbar(console_frame, command=self.console_text.yview)\n        scrollbar.pack(side=\"right\", fill=Y)\n        self.console_text.pack(expand=1, fill=BOTH)\n        self.console_text['yscrollcommand'] = scrollbar.set\n\nif __name__ == '__main__':\n    root = Tk()\n    PortScanner(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 09/9.09_chat_server.py",
    "content": "\"\"\"\nCode illustration: 9.09\n    Chat server\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport socket\nimport threading\n\n\nclass ChatServer:\n\n    clients_list = []\n\n    last_received_message = \"\"\n\n    def __init__(self):\n        self.create_listening_server()\n\n    def create_listening_server(self):\n        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        local_ip = '127.0.0.1'\n        local_port = 10319\n        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n        self.server_socket.bind((local_ip, local_port))\n        print(\"Listening for incoming messages..\")\n        self.server_socket.listen(5)\n        self.receive_messages_in_a_new_thread()\n\n    def receive_messages(self, so):\n        while True:\n            incoming_buffer = so.recv(256)\n            if not incoming_buffer:\n                break\n            self.last_received_message = incoming_buffer.decode('utf-8')\n            self.broadcast_to_all_clients(so)\n        so.close()\n\n    def broadcast_to_all_clients(self, senders_socket):\n        for client in self.clients_list:\n            socket, (ip, port) = client\n            if socket is not senders_socket:\n                socket.sendall(self.last_received_message.encode('utf-8'))\n\n    def receive_messages_in_a_new_thread(self):\n        while 1:\n            client = so, (ip, port) = self.server_socket.accept()\n            self.add_to_clients_list(client)\n            print ('Connected to ', ip, ':', str(port))\n            t = threading.Thread(target=self.receive_messages, args=(so,))\n            t.start()\n\n    def add_to_clients_list(self, client):\n        if client not in self.clients_list:\n            self.clients_list.append(client)\n\nif __name__ == \"__main__\":\n    ChatServer()\n"
  },
  {
    "path": "Chapter 09/9.10_chat_client.py",
    "content": "'''\nCode illustration: 9.10\n    Chat Client\n\n    *** NOTE  Run atleast 2 instances of this program to see chat in action***\n\nTkinter GUI Application Development Blueprints\n'''\n\nfrom tkinter import Tk, Frame, Scrollbar, Label, END, Entry, Text, VERTICAL\nimport socket\nimport threading\nfrom tkinter import messagebox\n\n\nclass ChatClient:\n\n    client_socket = None\n    last_received_message = None\n\n    def __init__(self, root):\n        self.root = root\n        self.initialize_socket()\n        self.initialize_gui()\n        self.listen_for_incoming_messages_in_a_thread()\n\n    def initialize_socket(self):\n        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        remote_ip = '127.0.0.1'\n        remote_port = 10319\n        self.client_socket.connect((remote_ip, remote_port))\n\n    def initialize_gui(self):\n        self.display_name_section()\n        self.display_chat_transcript()\n        self.display_chat_entrybox()\n\n    def listen_for_incoming_messages_in_a_thread(self):\n        t = threading.Thread(\n            target=self.recieve_message_from_server, args=(self.client_socket,))\n        t.start()\n\n    def recieve_message_from_server(self, so):\n        while True:\n            buf = so.recv(256)\n            if not buf:\n                break\n            self.chat_transcript_area.insert('end', buf.decode('utf-8') + '\\n')\n            self.chat_transcript_area.yview(END)\n        so.close()\n\n    def display_name_section(self):\n        frame = Frame()\n        Label(frame, text='Enter your name:').pack(side='left')\n        self.name_widget = Entry(frame, width=20)\n        self.name_widget.pack(side='left', anchor='e')\n        frame.pack(side='top', anchor='w')\n\n    def display_chat_transcript(self):\n        frame = Frame()\n        Label(frame, text='Chat Transcript:').pack(side='top', anchor='w')\n        self.chat_transcript_area = Text(frame, width=60, height=20)\n        scrollbar = Scrollbar(\n            frame, command=self.chat_transcript_area.yview, orient=VERTICAL)\n        self.chat_transcript_area.config(yscrollcommand=scrollbar.set)\n        self.chat_transcript_area.bind('<KeyPress>', lambda e: 'break')\n        self.chat_transcript_area.pack(side='left')\n        scrollbar.pack(side='right', fill='y')\n        frame.pack(side='top')\n\n    def display_chat_entrybox(self):\n        frame = Frame()\n        Label(frame, text='Enter chat messages:').pack(side='top', anchor='w')\n        self.enter_text_widget = Text(frame, width=60, height=8)\n        scrollbar = Scrollbar(\n            self.root, command=self.enter_text_widget.yview, orient=VERTICAL)\n        self.enter_text_widget.config(yscrollcommand=scrollbar.set)\n        self.enter_text_widget.pack(side='left')\n        scrollbar.pack(side='right', fill='y')\n        self.enter_text_widget.bind('<Return>', self.on_enter_key_pressed)\n        frame.pack(side='top')\n\n    def on_enter_key_pressed(self, event):\n        if len(self.name_widget.get()) == 0:\n            messagebox.showerror(\n                \"Enter your name\", \"Enter your name to send a message\")\n            return\n        self.send_chat()\n        self.clear_text()\n\n    def clear_text(self):\n        self.enter_text_widget.delete(1.0, 'end')\n\n    def send_chat(self):\n        senders_name = self.name_widget.get().strip() + \":\"\n        data = self.enter_text_widget.get(1.0, 'end').strip()\n        message = (senders_name + data).encode('utf-8')\n        self.chat_transcript_area.insert('end', message.decode('utf-8') + '\\n')\n        self.chat_transcript_area.yview(END)\n        self.client_socket.send(message)\n        self.enter_text_widget.delete(1.0, 'end')\n        return 'break'\n\nif __name__ == '__main__':\n    root = Tk()\n    ChatClient(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 09/9.11_phonebook.py",
    "content": "'''\nCode illustration: 9.11\n    Phonebook Application\nTkinter GUI Application Development Blueprints\n'''\nfrom tkinter import Tk, Button, PhotoImage, Label, LabelFrame, W, E, Entry, END, \\\n            Toplevel\nfrom tkinter import ttk\nimport sqlite3\n\n\nclass PhoneBook:\n\n    db_filename = 'phonebook.db'\n\n    def __init__(self, root):\n        self.root = root\n        self.create_gui()\n\n    def execute_db_query(self, query, parameters=()):\n        with sqlite3.connect(self.db_filename) as conn:\n            cursor = conn.cursor()\n            query_result = cursor.execute(query, parameters)\n            conn.commit()\n        return query_result\n\n    def create_gui(self):\n        self.create_left_icon()\n        self.create_label_frame()\n        self.create_message_area()\n        self.create_tree_view()\n        self.create_bottom_buttons()\n        self.view_records()\n\n    def create_left_icon(self):\n        photo = PhotoImage(file='icons/phonebookicon.gif')\n        label = Label(image=photo)\n        label.image = photo\n        label.grid(row=0, column=0)\n\n    def create_label_frame(self):\n        labelframe = LabelFrame(self.root, text='Create New Record')\n        labelframe.grid(row=0, column=1, padx=8, pady=8, sticky='ew')\n        Label(labelframe, text='Name:').grid(row=1, column=1, sticky=W, pady=2)\n        self.namefield = Entry(labelframe)\n        self.namefield.grid(row=1, column=2, sticky=W, padx=5, pady=2)\n        Label(labelframe, text='Contact Number:').grid(\n            row=2, column=1, sticky=W,  pady=2)\n        self.numfield = Entry(labelframe)\n        self.numfield.grid(row=2, column=2, sticky=W, padx=5, pady=2)\n        ttk.Button(labelframe, text='Add Record', command=self.on_add_record_button_clicked).grid(\n            row=3, column=2, sticky=E, padx=5, pady=2)\n\n    def create_message_area(self):\n        self.message = Label(text='', fg='red')\n        self.message.grid(row=3, column=1, sticky=W)\n\n    def create_tree_view(self):\n        self.tree = ttk.Treeview(height=5, columns=2)\n        self.tree.grid(row=4, column=0, columnspan=2)\n        self.tree.heading('#0', text='Name', anchor=W)\n        self.tree.heading(2, text='Phone Number', anchor=W)\n\n    def create_bottom_buttons(self):\n        ttk.Button(text='Delete Selected', command=self.on_delete_selected_button_clicked).grid(\n            row=5, column=0, sticky=W)\n        ttk.Button(text='Modify Selected', command=self.on_modify_selected_button_clicked).grid(\n            row=5, column=1, sticky=W)\n\n    def on_add_record_button_clicked(self):\n        self.add_new_record()\n\n    def on_delete_selected_button_clicked(self):\n        self.message['text'] = ''\n        try:\n            self.tree.item(self.tree.selection())['values'][0]\n        except IndexError as e:\n            self.message['text'] = 'No item selected to delete'\n            return\n        self.delete_record()\n\n    def on_modify_selected_button_clicked(self):\n        self.message['text'] = ''\n        try:\n            self.tree.item(self.tree.selection())['values'][0]\n        except IndexError as e:\n            self.message['text'] = 'No item selected to modify'\n            return\n        self.open_modify_window()\n\n    def add_new_record(self):\n        if self.new_records_validated():\n            query = 'INSERT INTO contacts VALUES(NULL,?, ?)'\n            parameters = (self.namefield.get(), self.numfield.get())\n            self.execute_db_query(query, parameters)\n            self.message['text'] = 'Phone record of {} added'.format(\n                self.namefield.get())\n            self.namefield.delete(0, END)\n            self.numfield.delete(0, END)\n        else:\n            self.message['text'] = 'name and phone number cannot be blank'\n        self.view_records()\n\n    def new_records_validated(self):\n        return len(self.namefield.get()) != 0 and len(self.numfield.get()) != 0\n\n    def view_records(self):\n        items = self.tree.get_children()\n        for item in items:\n            self.tree.delete(item)\n        query = 'SELECT * FROM contacts ORDER BY name desc'\n        phone_book_entries = self.execute_db_query(query)\n        for row in phone_book_entries:\n            self.tree.insert('', 0, text=row[1], values=row[2])\n\n    def delete_record(self):\n        self.message['text'] = ''\n        name = self.tree.item(self.tree.selection())['text']\n        query = 'DELETE FROM contacts WHERE name = ?'\n        self.execute_db_query(query, (name,))\n        self.message['text'] = 'Phone record for {} deleted'.format(name)\n        self.view_records()\n\n    def open_modify_window(self):\n        name = self.tree.item(self.tree.selection())['text']\n        old_phone_number = self.tree.item(self.tree.selection())['values'][0]\n        self.transient = Toplevel()\n        Label(self.transient, text='Name:').grid(row=0, column=1)\n        Entry(self.transient, textvariable=StringVar(\n            self.transient, value=name), state='readonly').grid(row=0, column=2)\n        Label(self.transient, text='Old Phone Number:').grid(row=1, column=1)\n        Entry(self.transient, textvariable=StringVar(\n            self.transient, value=old_phone_number), state='readonly').grid(row=1, column=2)\n        Label(self.transient, text='New Phone Number:').grid(\n            row=2, column=1)\n        new_phone_number_entry_widget = Entry(self.transient)\n        new_phone_number_entry_widget.grid(row=2, column=2)\n        Button(self.transient, text='Update Record', command=lambda: self.update_record(\n            new_phone_number_entry_widget.get(), old_phone_number, name)).grid(row=3, column=2, sticky=E)\n        self.transient.mainloop()\n\n    def update_record(self, newphone, old_phone_number, name):\n        query = 'UPDATE contacts SET contactnumber=? WHERE contactnumber=? AND name=?'\n        parameters = (newphone, old_phone_number, name)\n        self.execute_db_query(query, parameters)\n        self.transient.destroy()\n        self.message['text'] = 'Phone number of {} modified'.format(name)\n        self.view_records()\n\nif __name__ == '__main__':\n    root = Tk()\n    application = PhoneBook(root)\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 09/9.12_async_demo.py",
    "content": "from tkinter import Tk, Button\nimport asyncio\nimport threading\nimport random\n\n\ndef asyncio_thread(event_loop):\n  print('The tasks of fetching multiple URLs begins')\n  event_loop.run_until_complete(simulate_fetch_all_urls())\n\n\ndef execute_tasks_in_a_new_thread(event_loop):\n  \"\"\" Button-Event-Handler starting the asyncio part. \"\"\"\n  threading.Thread(target=asyncio_thread, args=(event_loop, )).start()\n\n\nasync def simulate_fetch_one_url(url):\n  \"\"\" We simulate fetching of URL by sleeping for a random time \"\"\"\n  seconds = random.randint(1, 8)\n  await asyncio.sleep(seconds)\n  return 'url: {}\\t fetched in {} seconds'.format(url, seconds)\n\n\nasync def simulate_fetch_all_urls():\n  \"\"\" Creating and starting 10 i/o bound tasks. \"\"\"\n  all_tasks = [simulate_fetch_one_url(url) for url in range(10)]\n  completed, pending = await asyncio.wait(all_tasks)\n  results = [task.result() for task in completed]\n  print('\\n'.join(results))\n\n\ndef check_if_button_freezed():\n  print(\n      'This button is responsive even when a list of i/o tasks are in progress'\n  )\n\n\ndef main(event_loop):\n  root = Tk()\n  Button(\n      master=root,\n      text='Fetch All URLs',\n      command=lambda: execute_tasks_in_a_new_thread(event_loop)).pack()\n  Button(\n      master=root,\n      text='This will not Freeze',\n      command=check_if_button_freezed).pack()\n  root.mainloop()\n\n\nif __name__ == '__main__':\n  event_loop = asyncio.get_event_loop()\n  main(event_loop)\n"
  },
  {
    "path": "Chapter 09/9.13.arduino_sketch.ino",
    "content": "const int triggerPin = 8;\nconst int echoBackPin = 7;\n\nvoid setup() {\n Serial.begin(9600);\n pinMode(triggerPin, OUTPUT);\n pinMode(echoBackPin, INPUT);\n}\n\nvoid loop() {\n  long duration, distanceIncm;\n  // trigger ultrasound ping\n  digitalWrite(triggerPin, LOW);\n  delayMicroseconds(2);\n  digitalWrite(triggerPin, HIGH);\n  delayMicroseconds(5);\n  digitalWrite(triggerPin, LOW);\n  // receive input from the sensor\n  duration = pulseIn(echoBackPin, HIGH);\n\n  //calculate distance\n  distanceIncm = duration / 29 / 2;\n\n  // send data over serial port\n  Serial.print('distance in cm is :');\n  Serial.print(distanceIncm);\n  Serial.println();\n  delay(100);\n}\n"
  },
  {
    "path": "Chapter 09/9.14_read_from_serial_port.py",
    "content": "from tkinter import Tk, Label\nimport serial\n\nser = serial.Serial()\nser.port = \"/dev/ttyUSB0\"\nser.baudrate = 9600\ntry:\n  ser.open()\nexcept serial.SerialException:\n  print(\"Could not open serial port: \" + ser.port)\n\nroot = Tk()\nroot.geometry('{}x{}'.format(200, 100))\nlabel = Label(root, font=(\"Helvetica\", 26))\nlabel.pack(fill='both')\n\n\ndef read_serial_data():\n  if ser.isOpen():\n    try:\n      response = ser.readline()\n      print(response)\n      label.config(\n          text='Distance : \\n' + response.decode(\"utf-8\").rstrip() + ' cm')\n    except serial.SerialException:\n      print(\"no message received\")\n  root.after(100, read_serial_data)\n\n\nread_serial_data()\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 09/readme.txt",
    "content": "====================================================================\nCode Readme\nTkinter GUI Application Development Blueprints\nChapter 9: Multiple Fun Projects\n====================================================================\nCode Description:\nCode 9.01:      Race condition demo\nCode 9.02:      Avoiding race condition with locks\nCode 9.03:      Threading with Queue Simple Demo\nCode 9.04:      Snake Game\nCode 9.05:      Fetching web content with urllib -  demo\nCode 9.06:      Weather Reporter\nCode 9.07:      Socket Demo\nCode 9.08:      Port Scanner\nCode 9.09:      Chat Server\nCode 9.10:      Chat Client\nCode 9.11:      Phone Book\nCode 9.12:      Asyncio Demo\nCode 9.13:      Arduino Skecth.ino\nCode 9.14:      Reading from Serial Port\n\nDirectory 'icons' contains all images used in the programs\nDirectory 'weatherimages' contains all images used by Weather Reporter program\nphonebook.db - the sqlite database accompanying code 9.11 Phone Book\n"
  },
  {
    "path": "Chapter 10/10.01_trace_variable.py",
    "content": "\"\"\"\nCode illustration: 10.01\nTkinter Trace Variable Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Label, Entry, StringVar\nroot = Tk()\n\nmy_variable = StringVar()\n\n\ndef trace_when_my_variable_written(var, indx, mode):\n    print (\"Traced variable {}\".format(my_variable.get()))\n\nmy_variable.trace_variable(\"w\", trace_when_my_variable_written)\n\n\nLabel(root, textvariable=my_variable).pack(padx=5, pady=5)\nEntry(root, textvariable=my_variable).pack(padx=5, pady=5)\n\n\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.02_widget_traversal.py",
    "content": "\"\"\"\nCode illustration: 10.02\nWidget Traversal\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Text, NSEW, Frame,Entry, Button, Radiobutton, Scale, X,\\\n        Label, END, HORIZONTAL\n\n\nclass TraversalDemo:\n\n    def __init__(self, root):\n        frame = Frame(\n            root, takefocus=1, highlightthickness=2, highlightcolor='red')\n        entry = Entry(frame)\n        entry.pack(fill=X, expand=1)\n        entry.insert(END, 'Tabs jumps to next widget')\n        frame.pack(fill=X, expand=1)\n        frame.focus_force()\n\n        frame = Frame(root, highlightthickness=2,  highlightcolor='red')\n        for button_text, column_number in (('A', 1), ('B', 2), ('C', 3), ('D', 4)):\n            Button(frame, text=button_text, highlightthickness=2).grid(\n                padx=10, pady=6, row=0, column=column_number, sticky=NSEW)\n        frame.pack(fill=X, expand=1)\n\n        frame = Frame(\n            root, takefocus=1, highlightthickness=2,  highlightcolor='red')\n        for i in range(4):\n            Radiobutton(frame, text=i, value=i).grid(\n                padx=10, pady=6, row=1, column=i, sticky=NSEW)\n        frame.pack(fill=X, expand=1)\n\n        frame = Frame(\n            root, takefocus=1, highlightthickness=2,  highlightcolor='red')\n        text = Text(frame, height=4)\n        text.insert(\n            END, 'Tabs does not jump to the next widget from inside the Text widget.\\nUse Ctrl + Tab to traverse')\n        text.grid(row=0, column=1, columnspan=3)\n        frame.pack(fill=X, expand=1)\n\n        frame = Frame(root, takefocus=0)\n        Label(frame, text='use left/right key').pack()\n        Scale(frame, from_=0.0, to=100.0, orient=HORIZONTAL, takefocus=1,\n              highlightthickness=2,  highlightcolor='red').pack()\n        frame.pack(fill=X, expand=1)\n\n\nroot = Tk()\napp = TraversalDemo(root)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.03_validation_mode_demo.py",
    "content": "\"\"\"\nCode illustration: 10.03\nValidation Modes Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\n\nclass ValidateModeDemo():\n\n    def __init__(self):\n        self.root = tk.Tk()\n        vcmd = (self.root.register(self.validate_data), '%V')\n\n        # validate = none mode - will not call validate_data method ever.\n        tk.Label(text='None').pack()\n        tk.Entry(self.root, validate=\"none\", validatecommand=vcmd).pack()\n\n        # validate = focus mode - will call validate method_data on focusin and\n        # focusout\n        tk.Label(text='Focus').pack()\n        tk.Entry(self.root, validate=\"focus\", validatecommand=vcmd).pack()\n\n        # validate = focusin mode - - will call validate_data method on focusin\n        tk.Label(text='Focusin').pack()\n        tk.Entry(self.root, validate=\"focusin\", validatecommand=vcmd).pack()\n\n        # validate = focusout mode - will call validate_data method on focusout\n        tk.Label(text='Focus Out').pack()\n        tk.Entry(self.root, validate=\"focusout\", validatecommand=vcmd).pack()\n\n        # validate = Key mode - will call validate_data method only when you\n        # type something or edit the entry\n        tk.Label(text='key').pack()\n        tk.Entry(self.root, validate=\"key\", validatecommand=vcmd).pack()\n\n        # validate = all mode - will call validate_data method on focus and key\n        # events\n        tk.Label(text='all').pack()\n        tk.Entry(self.root, validate=\"all\", validatecommand=vcmd).pack()\n\n        self.root.mainloop()\n\n    def validate_data(self, v):\n        print ('validate_data called via mode : {}'.format(v))\n        # this is where you will validate your data and return True or False\n        # depending on wether the data is valid or not\n        # for now let us just return True for all cases.\n        return True\n\napp = ValidateModeDemo()\n"
  },
  {
    "path": "Chapter 10/10.04_percent _substitutions _demo.py",
    "content": "\"\"\"\nCode illustration: 10.04\n\nDemonstration of percent substitutions in data validation\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\n\nclass PercentSubstitutionsDemo():\n\n    def __init__(self):\n        self.root = tk.Tk()\n        tk.Label(text='Type Something Below').pack()\n        vcmd = (self.root.register(self.validate), '%d',\n                '%i', '%P', '%s', '%S', '%v', '%V', '%W')\n        tk.Entry(self.root, validate=\"all\", validatecommand=vcmd).pack()\n        self.root.mainloop()\n\n    def validate(self, d, i, P, s, S, v, V, W):\n        print(\"Following Data is received for running our validation checks:\")\n        print(\"d:{}\".format(d))\n        print(\"i:{}\".format(i))\n        print(\"P:{}\".format(P))\n        print(\"s:{}\".format(s))\n        print(\"S:{}\".format(S))\n        print(\"v:{}\".format(v))\n        print(\"V:{}\".format(V))\n        print(\"W:{}\".format(W))\n        # returning true for now\n        # in actual validation you return true if data is valid else return\n        # false\n        return True\n\napp = PercentSubstitutionsDemo()\n"
  },
  {
    "path": "Chapter 10/10.05_key_validation.py",
    "content": "\"\"\"\nCode illustration: 10.05\nvalidate='key' demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nimport tkinter as tk\n\n\nclass KeyValidationDemo():\n\n    def __init__(self):\n        root = tk.Tk()\n        tk.Label(\n            root, text='Enter your name / only alpabets & space allowed').pack()\n        vcmd = (root.register(self.validate_data), '%S')\n        invcmd = (root.register(self.invalid_name), '%S')\n        tk.Entry(root, validate=\"key\", validatecommand=vcmd,\n                 invalidcommand=invcmd).pack(pady=5, padx=5)\n        self.error_message = tk.Label(root, text='', fg='red')\n        self.error_message.pack()\n        root.mainloop()\n\n    def validate_data(self, S):\n        print(\"S={}\".format(S))\n        self.error_message.config(text='')\n        return (S.isalpha() or S == ' ')\n\n    def invalid_name(self, S):\n        self.error_message.config(\n            text='Invalid character %s \\n name can only have alphabets and spaces' % S)\n\napp = KeyValidationDemo()\n"
  },
  {
    "path": "Chapter 10/10.06_focus_out _validation.py",
    "content": "\"\"\"\nCode illustration: 10.06\nvalidate='focusout' demo\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter as tk\nimport re\n\n\nclass FocusOutValidationDemo():\n\n    def __init__(self):\n        self.master = tk.Tk()\n        self.error_message = tk.Label(text='', fg='red')\n        self.error_message.pack()\n        tk.Label(text='Enter Email Address').pack()\n        vcmd = (self.master.register(self.validate_email), '%P')\n        invcmd = (self.master.register(self.invalid_email), '%P')\n        self.email_entry = tk.Entry(\n            self.master, validate=\"focusout\", validatecommand=vcmd, invalidcommand=invcmd)\n        self.email_entry.pack()\n        tk.Button(self.master, text=\"Login\").pack()\n        tk.mainloop()\n\n    def validate_email(self, P):\n        self.error_message.config(text='')\n        x = re.match(r\"[^@]+@[^@]+\\.[^@]+\", P)\n        return (x != None)\n\n    def invalid_email(self, P):\n        self.error_message.config(text='Invalid Email Address')\n        self.email_entry.focus_set()\n\napp = FocusOutValidationDemo()\n"
  },
  {
    "path": "Chapter 10/10.07_formatting_entry_widget_to_display_date.py",
    "content": "\"\"\"\nCode illustration: 10.07\nFormatting Entry Widget\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Entry, Label, StringVar, INSERT\n\n\nclass FormatEntryWidgetDemo:\n\n    def __init__(self, root):\n        Label(root, text='Date(MM/DD/YYYY)').pack()\n        self.entered_date = StringVar()\n        self.date_entry = Entry(textvariable=self.entered_date)\n        self.date_entry.pack(padx=5, pady=5)\n        self.date_entry.focus_set()\n        self.slash_positions = [2, 5]\n        root.bind('<Key>', self.format_date_entry_widget)\n\n    def format_date_entry_widget(self, event):\n        entry_list = [c for c in self.entered_date.get() if c != '/']\n        for pos in self.slash_positions:\n            if len(entry_list) > pos:\n                entry_list.insert(pos, '/')\n        self.entered_date.set(''.join(entry_list))\n        # Controlling cursor\n        cursor_position = self.date_entry.index(\n            INSERT)  # current cursor position\n        for pos in self.slash_positions:\n            if cursor_position == (pos + 1):  # if cursor position is on slash\n                cursor_position += 1\n        if event.keysym not in ['BackSpace', 'Right', 'Left', 'Up', 'Down']:\n            self.date_entry.icursor(cursor_position)\n\nroot = Tk()\nFormatEntryWidgetDemo(root)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.08_font_demo.py",
    "content": "\"\"\"\nCode illustration: 10.08\n        font Demo\nTkinter GUI Application Development Blueprints\n\"\"\"\n\nfrom tkinter import Tk, Label, Pack, font\n\nroot = Tk()\nlabel = Label(root, text=\"Humpty Dumpty was pushed\")\nlabel.pack()\ncurrent_font = font.Font(font=label['font'])\nprint ('Actual :', str(current_font.actual()))\nprint ('Family : ', current_font.cget(\"family\"))\nprint ('Weight : ', current_font.cget(\"weight\"))\nprint ('Text width of Dumpty : {}'.format(current_font.measure(\"Dumpty\")))\nprint ('Metrics:', str(current_font.metrics()))\ncurrent_font.config(size=14)\nlabel.config(font=current_font)\nprint ('New Actual :', str(current_font.actual()))\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.09_all_fonts_on_a_system.py",
    "content": "\"\"\"\nCode illustration: 10.09\n        Fetching tuple of all fonts installed on a system\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, font\nroot = Tk()\nall_fonts = font.families()\nprint(all_fonts)\n"
  },
  {
    "path": "Chapter 10/10.10_font_selector.py",
    "content": "\"\"\"\nCode illustration: 10.10\nFont Selector\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, StringVar, Label, Entry, Text, BooleanVar, Checkbutton, \\\n        INSERT, DISABLED, ttk, font\n\n\nclass FontSelectorDemo():\n\n    def __init__(self):\n        self.current_font = font.Font(font=('Times New Roman', 12))\n        self.family = StringVar(value='Times New Roman')\n        self.size = StringVar(value='12')\n        self.weight = StringVar(value=font.NORMAL)\n        self.slant = StringVar(value=font.ROMAN)\n        self.underline = BooleanVar(value=False)\n        self.overstrike = BooleanVar(value=False)\n        self.sample_text = 'The quick brown fox jumps over the lazy dog'\n        self.gui_creator()\n\n    def gui_creator(self):\n        # font family selector combobox\n        Label(text='Font Family').grid(row=0, column=0)\n        font_list = ttk.Combobox(textvariable=self.family)\n        font_list.grid(\n            row=1, column=0, columnspan=2, sticky='nsew', padx=10)\n        font_list.bind('<<ComboboxSelected>>', self.on_value_change)\n        all_fonts = list(font.families())\n        all_fonts.sort()\n        font_list['values'] = all_fonts\n        # Font Sizes\n        Label(text='Font Size').grid(row=0, column=2)\n        sizeList = ttk.Combobox(textvariable=self.size)\n        sizeList.bind('<<ComboboxSelected>>', self.on_value_change)\n        sizeList.grid(\n            row=1, column=2, columnspan=2, sticky='nsew', padx=10)\n        all_sizes = list(range(6, 70))\n        sizeList['values'] = all_sizes\n        # Font Styles\n        Checkbutton(text='bold',  variable=self.weight, command=self.on_value_change,\n                    onvalue='bold', offvalue='normal').grid(row=2, column=0)\n        Checkbutton(text='italic', variable=self.slant, command=self.on_value_change,\n                    onvalue='italic', offvalue='roman').grid(row=2, column=1)\n        Checkbutton(text='underline', variable=self.underline,\n                    command=self.on_value_change, onvalue=True, offvalue=False).grid(row=2, column=2)\n        Checkbutton(text='overstrike', variable=self.overstrike,\n                    command=self.on_value_change,  onvalue=True, offvalue=False).grid(row=2, column=3)\n        self.text = Text()\n        self.text.columnconfigure(1, weight=1)\n        self.text.grid(\n            row=3, column=0, columnspan=10, padx=10, pady=10, sticky='ew')\n        self.text.insert(INSERT, '{}\\n{}'.format(\n            self.sample_text, self.sample_text.upper()), 'fontspecs')\n        self.text.config(state=DISABLED)\n\n    def on_value_change(self, event=None):\n        self.current_font.config(family=self.family.get(),\n                                 size=self.size.get(), weight=self.weight.get(),\n                                 slant=self.slant.get(), underline=self.underline.get(),\n                                 overstrike=self.overstrike.get())\n        self.text.tag_config('fontspecs', font=self.current_font)\n\n\nif __name__ == '__main__':\n    root = Tk()\n    root.resizable(0, 0)\n    font = FontSelectorDemo()\n    root.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.11_reading_from_command_line.py",
    "content": "﻿\"\"\"\nCode illustration: 10.11\n    Reading from the command line\nTkinter GUI Application Development Blueprints\n\"\"\"\nfrom tkinter import Tk, Text, END\nfrom subprocess import Popen, PIPE\nroot = Tk()\ntext = Text(root)\ntext.pack()\n# replace \"ls\" with \"dir\" in the next line on windows platform\nwith Popen([\"ls\"], stdout=PIPE, bufsize=1, universal_newlines=True) as p:\n    for line in p.stdout:\n        text.insert(END, line)\nroot.mainloop()\n"
  },
  {
    "path": "Chapter 10/10.12_tkinter_class_hierarchy.py",
    "content": "\"\"\"\nCode illustration: 10.12\nTkinter Class Hierarchy Inspect\nTkinter GUI Application Development Blueprints\n\"\"\"\nimport tkinter\nimport inspect\n\nprint ('Class Hierarchy for Frame Widget')\nfor i, classname in enumerate(inspect.getmro(tkinter.Frame)):\n    print('\\t{}: {}'.format(i, classname))\n\nprint ('Class Hierarchy for Toplevel')\nfor i, classname in enumerate(inspect.getmro(tkinter.Toplevel)):\n    print ('\\t{}:{}'.format(i, classname))\n\nprint ('Class Hierarchy for Tk')\nfor i, classname in enumerate(inspect.getmro(tkinter.Tk)):\n    print ('\\t{}: {}'.format(i, classname))\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Packt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "\n\n\n# Tkinter GUI Application Development Blueprints - Second Edition\r\nThis is the code repository for [Tkinter GUI Application Development Blueprints - Second Edition](https://www.packtpub.com/application-development/tkinter-gui-application-development-blueprints-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781788837460), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish.\r\n## About the Book\r\nTkinter is the built-in GUI package that comes with standard Python distributions. It is a cross-platform package, which means you build once and deploy everywhere. It is simple to use and intuitive in nature, making it suitable for programmers and non-programmers alike.\r\n\r\nThis book will help you master the art of GUI programming. It delivers the bigger picture of GUI programming by building real-world, productive, and fun applications such as a text editor, drum machine, game of chess, audio player, drawing application, piano tutor, chat application, screen saver, port scanner, and much more. In every project, you will build on the skills acquired in the previous project and gain more expertise. You will learn to write multithreaded programs, network programs, database-driven programs, asyncio based programming and more. You will also get to know the modern best practices involved in writing GUI apps.\r\n## Instructions and Navigation\r\nAll of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02.\r\n\r\nAll chapters have code files placed in their respective folder.\r\n\r\nThe code will look like the following:\r\n```\r\ndef toggle_play_button_state(self):\r\n  if self.now_playing:\r\n    self.play_button.config(state=\"disabled\")\r\n  else:\r\n    self.play_button.config(state=\"normal\")\r\n```\r\n\r\nWe assume an introductory level familiarity with the basic constructs of Python\r\nprogramming language. We use Python version 3.6 with Tkinter 8.6, and it is recommended\r\nto stick to these exact versions to avoid compatibility issues.\r\nThe programs discussed in this book have been developed on the Linux Mint\r\nplatform. However, given the multiplatform abilities of Tkinter, you can easily work along\r\non other platforms such as Windows, Mac OS, and other distributions of Linux. The links to\r\ndownload and install other project-specific modules and software are mentioned in the\r\nrespective chapters.\r\n\r\n## Related Products\r\n* [Tkinter GUI Application Development Projects [Video]](https://www.packtpub.com/application-development/tkinter-gui-application-development-projects-video?utm_source=github&utm_medium=repository&utm_campaign=9781787280151)\r\n\r\n* [Tkinter GUI Application Development Blueprints](https://www.packtpub.com/application-development/tkinter-gui-application-development-blueprints?utm_source=github&utm_medium=repository&utm_campaign=9781785889738)\r\n\r\n* [Tkinter GUI Application Development HOTSHOT](https://www.packtpub.com/application-development/tkinter-gui-application-development-hotshot?utm_source=github&utm_medium=repository&utm_campaign=9781849697941)\r\n\r\n\r\n### Download a free PDF\n\n <i>If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.<br>Simply click on the link to claim your free PDF.</i>\n<p align=\"center\"> <a href=\"https://packt.link/free-ebook/9781788837460\">https://packt.link/free-ebook/9781788837460 </a> </p>"
  }
]