diff options
Diffstat (limited to 'lib/bottompanel/graph_wdg.tcl')
-rwxr-xr-x | lib/bottompanel/graph_wdg.tcl | 1115 |
1 files changed, 1115 insertions, 0 deletions
diff --git a/lib/bottompanel/graph_wdg.tcl b/lib/bottompanel/graph_wdg.tcl new file mode 100755 index 0000000..bcb2d62 --- /dev/null +++ b/lib/bottompanel/graph_wdg.tcl @@ -0,0 +1,1115 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2008 by Martin Ošmera # +# martin.osmera@gmail.com # +# # +# This program is free software; you can redistribute it and#or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Graph widget for showing port states +# -------------------------------------------------------------------------- + +class GraphWidget { + ## COMMON + common step_y 13 ;# Int: Vertical distance between graph rows + common half_edge 5 ;# Int: Half length of bit edge + common full_edge 10 ;# Int: Full length of bit edge + + # Big font (vertical header) + common big_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -14 -weight bold \ + ] + # Small font (horizontal header) + common small_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -14 -weight bold \ + ] + # Font for booleans values for each port + common bool_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -12 -weight bold \ + ] + # Definition of graph popup menu + common GRAPHMENU { + {command {ON/OFF} {} 0 "graph_change_status_on" + {} "Enable/Disable graph"} + {separator} + {command {Change grid} {} 1 "graph_switch_grid_mode 1" + {} "Change grid morfology"} + {separator} + {command {Zoom in} {} 1 "graph_zoom_in" + {viewmag_in} "Change bit length on X axis to a lower value"} + {command {Zoom out} {} 1 "graph_zoom_out" + {viewmag_out} "Change bit length on X axis to a higher value"} + {separator} + {command {Remove marks} {} 1 "graph_clear_marks" + {editdelete} "Clear user marks"} + } + + # Variables related to object initialization + private variable gui_initialized 0 ;# Bool: GUI created + private variable _parent ;# Parent widget + private variable parent ;# Innert parent widget + + private variable canvasWidget ;# ID of the canvas widget + private variable grid_mode {b} ;# Current grid mode (one of {b n x y}) + private variable drawing_on 1 ;# Bool: Graph enabled + private variable magnification 0 ;# Magnification level (0..3) + private variable graph_elements ;# Array: IDs of graph elements (green and red lines) + private variable intr_lines {} ;# List of IDs of interrupt lines + private variable marks {} ;# List of IDs mark rectangulars + private variable mark_flags {} ;# List of Boolean mark flags + private variable state_history {} ;# History of X bits (for changing magnification level and stepback) + private variable intr_history {} ;# History of X interrupt flags + private variable previous_state ;# Array: previous state of each bit + private variable menu {} ;# ID of canvas popup menu + private variable step_x ;# Number of pixels required for draw one bit + private variable scrollable_frame ;# Widget: Scrollable area (parent for all other widgets) + private variable horizontal_scrollbar ;# Widget: Horizontal scrollbar for scrollable area + private variable number_of_ports ;# Int: Number of MCU's ports (see engine proc. get_ports_info) + private variable port_numbers ;# List: Numbers of implemented ports (e.g. {0 3}) + private variable port_length_in_px ;# Length of one port segment in PX + private variable port_graph_length ;# Same as port_length_in_px but only visible area + private variable history_max_length ;# Maximum history depth + + private variable Super ;# Object: Super + + + ## Prepare object for creating its GUI + # @parm Widget Parent - GUI parent widget + # @parm List _data_list - Configuration data list + # @return void + constructor {Parent super} { + set _parent $Parent + set Super $super + set gui_initialized 0 + } + + ## Object destructor + destructor { + if {$gui_initialized} { + menu_Sbar_remove $menu + } + } + + ## React to MCU change + # @return void + public method change_mcu {} { + if {!$gui_initialized} {return} + + foreach wdg [winfo children $_parent] { + destroy $wdg + } + set gui_initialized 0 + CreateGraphGUI + } + + ## Initialize graph + # @return void + public method CreateGraphGUI {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + # Determinate number of ports and port indexes + set number_of_ports [$Super get_ports_info] + set port_numbers [lindex $number_of_ports 1] + set number_of_ports [lindex $number_of_ports 0] + + set port_length_in_px [expr {840 / $number_of_ports}] + set port_graph_length [expr {$port_length_in_px - 15}] + set history_max_length [expr {$port_graph_length / 5}] + + # Create scrollable area + set scrollable_frame [ScrollableFrame $_parent.scrollable_frame \ + -xscrollcommand "$this graph_gui_scroll_set" \ + ] + set horizontal_scrollbar [ttk::scrollbar $_parent.horizontal_scrollbar \ + -orient horizontal -command "$scrollable_frame xview" \ + ] + pack $scrollable_frame -fill both -side bottom -expand 1 + set parent [$scrollable_frame getframe] + + # Create canvas widget + set canvasWidget [canvas $parent.canvas \ + -height 120 -width 860 -bd 0 \ + -highlightthickness 0 \ + ] + + # Create graph headers + for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} { + $canvasWidget create text 10 $y -text $i -font $small_font -anchor n -fill {#0000FF} -tags background + } + for {set i 0} {$i < $number_of_ports} {incr i} { + set x [expr {$i * $port_length_in_px + $port_length_in_px / 2 + 20}] + $canvasWidget create text $x 7 \ + -text "P[lindex $port_numbers $i]" \ + -font $big_font -fill {#0000FF} -tags background + } + # Create separators + $canvasWidget create line 20 0 20 120 -fill {#000000} -tags background + $canvasWidget create line 0 15 860 15 -fill {#000000} -tags background + for {set i 1} {$i <= $number_of_ports} {incr i} { + set x [expr {$i * $port_length_in_px + 20}] + $canvasWidget create line $x 0 $x 120 -fill {#000000} -tags background + incr x -$step_y + $canvasWidget create line $x 0 $x 120 -fill {#888888} -tags background + } + + # Initialize array of graph elements and previous states + for {set i 0} {$i < 40} {incr i} { + set graph_elements($i) {} + set previous_state($i) 1 + } + + # Create canvas popup menu + set menu $canvasWidget.menu + menuFactory $GRAPHMENU $menu 0 "$Super " 0 {} + + + # Set event bindings for the canvas widget + bind $canvasWidget <Motion> "$this graph_highlight %x %y" + bind $canvasWidget <Leave> "$this graph_unhighlight" + bind $canvasWidget <ButtonRelease-3> "$this graph_popup_menu %X %Y" + bind $canvasWidget <Button-1> "$this graph_place_mark %x %y" + + # Pack the canvas widget + set marks [string repeat {{} } [expr {$history_max_length + 1}]] + pack $canvasWidget -fill none -expand 0 -anchor nw -side left + + # Commit magnification level + commit_magnification $magnification + + # Commit ON/OFF state + commit_state_on_off $drawing_on + + # Create graph grid + graph_switch_grid_mode $grid_mode + } + + ## Draw interrupt line + # @parm String = {} - If "nohistory" the history of interrupt lines will not be modified + # @return void + public method graph_draw_interrupt_line args { + if {!$gui_initialized} {CreateGraphGUI} + + # Check if graph is enabled + if {!$drawing_on} {return} + + # Adjust history + if {$args != {nohistory}} { + if {[llength $intr_history]} { + lset intr_history end 1 + } { + lappend intr_history 1 + } + } + + # Create interrupt lines + set lines {} + for {set col 0} {$col < $number_of_ports} {incr col} { + set x [expr {$col * $port_length_in_px + ([llength $graph_elements(0)] * $step_x) + 20}] + lappend lines [$canvasWidget create line $x 16 $x 120 \ + -fill {#DDAA00} -tags graph -width 2 -dash ,] + } + + # Adjust list of canvas elements related to this line + if {$args != {nohistory}} { + if {[llength $intr_lines]} { + lset intr_lines end $lines + } { + lappend intr_lines $lines + } + } + } + + ## Draw new port states in the graph + # A) With history enabled: + # @parm String - Hexadecimal value of P0 + # @parm String - Hexadecimal value of P1 + # @parm String - Hexadecimal value of P2 + # @parm String - Hexadecimal value of P3 + # @parm String - Hexadecimal value of P4 + # B) With disabled: + # @parm List - {# {P0_hex P1_hex P2_hex P3_hex P4_hex}} + # @return void + public method graph_new_output_state args { + if {!$gui_initialized} {CreateGraphGUI} + + # Check if graph is enabled + if {!$drawing_on} {return} + + # Determinate number of bits per block and the current position + set treshold [expr {$port_graph_length / $step_x}] + set position [llength $graph_elements(0)] + + # If graph is full -> remove last elements and move the graph + if {$position == $treshold} { + # Remove elemets + for {set i 0} {$i < ($number_of_ports * 8)} {incr i} { + foreach elm [lindex $graph_elements($i) 0] { + $canvasWidget delete $elm + } + set graph_elements($i) [lreplace $graph_elements($i) 0 0] + } + foreach elm [lindex $intr_lines 0] { + $canvasWidget delete $elm + } + set intr_lines [lreplace $intr_lines 0 0] + # Adjust position index + incr position -1 + # Move graph + $canvasWidget move graph -$step_x 0 + } + + # Adjust history (cannot be longer than 38) + if {[llength $intr_history] > $history_max_length} { + set intr_history [lreplace $intr_history 0 0] + set state_history [lreplace $state_history 0 0] + } + + # Adjust history + set args [join $args {}] + if {[lindex $args 0] != {#}} { + lappend state_history [list {#} $args] + lappend intr_history 0 + } { + set args [lindex $args 1] + } + lappend intr_lines {} + + # Adjust arguments + set ports {} + foreach idx $port_numbers { + lappend ports [lindex $args $idx] + } + + # Create new elements + set p_idx 0 ;# Port index (not port number) + set idx 0 ;# Bit index + $canvasWidget delete booleans ;# Clear boolean values + foreach num_x $ports { + set num [list 0 0 0 0 0 0 0 0] + for {set i 0; set j 7} {$i < 8} {incr i; incr j -1} { + lset num $j [lindex $num_x $i] + } + + # Draw bits + foreach bit $num { + draw_bit $idx $position $bit + incr idx + } + # Draw booleans + write_boolean $p_idx $num + incr p_idx + } + } + + ## Write boolean values for the given port + # @parm Int port_idx - Port number + # @parm Int val - Port value + # @return void + private method write_boolean {port_idx val} { + set x [expr {($port_idx + 1) * $port_length_in_px + 13}] + + for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} { + switch -- [lindex $val $i] { + {1} { + set txt {H} + set clr {#FF0000} + } + {0} { + set txt {L} + set clr {#00FF00} + } + {|} { + set txt {-} + set clr {#FF8800} + } + {?} { + set txt {-} + set clr {#888888} + } + {X} { + set txt {-} + set clr {#8800FF} + } + {-} { + set txt {?} + set clr {#AAAA00} + } + {=} { + set txt {L} + set clr {#FF00AA} + } + } + + $canvasWidget create text $x $y \ + -text $txt \ + -font $bool_font \ + -anchor n \ + -fill $clr \ + -tags booleans + } + } + + ## Draw one bit to the graph + # @parm Int idx - Bit index (0..39) + # @parm Int pos - Target position + # @parm Char bool - Bit value + # @return void + private method draw_bit {idx pos bool} { + # Local variables + set prev $previous_state($idx) ;# Previous state of the bit + set offset_y [expr {($idx % 8) * $step_y + 18}] ;# Y offset + set lines {} ;# List of line IDs + # X offset + set offset_x [expr { + ($idx / 8) * $port_length_in_px + ($pos * $step_x) + 20 + }] + + # Determinate length of line elements acording to the current magnification level + switch -- $magnification { + {0} { + set line_len 3 + set enge_diff 0 + set enge_inc0 0 + set enge_inc1 0 + } + {1} { + set line_len 4 + set enge_diff 1 + set enge_inc0 1 + set enge_inc1 1 + } + {2} { + set line_len 6 + set enge_diff 1 + set enge_inc0 2 + set enge_inc1 1 + } + {3} { + set line_len 8 + set enge_diff 2 + set enge_inc0 2 + set enge_inc1 2 + } + } + + # Logical one forced to zero (e.g. by NPN transistor) + if {$bool == {=}} { + set bool 0 + set zero_color {#FF00AA} + } { + set zero_color {#FF0000} + } + + ## Draw graph line(s) + + # High frequency pulse + if {$bool == {|}} { + # Draw transition from the previous value + switch -- $prev { + {0} { ;# From logical 0 + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $full_edge}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill {#00FF00} -tags graph] + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + 0}] \ + -fill $zero_color -tags graph] + } + {1} { ;# From logical 1 + } + {?} { ;# From no voltage + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + 0}] \ + -fill $zero_color -tags graph] + } + {-} { ;# From undeterminable state + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + 0}] \ + -fill $zero_color -tags graph] + } + } + + if {$magnification == 0} { + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + 1}] $offset_y \ + [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + + lappend lines [$canvasWidget create line \ + [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \ + [expr {$offset_x + 1}] [expr {$offset_y + $full_edge}] \ + [expr {$offset_x + 3}] [expr {$offset_y + $full_edge}] \ + [expr {$offset_x + 3}] [expr {$offset_y + $half_edge}] \ + -fill {#00FF00} -tags graph] + + lappend lines [$canvasWidget create line \ + [expr {$offset_x + 4}] [expr {$offset_y + $half_edge}] \ + [expr {$offset_x + 4}] [expr {$offset_y}] \ + -fill $zero_color -tags graph] + } else { + switch -- $magnification { + {1} { + set line_len 3 + set enge_diff 0 + set enge_inc0 0 + set enge_inc1 0 + } + {2} { + set line_len 4 + set enge_diff 1 + set enge_inc0 1 + set enge_inc1 1 + } + {3} { + set line_len $half_edge + set enge_diff 1 + set enge_inc0 2 + set enge_inc1 1 + } + } + + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $line_len}] $offset_y\ + -fill $zero_color -tags graph] + incr offset_x $line_len + lappend lines [$canvasWidget create line\ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] \ + [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph \ + ] + incr offset_x $enge_inc0 + incr offset_y $half_edge + lappend lines [$canvasWidget create line\ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] \ + [expr {$offset_y + 5}] \ + -fill {#00FF00} -tags graph \ + ] + incr offset_x $enge_inc1 + incr offset_y $half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $line_len + 1}] $offset_y \ + -fill {#00FF00} -tags graph] + + incr offset_x $line_len + incr offset_x + lappend lines [$canvasWidget create line\ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] \ + [expr {$offset_y - $half_edge}] \ + -fill {#00FF00} -tags graph] + incr offset_x $enge_inc0 + incr offset_y -$half_edge + lappend lines [$canvasWidget create line\ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] \ + [expr {$offset_y - $half_edge}] \ + -fill $zero_color -tags graph] + incr offset_x $enge_inc1 + incr offset_y -$half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $line_len}] $offset_y \ + -fill $zero_color -tags graph] + } + + # Access to external memory + } elseif {$bool == {X}} { + lappend lines [$canvasWidget create rectangle \ + $offset_x $offset_y \ + [expr {$offset_x + $step_x}] [expr {$offset_y + $half_edge}] \ + -fill $zero_color -width 0 -tags graph] + lappend lines [$canvasWidget create rectangle \ + $offset_x [expr {$offset_y + $half_edge}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \ + -fill {#00FF00} -width 0 -tags graph] + + + set bool $prev + + # Underminable state + } elseif {$bool == {-}} { + # Draw transition from the previous value + switch -- $prev { + {0} { ;# From logical zero + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $full_edge}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill {#00FF00} -tags graph] + } + {1} { ;# From logical one + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + 0}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + } + {|} { ;# From high frequency pulse + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + 0}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + } + } + + incr offset_y $half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $line_len}] [expr {$offset_y + int(rand() * $half_edge)}] \ + [expr {$offset_x + $line_len + $enge_inc0}] $offset_y \ + [expr {$offset_x + $line_len + $enge_inc0 + $enge_inc1}] [expr {$offset_y - int(rand() * $half_edge)}] \ + [expr {$offset_x + 2*$line_len + $enge_inc0 + $enge_inc1}] $offset_y \ + -fill {#FF8800} -tags graph] + + # "Undeterminable state" -> "Zero" + } elseif {$prev == {-} && $bool == 0} { + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + $full_edge}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \ + -fill {#00FF00} -tags graph] + + # "Undeterminable state" -> "One" + } elseif {$prev == {-} && $bool == 1} { + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + 0}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \ + -fill $zero_color -tags graph] + + # No voltage + } elseif {$bool == {?}} { + # Draw transition from the previous value + switch -- $prev { + {0} { ;# From logical zero + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $full_edge}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill {#00FF00} -tags graph] + } + {1} { ;# From logical one + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + 0}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + } + {|} { ;# From high frequency pulse + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + 0}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + } + } + + incr offset_y $half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $step_x}] $offset_y \ + -fill {#888888} -tags graph -width 2] + + # "No voltage" -> "Zero" + } elseif {$prev == {?} && $bool == 0} { + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + $full_edge}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \ + -fill {#00FF00} -tags graph] + + # "No voltage" -> "One" + } elseif {$prev == {?} && $bool == 1} { + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + 0}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \ + -fill $zero_color -tags graph] + + # "High freq. pulse" -> "Zero" + } elseif {$prev == {|} && $bool == 0} { + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + 0}] \ + $offset_x [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + lappend lines [$canvasWidget create line \ + $offset_x [expr {$offset_y + $half_edge}] \ + $offset_x [expr {$offset_y + $full_edge}] \ + [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \ + -fill {#00FF00} -tags graph] + + # "High freq. pulse" -> "One" + } elseif {$prev == {|} && $bool == 1} { + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $step_x}] $offset_y \ + -fill $zero_color -tags graph] + + # 1 -> 1 + } elseif {$prev == 1 && $bool == 1} { + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $step_x}] $offset_y \ + -fill $zero_color -tags graph] + + # 1 -> 0 + } elseif {$prev == 1 && $bool == 0} { + lappend lines [$canvasWidget create line \ + $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \ + -fill $zero_color -tags graph] + incr offset_x $line_len + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] [expr {$offset_y + $half_edge}] \ + -fill $zero_color -tags graph] + incr offset_x $enge_inc0 + incr offset_y $half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] [expr {$offset_y + 5}] \ + -fill {#00FF00} -tags graph] + incr offset_x $enge_inc1 + incr offset_y $half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \ + -fill {#00FF00} -tags graph] + + # 0 -> 1 + } elseif {$prev == 0 && $bool == 1} { + incr offset_y $full_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \ + -fill {#00FF00} -tags graph] + incr offset_x $line_len + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \ + -fill {#00FF00} -tags graph] + incr offset_x $enge_inc0 + incr offset_y -$half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \ + -fill $zero_color -tags graph] + incr offset_x $enge_inc1 + incr offset_y -$half_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \ + -fill $zero_color -tags graph] + + # 0 -> 0 + } else { + incr offset_y $full_edge + lappend lines [$canvasWidget create line \ + $offset_x $offset_y \ + [expr {$offset_x + $step_x}] $offset_y \ + -fill {#00FF00} -tags graph] + } + + # Adjust array of graph elements and previous states + lappend graph_elements($idx) $lines + set previous_state($idx) $bool + } + + ## Iterate over avaliable grid modes + # @parm Int by - Iterate by + # @return void + public method graph_switch_grid_mode {_grid_mode} { + set grid_mode $_grid_mode + + # Adjust button in button bar and canvas popup menu + switch -- $grid_mode { + {b} {set image {grid0}} + {n} {set image {grid1}} + {y} {set image {grid2}} + {x} {set image {grid3}} + } + $menu entryconfigure [::mc "Change grid"] -image ::ICONS::16::$image + # Redraw grid + adjust_grid + } + + ## Adjust grid morfology to the current grid mode + # @return void + private method adjust_grid {} { + # Remove the current grid + catch { + $canvasWidget delete grid + } + # Create new grid + switch -- $grid_mode { + {b} { + draw_y_grid + draw_x_grid + } + {n} {} + {y} {draw_y_grid} + {x} {draw_x_grid} + } + } + + ## Draw vertical grid lines + # @return void + private method draw_y_grid {} { + # Iterate over graph blocks + for {set i 0} {$i < $number_of_ports} {incr i} { + # Determinate horizontal boundaries + set xoff [expr {$i * $port_length_in_px + 20 + $step_x}] + set xend [expr {($i + 1) * $port_length_in_px + 5}] + # Draw vertical lines + for {set x $xoff} {$x < $xend} {incr x $step_x} { + $canvasWidget create line $x 16 $x 120 -fill {#AAAAAA} -tags grid -dash . + } + } + } + + ## Draw horizontal grid lines + # @return void + private method draw_x_grid {} { + for {set y 30} {$y < 120} {incr y $step_y} { + $canvasWidget create line 0 $y 860 $y -fill {#888888} -tags grid + } + } + + ## Set graph configuration variables + # @parm Char _grid_mode - Grid morfology (one of {'n' 'x' 'y' 'b'}) + # @parm Int _magnification - Magnification mode (one of {0 1 2 3}) + # @parm Bool _drawing_on - Widget enabled + # @parm List _mark_flags - List of mark flags (e.g {0 0 0 1 1 0}) + # @return void + public method graph_set_data {_grid_mode _magnification _drawing_on _mark_flags} { + set grid_mode $_grid_mode + set magnification $_magnification + set drawing_on $_drawing_on + set mark_flags $_mark_flags + } + + ## Get mark flags + # @return String - String of boolean flags + public method graph_get_marks {} { + return [join $mark_flags {}] + } + + ## Adjust graph to the current magnification level + # @return void + public method commit_magnification {_magnification} { + set magnification $_magnification + + # Determinate one bit X axis step + set step_x [expr {$magnification * 5 + 5}] + + clear_graph keephistory ;# Clear graph + adjust_grid ;# Adjust graph grid + # Remove user marks + catch { + $canvasWidget delete mark + } + + # Restore graph content from the history (voltage levels and interrupt lines) + set length [expr {$port_graph_length / $step_x - 1}] + foreach state [lrange $state_history end-$length end] \ + intr [lrange $intr_history end-$length end] \ + { + graph_new_output_state $state + if {$intr == 1} { + graph_draw_interrupt_line nohistory + } + } + + # Restore user marks + set x_off [expr {21 - $step_x}] + set i -1 + foreach mark [lrange $mark_flags 0 $length] { + incr i + incr x_off $step_x + if {!$mark} {continue} + + set x $x_off + set lines [list] + for {set j 0} {$j < $number_of_ports} {incr j} { + lappend lines [$canvasWidget create rectangle \ + $x 16 [expr {$x + $step_x - 1}] 120 \ + -fill {#AA88FF} -tags mark -width 0] + incr x $port_length_in_px + } + lset marks $i $lines + } + } + + ## Remove all graph elements (voltage levels) + # @parm String - If "keephistory" then do not clear history + # @return void + public method clear_graph args { + if {!$gui_initialized} {CreateGraphGUI} + + catch { + $canvasWidget delete graph + } + catch { + $canvasWidget delete highlight + } + catch { + $canvasWidget delete booleans + } + for {set i 0} {$i < 40} {incr i} { + set graph_elements($i) {} + } + set intr_lines {} + + if {$args != {keephistory}} { + set state_history {} + set intr_history {} + for {set i 0} {$i < 40} {incr i} { + set previous_state($i) 1 + } + } + } + + ## Turn graph ON/OFF + # @return void + public method graph_change_status_on {} { + $Super graph_commit_state_on_off $drawing_on + } + + ## Adjust object to the current value of flag 'drawing_on' + # @return void + public method commit_state_on_off {_drawing_on} { + if {!$gui_initialized} {CreateGraphGUI} + set drawing_on $_drawing_on + + # Enable widgets + if {$drawing_on} { + $menu entryconfigure [::mc "Remove marks"] -state normal + $menu entryconfigure [::mc "Change grid"] -state normal + $canvasWidget configure -state normal + + # Disable widgets, clear graph and clear history + } else { + $menu entryconfigure [::mc "Remove marks"] -state disabled + $menu entryconfigure [::mc "Change grid"] -state disabled + $menu entryconfigure [::mc "Zoom in"] -state disabled + $menu entryconfigure [::mc "Zoom out"] -state disabled + $canvasWidget configure -state disabled + clear_graph + } + } + + ## Highlight graph segment + # @parm Int x - Relative X coordinate + # @parm Int y - Relative Y coordinate + # @return void + public method graph_highlight {x y} { + # Remove previous highlight + graph_unhighlight + + # Check for allowed coordinate range + if {$y < 17 || $x < 21} {return} + set x [expr {($x - 20) % $port_length_in_px}] + if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return} + + incr x [expr {-($x % $step_x)}] + incr x 21 + + # Draw highlight rectangulars + for {set i 0} {$i < $number_of_ports} {incr i} { + $canvasWidget create rectangle \ + $x 16 [expr {$x + $step_x - 1}] 120 \ + -fill {#88FFFF} -tags highlight -width 0 + incr x $port_length_in_px + } + + set y [expr {$y - (($y - 17) % $step_y)}] + + $canvasWidget create rectangle \ + 0 $y 860 [expr {$y + $step_y}] \ + -fill {#88FFFF} -tags highlight -width 0 + + # Set tag priorities + catch { + $canvasWidget lower highlight mark + } + catch { + $canvasWidget lower highlight grid + } + catch { + $canvasWidget lower highlight graph + } + catch { + $canvasWidget lower highlight booleans + } + catch { + $canvasWidget lower highlight background + } + } + + ## Remove highlightion + # @return void + public method graph_unhighlight {} { + catch { + $canvasWidget delete highlight + } + } + + ## Popup canvas menu + # @parm Int X - Absolute X coordinate + # @parm Int Y - Absolute X coordinate + # @return void + public method graph_popup_menu {X Y} { + tk_popup $menu $X $Y + } + + ## Place mark in the graph + # @parm Int x - Relative X coordinate + # @parm Int y - Relative Y coordinate + # @return void + public method graph_place_mark {x y} { + # Check for allowed coordinate range + if {$y < 17 || $x < 21} {return} + set x [expr {($x - 20) % $port_length_in_px}] + if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return} + + incr x [expr {-($x % $step_x)}] + set idx [expr {$x / $step_x}] + + # Create mark + if {[lindex $mark_flags $idx] != 1} { + incr x 21 + set lines {} + for {set i 0} {$i < $number_of_ports} {incr i} { + lappend lines [$canvasWidget create rectangle \ + $x 16 [expr {$x + $step_x - 1}] 120 \ + -fill {#AA88FF} -tags mark -width 0] + incr x $port_length_in_px + } + catch { + $canvasWidget raise mark highlight + } + catch { + $canvasWidget lower mark grid + } + catch { + $canvasWidget lower mark graph + } + lset marks $idx $lines + lset mark_flags $idx 1 + + # Remove mark + } { + catch { + foreach elm [lindex $marks $idx] { + $canvasWidget delete $elm + } + } + lset marks $idx {} + lset mark_flags $idx 0 + } + } + + ## Remove all user marks from the graph + # @return void + public method graph_clear_marks {} { + catch { + $canvasWidget delete mark + } + set marks [string repeat {{} } [expr {$history_max_length + 1}]] + set mark_flags [string repeat {0 } [expr {$history_max_length + 1}]] + } + + ## Adjust scrollbar for scrollable area + # @parm Float frac0 - 1st fraction + # @parm Float frac0 - 2nd fraction + # @return void + public method graph_gui_scroll_set {frac0 frac1} { + # Hide scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {[winfo ismapped $horizontal_scrollbar]} { + pack forget $horizontal_scrollbar + update + } + # Show scrollbar + } { + if {![winfo ismapped $horizontal_scrollbar]} { + pack $horizontal_scrollbar -fill x -side top -before $scrollable_frame + } + $horizontal_scrollbar set $frac0 $frac1 + update + } + } + + ## Try to restore graph state before the given number of program steps + # @parm Int bits - Number of steps to take back + # @return void + public method graph_stepback {bits} { + if {!$gui_initialized} {CreateGraphGUI} + if {!$drawing_on} {return} + + # Remove elemets + incr bits -1 + for {set i 0} {$i < ($number_of_ports * 8)} {incr i} { + foreach elm [lrange $graph_elements($i) end-$bits end] { + foreach e $elm { + $canvasWidget delete $e + } + } + foreach elm [lrange $intr_lines end-$bits end] { + foreach e $elm { + $canvasWidget delete $e + } + } + set graph_elements($i) [lreplace $graph_elements($i) end-$bits end] + } + set intr_lines [lreplace $intr_lines end-$bits end] + + # Adjust history + set intr_history [lreplace $intr_history end-$bits end] + set state_history [lreplace $state_history end-$bits end] + + # Return graph to state before $bits steps + set last_state [lindex $state_history {end 1}] + if {[llength $last_state]} { + set ports {} + foreach idx $port_numbers { + lappend ports [lindex $last_state $idx] + } + + set p_idx 0 ;# Port index (not port number) + set idx 0 ;# Bit index + $canvasWidget delete booleans ;# Clear boolean values + foreach num $ports { + foreach bit $num { + set previous_state($idx) $bit + incr idx + } + # Draw booleans + write_boolean $p_idx $num + incr p_idx + } + } else { + clear_graph + } + } +} |