#! -*- coding: utf-8 -*- #(c) Stefan Heher 2009 #1234567890123456789012345678901234567890123456789012345678901234567890123456789 import gtk import pygtk import pango import time import gobject from timer import Timer from sugar import profile from sugar.graphics import style from sugar.activity import activity class Display: """ Definition and manipulation of all GUI-elemts. Exception (redesign?): def define_buttons in classes derived from Exercise. """ print("in display, class definition") def __init__(self, window): self._permanent_gui_elements(window) self.errors = 0 self._ex = None # WN091214 ??? self._ex_key = None # self._sett = None # setting updated by callbacks during input self.running = False # first round of calculations WN091214 ??? def register(self, sess, co, learner): """register _after_ Session and Coach have been instantiated""" self._sess = sess self._co = co self._learner = learner def _permanent_gui_elements(self, window): # The display is partitioned as follows # # table: # 0 1 2 #0+-------------------------+------------------------+ # | | | #1| | OVERLAYS OF | # | scrolled_window | collection_table | #2| | OR | # | | settings_table | #3+-------------------------+ OR | # | | feedback_table | #4| empty for calcs etc | | # | | | #5+-------------------------+------------------------+ self.main_window = window # Save the sugar main window # whole window with 5 lines and 2 columns self.table = gtk.Table(5, 2, True) self.main_window.set_canvas(self.table) self.log_buffer = gtk.TextBuffer() self.tag_table = self.log_buffer.get_tag_table() self.error_tag = gtk.TextTag("error") # tag for errors self.error_tag.set_property("foreground", "blue") self.tag_table.add(self.error_tag) self.correct_tag = gtk.TextTag("correct")# tag for correct calcs self.correct_tag.set_property("foreground", "green") self.tag_table.add(self.correct_tag) # Create a log_view with the previously created log_buffer self.log_view = gtk.TextView(self.log_buffer) # Set the font size for the log_view self.log_view.modify_font(pango.FontDescription('sans bold 14')) self.log_view.set_editable(False) self.log_view.set_cursor_visible(False) self.log_view.set_justification(gtk.JUSTIFY_CENTER) self.scrolled_window = gtk.ScrolledWindow() # for the log_view self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) # Connect log_view and scrolled window self.scrolled_window.add(self.log_view) # Insert the log_view into the upper half self.table.attach(self.scrolled_window, 0, 1, 0, 3) self.log_view.show() self.scrolled_window.show() # 3 tables as overlays with same 15 lines and 6 columns self.settings_table = gtk.Table(15, 6, True) self.collection_table = gtk.Table(15, 6, True) self.feedback_table = gtk.Table(15, 6, True) # Insert the 3 tables into the right half of the screen self.table.attach(self.settings_table, 1, 2, 0, 5) self.table.attach(self.collection_table,1, 2, 0, 5) self.table.attach(self.feedback_table, 1, 2, 0, 5) # show all tables, scrolled_window already shown above self.settings_table.show() self.collection_table.show() self.feedback_table.show() self.table.show() # since all other tables have been inserted def update_time(self): minutes, seconds = divmod(self.stopwatch.elapsed, 60) if(minutes < 10 and seconds < 10): time = "0" + str(int(minutes)) + ":" + "0" + str(int(seconds)) if(minutes > 9 and seconds > 9): time = str(int(minutes)) + ":" + str(int(seconds)) if(minutes > 9 and seconds < 10): time = str(int(minutes)) + ":" + "0" + str(int(seconds)) if(minutes < 10 and seconds > 10): time = "0" + str(int(minutes)) + ":" + str(int(seconds)) self.stopwatch_label.set_label(time) self.stopwatch_label.queue_draw() return True def feedback_table_draw(self): """RENAME to draw_feedback_screen""" # Section for stopwatch self.stopwatch = Timer() self.stopwatch_label = gtk.Label("00:00") self.stopwatch_label.modify_font(pango.FontDescription("sans 16")) self.feedback_table.attach(self.stopwatch_label, 3, 5, 12, 13) # Section for nickname self.name = profile.get_nick_name() self.name_label = gtk.Label(self.name) self.name_label.modify_font(pango.FontDescription("sans 16")) self.feedback_table.attach(self.name_label, 0, 6, 13, 14) # Section for progress bar self.progressbar = gtk.ProgressBar(adjustment=None) # Color for progress bar style = self.progressbar.get_style() style.bg[gtk.STATE_PRELIGHT] = gtk.gdk.color_parse("green") self.progressbar.set_style (style) self.progressbar.set_fraction(0) self.feedback_table.attach(self.progressbar, 0, 6, 8, 9) # Labels for progress bar self.progress0 = gtk.Label("0") self.progress0.modify_font(pango.FontDescription("sans 16")) self.feedback_table.attach(self.progress0, 0, 1, 9, 10 ) # Labels for status update self.correct_count = 0 self.correct_counter = gtk.Label(str(self.correct_count)) self.correct_counter.modify_font(pango.FontDescription("sans 16")) # Ugly code for label color attr = pango.AttrList() fg_color = pango.AttrForeground(0, 65535, 0, 0, 6) attr.insert(fg_color) self.correct_counter.set_attributes(attr) self.feedback_table.attach(self.correct_counter, 2, 4, 9, 10 ) self.false_count = 0 self.false_counter = gtk.Label(str(self.false_count)) self.false_counter.modify_font(pango.FontDescription("sans 16")) # Ugly code for label color attr = pango.AttrList() fg_color = pango.AttrForeground(0, 0, 65535, 0, 6) attr.insert(fg_color) self.false_counter.set_attributes(attr) self.feedback_table.attach(self.false_counter, 2, 4, 10, 11 ) self.stopwatch_label.show() gobject.timeout_add(1000, self.update_time) self.name_label.show() self.progressbar.show() self.progress0.show() self.correct_counter.show() self.false_counter.show() self.total_calcs = self._ex.count() self.progress_total = gtk.Label(str(self.total_calcs)) self.progress_total.modify_font(pango.FontDescription("sans 16")) self.feedback_table.attach(self.progress_total, 5, 6, 9, 10 ) self.progress_total.show() def feedback_table_hide(self): self.progressbar.set_fraction(0) self.stopwatch_label.hide() self.name_label.hide() self.progressbar.hide() self.progress0.hide() self.correct_counter.hide() self.false_counter.hide() self.progress_total.hide() def offer_setting(self,ex): """ Prepare display for update of settings. """ self._ex = ex #WN.LV either drop this or self.current_exercise self._sett = self._ex.get_setting() #WN.LV make _sett local ### START BUTTON BEGIN ### self.start_button = gtk.Button(None, gtk.STOCK_GO_FORWARD) self.start_button.connect("clicked", self.clicked_start_callback) self.feedback_table.attach(self.start_button, 0, 6, 14, 15) self.start_alignment = self.start_button.get_children()[0] self.start_hbox = self.start_alignment.get_children()[0] self.start_image, self.start_label = self.start_hbox.get_children() self.start_label.set_label("") self.start_button.show() ### START BUTTON END ### self.current_exercise = ex #WN.LV either drop this or self._ex #print('in display.offer_setting, self._sett=', self._sett) self.current_exercise.define_buttons() self.current_exercise.set_buttons(self._sett) def clicked_start_callback(self, widget): """ Finish offer_setting, deliver settings (possibly updated) and tell the coach to start the calculations of the exercise ELIF """ if self.running == False: self.running = True self.start_button.set_label(gtk.STOCK_STOP) self.start_alignment = self.start_button.get_children()[0] self.start_hbox = self.start_alignment.get_children()[0] self.start_image, self.start_label = self.start_hbox.get_children() self.start_label.set_label("") self._co.notify(('setting-done', self._sett))# difference from here self.settings_table.hide() self.collection_table.hide() self.feedback_table_draw() elif self.running == True: self.protocol('----------------------------------------', 0, 'OK') self.running = False self.start_button.set_label(gtk.STOCK_GO_FORWARD) self.start_alignment = self.start_button.get_children()[0] self.start_hbox = self.start_alignment.get_children()[0] self.start_image, self.start_label = self.start_hbox.get_children() self.start_label.set_label("") self.display_table.destroy() # difference from here self.feedback_table_hide() self.settings_table.show() self.collection_table.show() def init_calc(self): """ prepares for calculations from 1 setting. for instance, a calculation might be on 1 ore more lines. """ print("in display.init_calc") # make empty lines such that all calcs are entered at bottom for i in range(1,21): end_iterator = self.log_buffer.get_end_iter() self.log_buffer.insert(end_iterator, "\n") self.log_view.scroll_mark_onscreen(self.log_buffer.get_insert()) def destroy_box(self): self.calculation_box.destroy() def protocol(self, full_line, errors, feedback): end_iterator = self.log_buffer.get_end_iter() if( feedback == 'OK' ): self.log_buffer.insert_with_tags_by_name(end_iterator, "\n" + full_line, "correct" ) elif ( feedback == 'XXX' ): self.log_buffer.insert_with_tags_by_name(end_iterator, "\n" + full_line, "error" ) end_iterator = self.log_buffer.get_end_iter() mark = self.log_buffer.create_mark(None, end_iterator, True) self.log_view.scroll_mark_onscreen(mark) # def dis_calc(self, clist, cursor, errs): # _i, _calc = 0, '' # for _c in clist: # _i = _i + 1 # if (_i == cursor) & (errs > 0): # _calc = _calc + '_' # else: # _calc = _calc + _c # return _calc + ' ' + errs * '/' def input_digit(self, widget, dig, proterr, protok): """callback: input a digit and give feedback. The _only_ other active widget is the -button on the right""" entry_text = widget.get_text() ### bitte anzeigen !??????? if(entry_text == dig): self.errors = 0 #WN090518 ??? self.protocol(protok, self.errors, 'OK') self.destroy_box() self.notify(('digit-done', None)) elif(entry_text == ""): pass #otherwise feedback in protocol written twice: see entry.set_text("") below else: self.false_count = self.false_count + 1 self.false_counter.set_text(str(self.false_count)) self.errors = self.errors + 1 widget.set_text("") self.protocol(proterr, self.errors, 'XXX') #WN090518 def display_calc(self, lines): self.display_table = gtk.Table(5, 1, True) self.table.attach(self.display_table, 0, 1, 0, 5) self.display_table.show() """display the lines of a calc with _ at all input positions""" lino = 0 for li in lines: #print('in Display.display_calc, line=', li) self.create_entryline((lino, -1, 'dummy-dig', 'dummy-proterr', 'dummy-protok', li)) lino = lino + 1 def create_entryline(self, (lineno, linepos, dig, proterr, protok, line)): """create gtk.Entry in line at linepos and set callback_input_digit""" #print('in Display.create_entryline: lineno=', lineno, ', linepos=', # linepos, ', line=', line) calculation, cursor = line, linepos self.calculation_box = gtk.HBox(True, 0) calc_pos = 0 self.display_table.attach(self.calculation_box, 0, 1, 3 + lineno, 4 + lineno) for i in calculation: if (calc_pos != cursor): self.label = gtk.Label(i) self.label.modify_font(pango.FontDescription("sans 24")) self.calculation_box.pack_start(self.label) self.label.show() else: # prepare for input self.text_entry = gtk.Entry(max = 1) self.text_entry.modify_font(pango.FontDescription("sans 24")) self.text_entry.connect("changed", self.input_digit, dig, proterr, protok) self.calculation_box.pack_start(self.text_entry) self.text_entry.show() calc_pos = calc_pos + 1 #?kann m.die calculation_box ZUERST aufbauen und DANN self.table.attach self.calculation_box.show() if(cursor != -1): self.text_entry.grab_focus() #just add lineno to table.attach #TODO rename calculation, cursor below ... #TODO remove hack on callback: #self.input_digit('widget', dig, protline) def finish_calc(self): self.stopwatch.stop() def notify(self, msg): """only used by gtk""" if msg[0] == 'digit-done': self._learner.notify(('digit-done', None)) def show_progress(self): self.progressbar.set_fraction(self.progressbar.get_fraction()+(float(1)/float(self.total_calcs))) self.correct_count = self.correct_count + 1 self.correct_counter.set_text(str(self.correct_count)) self.display_table.destroy() def offer_coll_to_learner(self, collect): """TODO: get the users choice from buttons above the settings""" collect.define_coll_gui() collect.set_coll_gui() def switch_exercise(self): """ Another exercise has been selected. """ self.settings_table.destroy() self.settings_table = gtk.Table(15, 6, True) self.table.attach(self.settings_table, 1, 2, 0, 5) self.settings_table.show() self.feedback_table.destroy() self.feedback_table = gtk.Table(15, 6, True) self.table.attach(self.feedback_table, 1, 2, 0, 5) self.feedback_table.show()