#!/usr/bin/env python ## CURSES BASIC-MAIL GUI # This is the Basic-Mail program, a basic email client written in python # with a curses interface. # # To Run: Go to the Basic-Mail directory and type "python Basic-Mail.py", # without the quotes. # If it doesn't open, make sure that the size of the console window # is at least 80 x 30 pixels. ## ## Filename: draw.py ## # This file contains the various functions used to draw windows. ## ## IMPORTS ## import curses, curses.ascii, curses.panel # Curses imports import traceback, os, sys, select, string # Random imports from variables import * ## Function: Fills the title line for windows def fill_line(window,width,header,letter,color,y): x = 0 while (x < width): window.addch(y,x,letter,curses.color_pair(color)) x += 1 window.addstr(y,(width-len(header))/2,header,curses.color_pair(color)) window.noutrefresh() ## Function: Draws borders for windows def draw_borders(window,width,height): window.vline(0,0,'|',height-1) window.vline(0,width-1,'|',height-1) window.hline(height-1,0,'+',width-1) window.hline(height-1,1,'-',width-1) window.hline(height-1,width-1,'+',1) window.noutrefresh() ## Function: Creates a window bar with options. ## Used for tab and menu bars. def create_bar(window,list,width,space): x = 2 count = 0 draw_borders(window,width,1) for number in list[0]: window.addstr(0,x,number) # If negative, crawls back from the end of the word if list[1][count] < 0: window.addch(0,x+len(list[0][count])+list[1][count],\ list[0][count][list[1][count]],\ curses.color_pair(3)) else: window.addch(0,x+list[1][count],list[0][count][list[1][count]],\ curses.color_pair(3)) # Highlights specified letter x += (len(number)+space) count += 1 window.refresh() ## Function: Highlights the user-selected option. ## Used for both menu and tab selection. def select_bar(window,list,location,height,width,options): ## Selects the user-selected option. # Highlights Text on Bar. x = 2 if list == menu: space = 2 if list == tabs: space = 1 # Finds placement of text. for number in list[0][0:location]: x += len(number) + space # Prints text. if list == menu: window.addstr(0,x,list[0][location],curses.color_pair(2)) elif list == tabs: window.addstr(0,x+1,list[0][location][1:-1],curses.color_pair(2)) # x+1 adjusts for the removed '\'. window.refresh() ## Function: Draws all the unselected menus and tabs to the screen. def draw_screen(active_tab): # Fills Title Line. fill_line(stdscr, 80, program_title,' ',2,0) # Creates the Menu and Tab Bars. create_bar(menu_bar,menu,bar_width,2) # Last number is the space between create_bar(tab_bar,tabs,bar_width,1) # Highlight Active Tab if active_tab == tab1: select_bar(tab_bar,tabs,0,10,10,0) # Highlights first tab elif active_tab == tab2: select_bar(tab_bar,tabs,1,10,10,0) # Highlights first tab elif active_tab == tab3: select_bar(tab_bar,tabs,2,10,10,0) # Highlights first tab elif active_tab == tab4: select_bar(tab_bar,tabs,3,10,10,0) # Highlights first tab elif active_tab == tab5: select_bar(tab_bar,tabs,4,10,10,0) # Highlights first tab ## Function: Draws the inbox window ## It is passed the mail array and the line to be highlighted ## Usage: draw_inbox(mail,10) def draw_inbox(mail,line): # Draw the bar on the bottom num = 0 x = 0 y = 0 inbox_win.hline(y,0,'-',78) for option in inbox_bar[0]: x += ((inbox_bar[1][num]/2)-(len(option)/2)) # Starting point inbox_win.addstr(y,x,option) x += ((inbox_bar[1][num]/2)+(len(option)/2)) num += 1 # Draws the mail y = 1 for list in mail: option_num = 0 x = 1 for option in list[:3]: if list == mail[line]: inbox_win.addstr(y,x,option[0:24],curses.color_pair(3)) else: inbox_win.addstr(y,x,option[0:24]) x += (inbox_bar[1][option_num]-1) if option_num == 1: x -= 1 option_num += 1 x += 2 y += 1 ## Function: Draws the basic layout of the message and compose windows ## Usage: message_1_win = draw_message_win(message_1_win) def draw_message_win(window): window.addstr(1,5,"From:") window.addstr(3,5,"To:") window.addstr(5,5,"Subject:") # Draw message box window.hline(7,7,'-',64) window.hline(25,7,'-',64) window.vline(7,7,'|',18) window.vline(7,70,'|',18) window.addch(7,7,'+') window.addch(7,70,'+') window.addch(25,7,'+') window.addch(25,70,'+') return window ## Function: Draws a specific message onto the message screen ## Usage: message_1_win = draw_message(window,mail,message) def draw_message(window,mail,message): window.addstr(1,11,mail[message][0][:55]) window.addstr(3,9,mail[message][1][:55]) window.addstr(5,14,mail[message][2][:55]) if len(mail[message][0]) > 55: window.addstr(1,66,"...") if len(mail[message][1]) > 55: window.addstr(3,66,"...") if len(mail[message][2]) > 55: window.addstr(5,66,"...") # Writes the message character by character char = 0 x = 8 y = 8 while char < len(mail[message][3]): if x > 69: window.addch(y,x,'\n') y += 1 x = 8 elif mail[message][3][char] == '\n': y += 1 x = 8 char += 1 else: window.addch(y,x,mail[message][3][char]) x += 1 char += 1 return draw_message_win(window) # Redraws borders ## Function: Returns the proper starting point for each field. ## Usage: x_original = x_field(field) def x_field(field): if field == 0: # From: return 11 elif field == 1: # To: return 9 elif field == 2: # Subject: return 14 elif field == 3: return 9 elif field == 4 or field == 5: return 0 ## Function: This ridiculously large chunk of code is the code ## for composing messages. It runs in its own loop, ## so you can't open menus or tabs while its running. ## It's specific to composition, so the general chat ## functionality cannot be reused, which is not very ## good coding practice, but what the hell, eh? ## It just returns the updated mail file. ## Usage: mail = write_message(message_1_win,mail) def write_message(window,mail): window.hline(1,11,'-',60) window.hline(3,9,'-',60) window.hline(5,14,'-',60) window.addstr(26,23,"[Cancel]") window.addstr(26,48,"[Send]") draw_message_win(window) from_field = "" to_field = "" subject_field = "" message_field = "" # Initialize composition variables field = 0 # Field to write to, 0 = From:, 1 = To:, 2 = Subject:, # 3 = Message, 4 = Cancel, 5 = Send live = 1 x_orig = x_field(field) x = x_orig y = 1 # Take user input while(live): if field == 4 or field == 5: curses.curs_set(0) else: curses.curs_set(1) # Makes Cursor visible, 0-2 if field == 4: window.addstr(26,48,"[Send]") window.addstr(26,23,"[Cancel]",curses.color_pair(2)) elif field == 5: window.addstr(26,48,"[Send]",curses.color_pair(2)) window.addstr(26,23,"[Cancel]") else: window.addstr(26,48,"[Send]") window.addstr(26,23,"[Cancel]") window.move(y,x) window.keypad(1) # Allows for special keys, e.g. backspace input = window.getch() # If Send or Cancel is selected if field == 4 or field == 5: if field == 4 and input == curses.KEY_DOWN: field = 5 y = 26 x_orig = x_field(field) x = x_orig elif field == 5 and input == curses.KEY_DOWN: field = 0 y = 1 x_orig = x_field(field) x = x_orig elif field == 4 and input == curses.KEY_UP: field = 3 y = 8 x_orig = x_field(field) x = x_orig elif field == 5 and input == curses.KEY_UP: field = 4 y = 26 x_orig = x_field(field) x = x_orig elif field == 4 and input == 10: live = 0 elif field == 5 and input == 10: live = 0 mail.append([from_field,to_field,subject_field,\ message_field]) # Functions regularly otherwise elif input == 263 and x > x_orig: # Backspace x -= 1 window.delch(y,x) # Deletes appropriate character from strings if field == 0: temp_field = from_field[(x-x_orig):] from_field = from_field[:(x-x_orig-1)] + temp_field elif field == 1: temp_field = to_field[(x-x_orig):] to_field = to_field[:(x-x_orig-1)] + temp_field elif field == 2: temp_field = subject_field[(x-x_orig):] subject_field = subject_field[:(x-x_orig-1)] + temp_field elif field == 3: temp_field = message_field[(x-x_orig):] message_field = message_field[:(x-x_orig-1)] + temp_field if field == 3: window.addch(y,x_orig+61,'|') window.addch(y,x_orig+60,' ') else: window.addch(y,x_orig+59,'-') elif input == 330 and x < (x_orig + 58): # Del Key window.delch(y,x) if field == 3: window.addch(y,x_orig+61,'|') window.addch(y,x_orig+61,' ') else: window.addch(y,x_orig+59,'-') elif input == curses.KEY_RIGHT and x < (x_orig + 58): # Right Arrow if field == 0 and x < (x_orig + len(from_field)): x += 1 if field == 1 and x < (x_orig + len(to_field)): x += 1 if field == 2 and x < (x_orig + len(subject_field)): x += 1 if field == 3 and x < (x_orig + len(message_field[:58])): x += 1 elif input == curses.KEY_LEFT and x > x_orig: # Left Arrow x -= 1 elif input == 10 or input == curses.KEY_DOWN: # Enter key, Down Arrow if field == 2: # Skips to message field from Subject: field = 3 y = 8 elif field == 3 and y == 24: # End of message field, back to From: field = 4 y = 26 elif field == 3: y += 1 message_field += '\n' else: field += 1 y += 2 x_orig = x_field(field) x = x_orig elif input == curses.KEY_UP: # Up Arrow if field == 0: field = 5 y = 26 elif field == 3 and y == 8: field = 2 y = 5 else: field -= 1 y -= 2 x_orig = x_field(field) x = x_orig elif curses.ascii.isctrl(input): # Ignores Ctrl Keys pass elif input > 255: # Ignores non-ASCII keys pass elif x < (x_orig + 59): # Not past borders if input != 4 and input != 5: window.addstr(y,x,str(curses.ascii.unctrl(input))) x += 1 if field == 0: from_field += curses.ascii.unctrl(input) elif field == 1: to_field += curses.ascii.unctrl(input) elif field == 2: subject_field += curses.ascii.unctrl(input) elif field == 3: message_field += curses.ascii.unctrl(input) return mail