Exemplo n.º 1
0
class Box(Component):

    color        = ColorTrait("white")
    border_color = ColorTrait("black")
    border_size  = border_size_trait

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        "Draw the box background in a specified graphics context"

        # Set up all the control variables for quick access:
        bs  = self.border_size
        bsd = bs + bs
        bsh = bs / 2.0
        x, y = self.position
        dx, dy = self.bounds

        with gc:
            # Fill the background region (if required);
            color = self.color_
            if color is not transparent_color:
                gc.set_fill_color(color)
                gc.draw_rect((x + bs, y + bs, dx - bsd, dy - bsd), FILL)
    
            # Draw the border (if required):
            if bs > 0:
                border_color = self.border_color_
                if border_color is not transparent_color:
                    gc.set_stroke_color(border_color)
                    gc.set_line_width(bs)
                    gc.draw_rect((x + bsh, y + bsh, dx - bs, dy - bs), STROKE)
        return
Exemplo n.º 2
0
class Legend(HasTraits):
    measured_color = ColorTrait('purple')
    loaded_color = ColorTrait('green')

    def draw(self, component, gc):
        r = 6
        gc.set_font(str_to_font('modern 10'))
        with gc:
            gc.translate_ctm(component.x + 20, component.y2 - 50)

            # monitor
            with gc:
                gc.set_line_width(1)
                gc.set_fill_color((0, 0, 0))
                gc.arc(0, 30, r, 0, 360)

                x = 0
                y = 30
                gc.move_to(x, y - r)
                gc.line_to(x, y + r)
                gc.stroke_path()

                gc.move_to(x - r, y)
                gc.line_to(x + r, y)
                gc.stroke_path()

            gc.set_text_position(10, 26)
            gc.show_text('Monitor')

            # irradiated
            with gc:
                gc.set_line_width(1)
                gc.set_fill_color(self.loaded_color_)
                gc.arc(0, 16, r, 0, 360)
                gc.fill_path()

            gc.set_text_position(10, 12)
            gc.show_text('Irradiated')

            # measured
            with gc:
                gc.set_line_width(1)
                gc.set_fill_color(self.loaded_color_)
                gc.arc(0, 0, r, 0, 360)
                gc.fill_path()

            with gc:
                gc.set_line_width(2)
                gc.set_stroke_color(self.measured_color_)
                gc.arc(0, 0, r + 1, 0, 360)
                gc.stroke_path()

            gc.set_text_position(10, -5)
            gc.show_text('Measured')
Exemplo n.º 3
0
class LatestOverlay(AbstractOverlay):
    data_position = None
    color = ColorTrait('transparent')

    # The color of the outline to draw around the marker.
    outline_color = ColorTrait('orange')

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        with gc:
            pts = self.component.map_screen(self.data_position)
            render_markers(gc, pts, 'circle', 5, self.color_, 2,
                           self.outline_color_)
Exemplo n.º 4
0
class LimitOverlay(AbstractOverlay):
    tool = LimitsTool
    label = Instance(XYPlotLabel)
    color = ColorTrait('red')
    label_manual_color = ColorTrait('tomato')
    label_bgcolor = ColorTrait('lightblue')

    def _label_default(self):
        return XYPlotLabel(
            component=self.component,
            bgcolor=self.label_bgcolor,
            # border_width = LabelDelegate
            border_color='black',
            # border_visible = LabelDelegate
            border_visible=True)

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):

        tool = self.tool
        y, y2 = other_component.y, other_component.y2
        x, x2 = other_component.x, other_component.x2

        if tool.ruler_pos:
            a, b = tool.ruler_pos
            if tool.orientation == 'x':
                x, x2 = a, a
                self.label.sx = x
                self.label.sy = b + 10
            else:
                y, y2 = b, b
                self.label.sx = a + 20
                self.label.sy = y

            with gc:
                gc.set_stroke_color(self.color_)
                gc.set_line_width(2)
                gc.lines([(x, y), (x2, y2)])
                gc.stroke_path()

            if tool.entered_value:
                self.label.bgcolor = self.label_manual_color
                v = tool.entered_value
            else:
                self.label.bgcolor = self.label_bgcolor
                v = floatfmt(tool.ruler_data_pos)

            self.label.text = '{}: {}'.format(tool.orientation.upper(), v)
            self.label.overlay(other_component,
                               gc,
                               view_bounds=None,
                               mode="normal")
Exemplo n.º 5
0
class ColorStop(HasStrictTraits):
    """ A point on a gradient with a fixed color. """

    #: The position of the color stop in the gradient, between 0.0 and 1.0.
    offset = Range(0.0, 1.0, update=True)

    #: The color at the color stop.
    color = ColorTrait("transparent", update=True)

    #: A trait which fires when the color stop is updated.
    updated = Event()

    def to_array(self):
        """ Return an array which represents the color stop.

        This is the raw form of the color stop required by Kiva.

        Returns
        -------
        stop_array : numpy array
            Return an array of (offset, r, b, b, a).
        """
        return array([self.offset] + list(self.color_))

    @observe("+update")
    def observe_update_traits(self, event):
        self.updated = True
Exemplo n.º 6
0
class ComponentEditor(BasicEditorFactory):
    """ wxPython editor factory for Enable components.
    """
    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # The class used to create all editor styles (overrides BasicEditorFactory).
    klass = _ComponentEditor

    # The background color for the window
    bgcolor = ColorTrait('sys_window')

    # The default size of the Window wrapping this Enable component
    size = Tuple((400, 400))

    # Convenience function for accessing the width
    width = Property

    # Convenience function for accessing the width
    height = Property

    def _get_width(self):
        return self.size[0]

    def _set_width(self, width):
        self.size = (width, self.size[1])

    def _get_height(self):
        return self.size[1]

    def _set_height(self, height):
        self.size = (self.size[0], height)
class Annotater(Component):

    color = ColorTrait((0.0, 0.0, 0.0, 0.2))
    style = Trait("rectangular", TraitPrefixList(["rectangular", 'freehand']))
    annotation = Event

    traits_view = View(Group('<component>', id='component'),
                       Group('<links>', id='links'),
                       Group('color', 'style', id='annotater', style='custom'))

    #---------------------------------------------------------------------------
    # Mouse event handlers
    #---------------------------------------------------------------------------

    def _left_down_changed(self, event):
        event.handled = True
        self.window.mouse_owner = self
        self._cur_x, self._cur_y = event.x, event.y
        self._start_x, self._start_y = event.x, event.y
        return

    def _left_up_changed(self, event):
        event.handled = True
        self.window.mouse_owner = None
        if self.xy_in_bounds(event):
            self.annotation = (min(self._start_x,
                                   event.x), min(self._start_y, event.y),
                               abs(self._start_x - event.x),
                               abs(self._start_y - event.y))
        self._start_x = self._start_y = self._cur_x = self._cur_y = None
        self.redraw()
        return

    def _mouse_move_changed(self, event):
        event.handled = True
        if self._start_x is not None:
            x = max(min(event.x, self.right - 1.0), self.x)
            y = max(min(event.y, self.top - 1.0), self.y)
            if (x != self._cur_x) or (y != self._cur_y):
                self._cur_x, self._cur_y = x, y
                self.redraw()
        return

    #---------------------------------------------------------------------------
    # "Component" interface
    #---------------------------------------------------------------------------

    def _draw(self, gc):
        "Draw the contents of the control"
        if self._start_x is not None:
            with gc:
                gc.set_fill_color(self.color_)
                gc.begin_path()
                gc.rect(min(self._start_x, self._cur_x),
                        min(self._start_y, self._cur_y),
                        abs(self._start_x - self._cur_x),
                        abs(self._start_y - self._cur_y))
                gc.fill_path()
        return
Exemplo n.º 8
0
class TextFieldStyle(HasTraits):
    """ This class holds style settings for rendering an EnableTextField.
        fixme: See docstring on EnableBoxStyle
    """

    # The color of the text
    text_color = ColorTrait((0, 0, 0, 1.0))

    # The font for the text (must be monospaced!)
    font = KivaFont("Courier 12")

    # The color of highlighted text
    highlight_color = ColorTrait((0.65, 0, 0, 1.0))

    # The background color of highlighted items
    highlight_bgcolor = ColorTrait("lightgray")

    # The font for flagged text (must be monospaced!)
    highlight_font = KivaFont("Courier 14 bold")

    # The number of pixels between each line
    line_spacing = Int(3)

    # Space to offset text from the widget's border
    text_offset = Int(5)

    # Cursor properties
    cursor_color = ColorTrait((0, 0, 0, 1))
    cursor_width = Int(2)

    # Drawing properties
    border_visible = Bool(False)
    border_color = ColorTrait((0, 0, 0, 1))
    bgcolor = ColorTrait((1, 1, 1, 1))
Exemplo n.º 9
0
class ANumericItem(HasPrivateTraits):
    """ Defines an abstract base class for accessing an item in a
        NumericContext.
    """

    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # The context containing this item:
    context = Instance(ANumericContext)

    # The list of groups the item belongs to:
    groups = List

    # Name of the context trait for this item (implemented in each subclass):
    #name = Property

    # The current value of the associated numeric array (implemented in each
    # subclass):
    #data = Property

    # Value to be substituted in reduction filters when 'use_value' is True:
    value = Any(nan)

    #-- View related ---------------------------------------------------------------

    # User interface label:
    label = Str

    # String formatting rule:
    format = Str('%.3f')

    # Foreground color (intended use: text color, plot line color):
    foreground_color = ColorTrait('black')

    # Background color (intended use: text background color, plot fill color):
    background_color = ColorTrait('white')
Exemplo n.º 10
0
class SelectorOverlay(AbstractOverlay):
    tool = Any
    color = ColorTrait('green')

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        if self.tool.event_state == 'select':
            with gc:
                w, h = self.component.bounds
                x, y = self.component.x, self.component.y

                gc.set_stroke_color(self.color_)
                gc.set_line_width(4)
                gc.rect(x, y, w, h)
                gc.stroke_path()
Exemplo n.º 11
0
class ColorBrush(Brush):
    """ A simple brush that paints a solid color. """

    #: The color to brush the region with.
    color = ColorTrait("transparent", update=True)

    def set_brush(self, gc):
        """ Apply the brush settings to a graphics context.

        This sets the fill color of the GC to the specified color.

        Parameters
        ----------
        gc : graphics context
            The graphics context to use the brush with.
        """
        gc.set_fill_color(self.color_)
Exemplo n.º 12
0
class GuideOverlay(AbstractOverlay):
    """
    draws a horizontal or vertical line at the specified value
    """
    orientation = Enum('h', 'v')
    value = Float
    color = ColorTrait("red")
    line_style = LineStyle('dash')
    line_width = Float(1)
    display_value = False

    label = Instance(Label, ())

    def overlay(self, component, gc, view_bounds=None, mode='normal'):
        with gc:
            gc.clip_to_rect(component.x, component.y, component.width,
                            component.height)
            with gc:
                gc.set_line_dash(self.line_style_)
                gc.set_line_width(self.line_width)
                gc.set_stroke_color(self.color_)
                gc.begin_path()

                if self.orientation == 'h':
                    x1 = component.x
                    x2 = component.x2
                    y1 = y2 = component.value_mapper.map_screen(self.value)
                else:
                    y1 = component.y
                    y2 = component.y2
                    x1 = x2 = component.index_mapper.map_screen(self.value)

                gc.move_to(x1, y1)
                gc.line_to(x2, y2)
                gc.stroke_path()

            if self.display_value:
                with gc:
                    l = self.label
                    l.text = '{:0.5f}'.format(self.value)
                    l.position = self.label_position
                    l.draw(gc)
Exemplo n.º 13
0
class SelectableBox(Box):
    """ A box that can be selected and renders in a different color """

    selected = Bool

    selected_color = ColorTrait('green')

    def select(self, selected):
        self.selected = selected

    def _selected_changed(self):
        self.request_redraw()

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        "Draw the box background in a specified graphics context"

        # Set up all the control variables for quick access:
        bs = self.border_size
        bsd = bs + bs
        bsh = bs / 2.0
        x, y = self.position
        dx, dy = self.bounds

        with gc:
            if self.selected:
                color = self.selected_color_
            else:
                color = self.color_
            if color is not transparent_color:
                gc.set_fill_color(color)
                gc.draw_rect((x + bs, y + bs, dx - bsd, dy - bsd), FILL)

            # Draw the border (if required):
            if bs > 0:
                border_color = self.border_color_
                if border_color is not transparent_color:
                    gc.set_stroke_color(border_color)
                    gc.set_line_width(bs)
                    gc.draw_rect((x + bsh, y + bsh, dx - bs, dy - bs), STROKE)
        return
Exemplo n.º 14
0
class GuideOverlay(AbstractOverlay):
    """
    draws a horizontal or vertical line at the specified value
    """
    orientation = Enum('h', 'v')
    value = Float
    color = ColorTrait("red")
    line_style = LineStyle('dash')

    line_width = Float(1)

    def overlay(self, component, gc, view_bounds=None, mode='normal'):
        """

        """
        gc.save_state()
        gc.clip_to_rect(self.component.x, self.component.y,
                        self.component.width, self.component.height)
        gc.set_line_dash(self.line_style_)
        gc.set_line_width(self.line_width)
        gc.set_stroke_color(self.color_)
        gc.begin_path()

        if self.orientation == 'h':
            x1 = self.component.x
            x2 = self.component.x2
            y1 = y2 = self.component.value_mapper.map_screen(self.value)

        else:
            y1 = self.component.y
            y2 = self.component.y2
            x1 = x2 = self.component.index_mapper.map_screen(self.value)

        gc.move_to(x1, y1)
        gc.line_to(x2, y2)
        gc.stroke_path()
        gc.restore_state()
Exemplo n.º 15
0
class ComponentEditor(BasicEditorFactory):
    """ TraitsUI editor factory for Enable components.
    """

    # -------------------------------------------------------------------------
    #  Trait definitions:
    # -------------------------------------------------------------------------

    # The class used to create all editor styles (overrides BasicEditorFactory)
    klass = _ComponentEditor

    #: The background color for the window
    bgcolor = ColorTrait("sys_window")

    #: When available, use HiDPI for GraphicsContext rasterization.
    high_resolution = Bool(True)

    #: The default size of the Window wrapping this Enable component
    size = Tuple((400, 400))

    #: Convenience function for accessing the width
    width = Property

    #: Convenience function for accessing the width
    height = Property

    def _get_width(self):
        return self.size[0]

    def _set_width(self, width):
        self.size = (width, self.size[1])

    def _get_height(self):
        return self.size[1]

    def _set_height(self, height):
        self.size = (self.size[0], height)
Exemplo n.º 16
0
class tcPlot(BarPlot):
    """custom plot to draw the timechart
    probably not very 'chacotic' We draw the chart as a whole
    """
    # The text of the axis title.
    title = Trait('', Str, Unicode)  #May want to add PlotLabel option
    # The font of the title.
    title_font = KivaFont('modern 9')
    # The font of the title.
    title_font_large = KivaFont('modern 15')
    # The font of the title.
    title_font_huge = KivaFont('modern 20')
    # The spacing between the axis line and the title
    title_spacing = Trait('auto', 'auto', Float)
    # The color of the title.
    title_color = ColorTrait("black")
    not_on_screen = List
    on_screen = List
    options = TimeChartOptions()
    range_tools = RangeSelectionTools()
    redraw_timer = None

    def invalidate(self):
        self.invalidate_draw()
        self.request_redraw()

    def immediate_invalidate(self):
        self.invalidate_draw()
        self.request_redraw_delayed()

    def request_redraw_delayed(self):
        self.redraw_timer.Stop()
        BarPlot.request_redraw(self)

    def request_redraw(self):
        if self.redraw_timer == None:
            self.redraw_timer = timer.Timer(30, self.request_redraw_delayed)
        self.redraw_timer.Start()

    def auto_zoom_y(self):
        if self.value_range.high != self.max_y + 1 or self.value_range.low != self.min_y:
            self.value_range.high = self.max_y + 1
            self.value_range.low = self.min_y
            self.invalidate_draw()
            self.request_redraw()

    def _gather_timechart_points(self, start_ts, end_ts, y, step):
        low_i = searchsorted(end_ts, self.index_mapper.range.low)
        high_i = searchsorted(start_ts, self.index_mapper.range.high)
        if low_i == high_i:
            return array([])

        start_ts = start_ts[low_i:high_i]
        end_ts = end_ts[low_i:high_i]
        points = column_stack(
            (start_ts, end_ts, zeros(high_i - low_i) + (y + step),
             ones(high_i - low_i) + (y - step),
             array(list(range(low_i, high_i)))))
        return points

    def _draw_label(self, gc, label, text, x, y):
        label.text = text
        l_w, l_h = label.get_width_height(gc)
        offset = array((x, y - l_h / 2))
        gc.translate_ctm(*offset)
        label.draw(gc)
        gc.translate_ctm(*(-offset))
        return l_w, l_h

    def _draw_timechart(self, gc, tc, label, base_y):
        bar_middle_y = self.first_bar_y + (base_y + .5) * self.bar_height
        points = self._gather_timechart_points(tc.start_ts, tc.end_ts, base_y,
                                               .2)
        overview = None
        if self.options.use_overview:
            if points.size > 500:
                overview = tc.get_overview_ts(self.overview_threshold)
                points = self._gather_timechart_points(overview[0],
                                                       overview[1], base_y, .2)

        if self.options.remove_pids_not_on_screen and points.size == 0:
            return 0
        if bar_middle_y + self.bar_height < self.y or bar_middle_y - self.bar_height > self.y + self.height:
            return 1  #quickly decide we are not on the screen
        self._draw_bg(gc, base_y, tc.bg_color)
        # we are too short in height, dont display all the labels
        if self.last_label >= bar_middle_y:
            # draw label
            l_w, l_h = self._draw_label(gc, label, tc.name, self.x,
                                        bar_middle_y)
            self.last_label = bar_middle_y - 8
        else:
            l_w, l_h = 0, 0
        if points.size != 0:
            # draw the middle line from end of label to end of screen
            if l_w != 0:  # we did not draw label because too short on space
                gc.set_alpha(0.2)
                gc.move_to(self.x + l_w, bar_middle_y)
                gc.line_to(self.x + self.width, bar_middle_y)
                gc.draw_path()
            gc.set_alpha(0.5)
            # map the bars start and stop locations into screen space
            lower_left_pts = self.map_screen(points[:, (0, 2)])
            upper_right_pts = self.map_screen(points[:, (1, 3)])
            bounds = upper_right_pts - lower_left_pts

            if overview:  # critical path, we only draw unicolor rects
                #calculate the mean color
                #print points.size
                gc.set_fill_color(get_aggcolor_by_id(get_color_id("overview")))
                gc.set_alpha(.9)
                rects = column_stack((lower_left_pts, bounds))
                gc.rects(rects)
                gc.draw_path()
            else:
                # lets display them more nicely
                rects = column_stack((lower_left_pts, bounds, points[:, (4)]))
                last_t = -1
                gc.save_state()
                for x, y, sx, sy, i in rects:
                    t = tc.types[int(i)]

                    if last_t != t:
                        # only draw when we change color. agg will then simplify the path
                        # note that a path only can only have one color in agg.
                        gc.draw_path()
                        gc.set_fill_color(get_aggcolor_by_id(int(t)))
                        last_t = t
                    gc.rect(x, y, sx, sy)
                # draw last path
                gc.draw_path()
                if tc.has_comments:
                    for x, y, sx, sy, i in rects:
                        if sx < 8:  # not worth calculatig text size
                            continue
                        label.text = tc.get_comment(i)
                        l_w, l_h = label.get_width_height(gc)
                        if l_w < sx:
                            offset = array(
                                (x, y + self.bar_height * .6 / 2 - l_h / 2))
                            gc.translate_ctm(*offset)
                            label.draw(gc)
                            gc.translate_ctm(*(-offset))

            if tc.max_latency > 0:  # emphase events where max_latency is reached
                ts = tc.max_latency_ts
                if ts.size > 0:
                    points = self._gather_timechart_points(ts, ts, base_y, 0)
                    if points.size > 0:
                        # map the bars start and stop locations into screen space
                        gc.set_alpha(1)
                        lower_left_pts = self.map_screen(points[:, (0, 2)])
                        upper_right_pts = self.map_screen(points[:, (1, 3)])
                        bounds = upper_right_pts - lower_left_pts
                        rects = column_stack((lower_left_pts, bounds))
                        gc.rects(rects)
                        gc.draw_path()
                        #print('gc.draw_path() ', __file__)
                        #assert True, 'draw_path'
        return 1

    def _draw_freqchart(self, gc, tc, label, y):
        self._draw_bg(gc, y, tc.bg_color)
        low_i = searchsorted(tc.start_ts, self.index_mapper.range.low)
        high_i = searchsorted(tc.start_ts, self.index_mapper.range.high)

        if low_i > 0:
            low_i -= 1
        if high_i < len(tc.start_ts):
            high_i += 1
        if low_i >= high_i - 1:
            return array([])
        start_ts = tc.start_ts[low_i:high_i - 1]
        end_ts = tc.start_ts[low_i + 1:high_i]
        values = (tc.types[low_i:high_i - 1] / (float(tc.max_types))) + y
        starts = column_stack((start_ts, values))
        ends = column_stack((end_ts, values))
        starts = self.map_screen(starts)
        ends = self.map_screen(ends)
        gc.begin_path()
        gc.line_set(starts, ends)
        gc.stroke_path()
        for i in range(len(starts)):
            x1, y1 = starts[i]
            x2, y2 = ends[i]
            sx = x2 - x1
            if sx > 8:
                label.text = str(tc.types[low_i + i])
                l_w, l_h = label.get_width_height(gc)
                if l_w < sx:
                    if x1 < 0: x1 = 0
                    offset = array((x1, y1))
                    gc.translate_ctm(*offset)
                    label.draw(gc)
                    gc.translate_ctm(*(-offset))

    def _draw_wake_ups(self, gc, processes_y):
        low_i = searchsorted(self.proj.wake_events['time'],
                             self.index_mapper.range.low)
        high_i = searchsorted(self.proj.wake_events['time'],
                              self.index_mapper.range.high)
        gc.set_stroke_color((0, 0, 0, .6))
        for i in range(low_i, high_i):
            waker, wakee, ts = self.proj.wake_events[i]
            if wakee in processes_y and waker in processes_y:
                y1 = processes_y[wakee]
                y2 = processes_y[waker]
                x, y = self.map_screen(array((ts, y1)))
                gc.move_to(x, y)
                y2 = processes_y[waker]
                x, y = self.map_screen(array((ts, y2)))
                gc.line_to(x, y)
                x, y = self.map_screen(array((ts, (y1 + y2) / 2)))
                if y1 > y2:
                    y += 5
                    dy = -5
                else:
                    y -= 5
                    dy = +5
                gc.move_to(x, y)
                gc.line_to(x - 3, y + dy)
                gc.move_to(x, y)
                gc.line_to(x + 3, y + dy)

        gc.draw_path()

    def _draw_bg(self, gc, y, color):
        gc.set_alpha(1)
        gc.set_line_width(0)
        gc.set_fill_color(color)
        this_bar_y = self.map_screen(array((0, y)))[1]
        gc.rect(self.x, this_bar_y, self.width, self.bar_height)
        gc.draw_path()
        gc.set_line_width(self.line_width)
        gc.set_alpha(0.5)

    def _draw_plot(self, gc, view_bounds=None, mode="normal"):
        gc.save_state()
        gc.clip_to_rect(self.x, self.y, self.width, self.height)
        gc.set_antialias(1)
        gc.set_stroke_color(self.line_color_)
        gc.set_line_width(self.line_width)
        self.first_bar_y = self.map_screen(array((0, 0)))[1]
        self.last_label = self.height + self.y
        self.bar_height = self.map_screen(array((0, 1)))[1] - self.first_bar_y
        self.max_y = y = self.proj.num_cpu * 2 + self.proj.num_process - 1
        if self.bar_height > 15:
            font = self.title_font_large
        else:
            font = self.title_font
        label = Label(text="",
                      font=font,
                      color=self.title_color,
                      rotate_angle=0)
        # we unmap four pixels on screen, and find the nearest greater power of two
        # this by rounding the log2, and then exponentiate again
        # as the overview data is cached, this avoids using too much memory

        four_pixels = self.index_mapper.map_data(array((0, 4)))
        if len(four_pixels) == 1:
            self.overview_threshold = 1 << int(
                log(1 + int(four_pixels[0] - four_pixels[0]), 2))
        else:
            self.overview_threshold = 1 << int(
                log(1 + int(four_pixels[1] - four_pixels[0]), 2))

        for i in range(len(self.proj.c_states)):
            tc = self.proj.c_states[i]
            if self.options.show_c_states:
                self._draw_timechart(gc, tc, label, y)
                y -= 1
            tc = self.proj.p_states[i]
            if self.options.show_p_states:
                self._draw_freqchart(gc, tc, label, y)
                y -= 1
        processes_y = {0xffffffffffffffff: y + 1}
        not_on_screen = []
        on_screen = []

        for tc in self.proj.processes:
            if tc.show == False:
                continue
            processes_y[(tc.comm, tc.pid)] = y + .5
            if self._draw_timechart(
                    gc, tc, label,
                    y) or not self.options.remove_pids_not_on_screen:
                y -= 1
                on_screen.append(tc)
            else:
                not_on_screen.append(tc)
        self.not_on_screen = not_on_screen
        self.on_screen = on_screen
        if self.options.show_wake_events:
            self._draw_wake_ups(gc, processes_y)

        message = ""
        if self.proj.filename == "dummy":
            message = "please load a trace file in the 'file' menu"
        elif len(self.proj.processes) == 0:
            message = "no processes??! is your trace empty?"
        if message:
            label.text = message
            label.font = self.title_font_huge
            gc.translate_ctm(100, (self.y + self.height) / 2)
            label.draw(gc)

        gc.restore_state()
        self.min_y = y
        if self.options.auto_zoom_y:
            self.options.auto_zoom_timer.Start()

    def _on_hide_others(self):
        for i in self.not_on_screen:
            i.show = False
        self.invalidate_draw()
        self.request_redraw()

    def _on_hide_onscreen(self):
        for i in self.on_screen:
            i.show = False
        self.invalidate_draw()
        self.request_redraw()
Exemplo n.º 17
0
class Polygon(Component):
    """ A filled polygon component. """

    #--------------------------------------------------------------------------
    # Trait definitions.
    #--------------------------------------------------------------------------

    # The background color of this polygon.
    background_color = ColorTrait("white")

    # The color of the border of this polygon.
    border_color = ColorTrait("black")

    # The dash pattern to use for this polygon.
    border_dash = Any

    # The thickness of the border of this polygon.
    border_size = Trait(1, border_size_trait)

    # Event fired when the polygon is "complete".
    complete = Event

    # The rule to use to determine the inside of the polygon.
    inside_rule = Trait('winding', {
        'winding': FILL_STROKE,
        'oddeven': EOF_FILL_STROKE
    })

    # The points that make up this polygon.
    model = Instance(PolygonModel, ())

    # Convenience property to access the model's points.
    points = Property

    # The color of each vertex.
    vertex_color = ColorTrait("black")

    # The size of each vertex.
    vertex_size = Float(3.0)

    traits_view = View(
        Group('<component>', id='component'), Group('<links>', id='links'),
        Group('background_color',
              '_',
              'border_color',
              '_',
              'border_size',
              id='Box',
              style='custom'))

    colorchip_map = {'color': 'color', 'alt_color': 'border_color'}

    #--------------------------------------------------------------------------
    # Traits property accessors
    #--------------------------------------------------------------------------

    def _get_points(self):
        return self.model.points

    #--------------------------------------------------------------------------
    # 'Polygon' interface
    #--------------------------------------------------------------------------

    def reset(self):
        "Reset the polygon to the initial state"
        self.model.reset()
        self.event_state = 'normal'
        return

    #--------------------------------------------------------------------------
    # 'Component' interface
    #--------------------------------------------------------------------------

    def _draw_mainlayer(self, gc, view_bounds=None, mode="normal"):
        "Draw the component in the specified graphics context"
        self._draw_closed(gc)
        return

    #--------------------------------------------------------------------------
    # Protected interface
    #--------------------------------------------------------------------------

    def _is_in(self, point):
        """ Test if the point (an x, y tuple) is within this polygonal region.

        To perform the test, we use the winding number inclusion algorithm,
        referenced in the comp.graphics.algorithms FAQ
        (http://www.faqs.org/faqs/graphics/algorithms-faq/) and described in
        detail here:

        http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
        """
        point_array = array((point, ))
        vertices = array(self.model.points)
        winding = self.inside_rule == 'winding'
        result = points_in_polygon(point_array, vertices, winding)
        return result[0]

    #--------------------------------------------------------------------------
    # Private interface
    #--------------------------------------------------------------------------

    def _draw_closed(self, gc):
        "Draw this polygon as a closed polygon"

        if len(self.model.points) > 2:
            # Set the drawing parameters.
            gc.set_fill_color(self.background_color_)
            gc.set_stroke_color(self.border_color_)
            gc.set_line_width(self.border_size)
            gc.set_line_dash(self.border_dash)

            # Draw the path.
            gc.begin_path()
            gc.move_to(self.model.points[0][0] - self.x,
                       self.model.points[0][1] + self.y)
            offset_points = [(x - self.x, y + self.y)
                             for x, y in self.model.points]
            gc.lines(offset_points)

            gc.close_path()
            gc.draw_path(self.inside_rule_)

            # Draw the vertices.
            self._draw_vertices(gc)

        return

    def _draw_open(self, gc):
        "Draw this polygon as an open polygon"

        if len(self.model.points) > 2:
            # Set the drawing parameters.
            gc.set_fill_color(self.background_color_)
            gc.set_stroke_color(self.border_color_)
            gc.set_line_width(self.border_size)
            gc.set_line_dash(self.border_dash)

            # Draw the path.
            gc.begin_path()
            gc.move_to(self.model.points[0][0] - self.x,
                       self.model.points[0][1] + self.y)
            offset_points = [(x - self.x, y + self.y)
                             for x, y in self.model.points]
            gc.lines(offset_points)
            gc.draw_path(self.inside_rule_)

            # Draw the vertices.
            self._draw_vertices(gc)
        return

    def _draw_vertices(self, gc):
        "Draw the vertices of the polygon."

        gc.set_fill_color(self.vertex_color_)
        gc.set_line_dash(None)

        offset = self.vertex_size / 2.0
        offset_points = [(x + self.x, y + self.y)
                         for x, y in self.model.points]

        if hasattr(gc, 'draw_path_at_points'):
            path = gc.get_empty_path()
            path.rect(-offset, -offset, self.vertex_size, self.vertex_size)
            gc.draw_path_at_points(offset_points, path, FILL_STROKE)

        else:
            for x, y in offset_points:
                gc.draw_rect((x - offset, y - offset, self.vertex_size,
                              self.vertex_size), FILL)
        return
Exemplo n.º 18
0
class ANumericFilter ( HasPrivateTraits ):
    """ Defines an abstract base class for all NumericContext filters.
    """

    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # Name of the filter (implemented as a Property in each subclass):
    # name = Property

    # Event fired when filter is modified:
    updated = Event

    # Is the filter enabled or disabled?
    enabled = Bool( True, event = 'modified' )

    # Should the value, isbit and color traits be used?
    use_value = Bool( False, event = 'modified' )

    # Value to scale filter results by:
    value = Int( 1, event = 'modified' )

    # Is the value a bit number?
    is_bit = Bool( False, event = 'modified' )

#-- View related ---------------------------------------------------------------

    # Foreground color:
    foreground_color = ColorTrait( 'black', event = 'modified' )

    # Background color:
    background_color = ColorTrait( 'white', event = 'modified' )

    #---------------------------------------------------------------------------
    #  Handles the 'modified' pseudo-event being fired:
    #---------------------------------------------------------------------------

    def _modified_changed ( self ):
        """ Handles the 'modified' pseudo-event being fired.
        """
        self.updated = True

    #---------------------------------------------------------------------------
    #  Evaluates the result of the filter for the specified context:
    #---------------------------------------------------------------------------

    def __call__ ( self, context ):
        """ Evaluates the result of the filter for the specified context.
        """
        if self.enabled:
            result = self.evaluate( context )
            if (not self.use_value) or (result is None):
                return result
            result = not_equal( result, 0 )
            scale  = self.value
            if self.is_bit:
                scale = (1 << self.value)
            if scale == 1:
                return result
            return result * scale
        return None

    #---------------------------------------------------------------------------
    #  Sets the 'updated' trait True if the filter is affected by a change
    #  to any of the 'names' values in 'context'. Also returns whether the
    #  'updated' trait was set or not:
    #---------------------------------------------------------------------------

    def context_has_changed ( self, context, names ):
        """ Handles an update to the specified names within a specified context.
        """
        if self.context_changed( context, names ):
            self.updated = True
            return True

        return False

    #-- Overriddable Methods ---------------------------------------------------

    #---------------------------------------------------------------------------
    #  Evaluates the result of the filter for the specified context:
    #
    #  This method should be overridden by subclasses.
    #---------------------------------------------------------------------------

    def evaluate ( self, context ):
        """ Evaluates the result of the filter for the specified context.
        """
        return None

    #---------------------------------------------------------------------------
    #  Returns whether an update to a context affects the filter. It should
    #  return True if a change to any of the 'name' values in the specified
    #  'context' affects the filter, and False otherwise.
    #
    #  This method can be optionally overridden by a subclass if the filter
    #  it defines has dependencies on the contents of a context.
    #---------------------------------------------------------------------------

    def context_changed ( self, context, names ):
        """ Handles an update to the specified names within a specified context.
        """
        return False

    #---------------------------------------------------------------------------
    #  Returns the string representation of the filter:
    #
    #  This method can be optionally overridden by subclasses if they wish to
    #  return a different string representation of the filter.
    #---------------------------------------------------------------------------

    def __str__ ( self ):
        """ Returns the string representation of the filter.
        """
        return self.name
Exemplo n.º 19
0
class ViewportZoomTool(AbstractOverlay, ToolHistoryMixin, BaseZoomTool):
    """ Selects a range along the index or value axis.

    The user left-click-drags to select a region to zoom in.
    Certain keyboard keys are mapped to performing zoom actions as well.

    Implements a basic "zoom stack" so the user move go backwards and forwards
    through previous zoom regions.
    """

    # The selection mode:
    #
    # range:
    #   Select a range across a single index or value axis.
    # box:
    #   Perform a "box" selection on two axes.
    tool_mode = Enum("range", "box")  #Enum("box", "range")

    # Is the tool always "on"? If True, left-clicking always initiates
    # a zoom operation; if False, the user must press a key to enter zoom mode.
    always_on = Bool(False)

    #-------------------------------------------------------------------------
    # Zoom control
    #-------------------------------------------------------------------------

    # The axis to which the selection made by this tool is perpendicular. This
    # only applies in 'range' mode.
    axis = Enum("x", "y")

    #-------------------------------------------------------------------------
    # Interaction control
    #-------------------------------------------------------------------------

    # Enable the mousewheel for zooming?
    enable_wheel = Bool(True)

    # The mouse button that initiates the drag.
    drag_button = Enum("left", "right")

    # Conversion ratio from wheel steps to zoom factors.
    wheel_zoom_step = Float(.25)

    # The key press to enter zoom mode, if **always_on** is False.  Has no effect
    # if **always_on** is True.
    enter_zoom_key = Instance(KeySpec, args=("z", ))

    # The key press to leave zoom mode, if **always_on** is False.  Has no effect
    # if **always_on** is True.
    exit_zoom_key = Instance(KeySpec, args=("z", ))

    # Disable the tool after the zoom is completed?
    disable_on_complete = Bool(True)

    # The minimum amount of screen space the user must select in order for
    # the tool to actually take effect.
    minimum_screen_delta = Int(10)

    # The most that this tool will zoom in on the target.  Since zoom is the
    # ratio of the original bounds to the new bounds, a max_zoom value of 2.0
    # would make the tool stop once it had zoomed into a region half the size
    # of the original bounds.
    max_zoom = Float(inf)

    # The most that this tool will zoom out from the target.  For example,
    # a min_zoom of 0.2 would prevent the tool from showing a view zoomed
    # out more than 5 times from the original bounds.
    min_zoom = Float(-inf)

    #-------------------------------------------------------------------------
    # Appearance properties (for Box mode)
    #-------------------------------------------------------------------------

    # The pointer to use when drawing a zoom box.
    pointer = "magnifier"

    # The color of the selection box.
    color = ColorTrait("lightskyblue")

    # The alpha value to apply to **color** when filling in the selection
    # region.  Because it is almost certainly useless to have an opaque zoom
    # rectangle, but it's also extremely useful to be able to use the normal
    # named colors from Enable, this attribute allows the specification of a
    # separate alpha value that replaces the alpha value of **color** at draw
    # time.
    alpha = Trait(0.4, None, Float)

    # The color of the outside selection rectangle.
    border_color = ColorTrait("dodgerblue")

    # The thickness of selection rectangle border.
    border_size = Int(1)

    # The possible event states of this zoom tool.
    event_state = Enum("normal", "selecting")

    #------------------------------------------------------------------------
    # Key mappings
    #------------------------------------------------------------------------

    # The key that cancels the zoom and resets the view to the original defaults.
    cancel_zoom_key = Instance(KeySpec, args=("Esc", ))

    #------------------------------------------------------------------------
    # Private traits
    #------------------------------------------------------------------------

    # If **always_on** is False, this attribute indicates whether the tool
    # is currently enabled.
    _enabled = Bool(False)

    # the original numerical screen ranges
    _orig_position = Trait(None, List, Float)
    _orig_bounds = Trait(None, List, Float)

    # The (x,y) screen point where the mouse went down.
    _screen_start = Trait(None, None, Tuple)

    # The (x,,y) screen point of the last seen mouse move event.
    _screen_end = Trait(None, None, Tuple)

    def __init__(self, component=None, *args, **kw):
        # Support AbstractController-style constructors so that this can be
        # handed in the component it will be overlaying in the constructor
        # without using kwargs.
        self.component = component
        super(ViewportZoomTool, self).__init__(*args, **kw)
        self._reset_state_to_current()

        if self.tool_mode == "range":
            i = self._get_range_index()
            self._orig_position = self.component.view_position[i]
            self._orig_bounds = self.component.view_bounds[i]
        else:
            self._orig_position = self.component.view_position
            self._orig_bounds = self.component.view_bounds
        return

    def enable(self, event=None):
        """ Provides a programmatic way to enable this tool, if
        **always_on** is False.

        Calling this method has the same effect as if the user pressed the
        **enter_zoom_key**.
        """
        if self.component.active_tool != self:
            self.component.active_tool = self
        self._enabled = True
        if event and event.window:
            event.window.set_pointer(self.pointer)
        return

    def disable(self, event=None):
        """ Provides a programmatic way to enable this tool, if **always_on**
        is False.

        Calling this method has the same effect as if the user pressed the
        **exit_zoom_key**.
        """
        self.reset()
        self._enabled = False
        if self.component.active_tool == self:
            self.component.active_tool = None
        if event and event.window:
            event.window.set_pointer("arrow")
        return

    def reset(self, event=None):
        """ Resets the tool to normal state, with no start or end position.
        """
        self.event_state = "normal"
        self._screen_start = None
        self._screen_end = None

    def deactivate(self, component):
        """ Called when this is no longer the active tool.
        """
        # Required as part of the AbstractController interface.
        return self.disable()

    def normal_left_down(self, event):
        """ Handles the left mouse button being pressed while the tool is
        in the 'normal' state.

        If the tool is enabled or always on, it starts selecting.
        """
        if self.always_on or self._enabled:
            # we need to make sure that there isn't another active tool that we will
            # interfere with.
            if self.drag_button == "left":
                self._start_select(event)
        return

    def normal_right_down(self, event):
        """ Handles the right mouse button being pressed while the tool is
        in the 'normal' state.

        If the tool is enabled or always on, it starts selecting.
        """
        if self.always_on or self._enabled:
            if self.drag_button == "right":
                self._start_select(event)
        return

    def normal_mouse_wheel(self, event):
        """ Handles the mouse wheel being used when the tool is in the 'normal'
        state.

        Scrolling the wheel "up" zooms in; scrolling it "down" zooms out.
        self.component is the viewport
        self.component.component is the canvas

        """
        if self.enable_wheel and event.mouse_wheel != 0:

            position = self.component.view_position
            scale = self.component.zoom
            transformed_x = event.x / scale + position[0]
            transformed_y = event.y / scale + position[1]

            # Calculate zoom
            if event.mouse_wheel < 0:
                zoom = 1.0 / (1.0 + 0.5 * self.wheel_zoom_step)
                new_zoom = self.component.zoom * zoom
            elif event.mouse_wheel > 0:
                zoom = 1.0 + 0.5 * self.wheel_zoom_step
                new_zoom = self.component.zoom * zoom

            if new_zoom < self.min_zoom:
                new_zoom = self.min_zoom
                zoom = new_zoom / self.component.zoom
            elif new_zoom > self.max_zoom:
                new_zoom = self.max_zoom
                zoom = new_zoom / self.component.zoom
            self.component.zoom = new_zoom

            x_pos = transformed_x - (transformed_x - position[0]) / zoom
            y_pos = transformed_y - (transformed_y - position[1]) / zoom

            self.component.set(view_position=[x_pos, y_pos],
                               trait_change_notify=False)
            bounds = self.component.view_bounds
            self.component.view_bounds = [bounds[0] / zoom, bounds[1] / zoom]

            event.handled = True
            self.component.request_redraw()
        return

    def _component_changed(self):
        self._reset_state_to_current()
        return

    #------------------------------------------------------------------------
    # Implementation of PlotComponent interface
    #------------------------------------------------------------------------
    def _activate(self):
        """ Called by PlotComponent to set this as the active tool.
        """
        self.enable()

    #------------------------------------------------------------------------
    # implementations of abstract methods on ToolHistoryMixin
    #------------------------------------------------------------------------
    def _reset_state_to_current(self):
        """ Clears the tool history, and sets the current state to be the
        first state in the history.
        """
        if self.tool_mode == "range":
            i = self._get_range_index()
            self._reset_state((self.component.view_position[i],
                               self.component.view_bounds[i]))
        else:
            self._reset_state(
                (self.component.view_position, self.component.view_bounds))
Exemplo n.º 20
0
class ErrorEnvelopeOverlay(AbstractOverlay):
    _cache_valid = False
    _screen_cache_valid = False

    upper = Array
    lower = Array
    use_downsampling = False
    line_color = black_color_trait
    region_color = ColorTrait((0.5, 0.5, 0.5, 0.5))
    use_region = False
    xs = None

    def invalidate(self):
        self._cache_valid = False
        self._screen_cache_valid = False

    def _gather_points(self):
        if not self._cache_valid:
            index = self.component.index
            value = self.component.value
            if not index or not value:
                return

            xs = self.xs
            if xs is None:
                xs = index.get_data()

            ls = self.lower
            us = self.upper

            self._cached_data_pts_u = [array((xs, us)).T]
            self._cached_data_pts_l = [array((xs, ls)).T]

            self._cache_valid = True

        return

    def get_screen_points(self):
        self._gather_points()
        if self.use_downsampling:
            return self._downsample()
        else:
            return (self.component.map_screen(self._cached_data_pts_u),
                    self.component.map_screen(self._cached_data_pts_l))

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        with gc:
            gc.clip_to_rect(0, 0, other_component.width,
                            other_component.height)
            upts, lpts = self.get_screen_points()
            if self.use_region:
                upts = upts[0]
                lpts = lpts[0]

                uxs, uys = upts.T
                lxs, lys = lpts.T

                x1 = x4 = uxs.min()
                x2 = x3 = uxs.max()
                y1 = uys[0]
                y2 = uys[-1]
                y3 = lys[-1]
                y4 = lys[0]

                gc.move_to(x1, y1)
                gc.line_to(x2, y2)
                gc.line_to(x3, y3)
                gc.line_to(x4, y4)
                # gc.set_fill_color((1, 0.4, 0.1, 0.5))
                gc.set_fill_color(self.region_color_)
                gc.fill_path()

            else:
                gc.set_line_dash((5, 5))
                gc.set_stroke_color(self.line_color_)
                self._render_line(gc, upts)
                self._render_line(gc, lpts)

    def _render_line(self, gc, points):
        for ary in points:
            if len(ary) > 0:
                gc.begin_path()
                gc.lines(ary)
                gc.stroke_path()

    def _downsample(self):
        if not self._screen_cache_valid:
            self._cached_screen_pts_u = self.component.map_screen(
                self._cached_data_pts_u)[0]
            self._cached_screen_pts_l = self.component.map_screen(
                self._cached_data_pts_l)[0]

            self._screen_cache_valid = True

            for pt_arrays in (self._cached_screen_pts_l,
                              self._cached_screen_pts_u):
                r, c = pt_arrays.shape
                # some boneheaded short-circuits
                m = self.component.index_mapper
                total_numpoints = r * c
                if (total_numpoints < 400) or (total_numpoints <
                                               m.high_pos - m.low_pos):
                    return [self._cached_screen_pts_l
                            ], [self._cached_screen_pts_u]

                # the new point array and a counter of how many actual points we've added
                # to it
                new_arrays = []
                for pts in pt_arrays:
                    new_pts = zeros(pts.shape, "d")
                    numpoints = 1
                    new_pts[0] = pts[0]

                    last_x, last_y = pts[0]
                    for x, y in pts[1:]:
                        if (x - last_x)**2 + (y - last_y)**2 > 2:
                            new_pts[numpoints] = (x, y)
                            last_x = x
                            last_y = y
                            numpoints += 1

                    new_arrays.append(new_pts[:numpoints])

        return [self._cached_screen_pts_l], [self._cached_screen_pts_u]
Exemplo n.º 21
0
class Line(Component):
    """A line segment component"""

    # Event fired when the points are no longer updating.
    # PZW: there seems to be a missing defn here; investigate.

    # An event to indicate that the point list has changed
    updated = Event

    # The color of the line.
    line_color = ColorTrait("black")

    # The dash pattern for the line.
    line_dash = Any

    # The width of the line.
    line_width = border_size_trait(1)

    # The points that make up this polygon.
    points = List  # List of Tuples

    # The color of each vertex.
    vertex_color = ColorTrait("black")

    # The size of each vertex.
    vertex_size = Float(3.0)

    # Whether to draw the path closed, with a line back to the first point
    close_path = Bool(True)

    # -------------------------------------------------------------------------
    # 'Line' interface
    # -------------------------------------------------------------------------

    def reset(self):
        "Reset the polygon to the initial state"

        self.points = []
        self.event_state = "normal"
        self.updated = self

    # -------------------------------------------------------------------------
    # 'Component' interface
    # -------------------------------------------------------------------------

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        "Draw this line in the specified graphics context"
        if len(self.points) > 1:
            with gc:
                # Set the drawing parameters.
                gc.set_stroke_color(self.line_color_)
                gc.set_line_dash(self.line_dash)
                gc.set_line_width(self.line_width)

                # Draw the path as lines.
                gc.begin_path()
                offset_points = [(x, y) for x, y in self.points]
                offset_points = resize(array(offset_points),
                                       (len(self.points), 2))
                gc.lines(offset_points)
                if self.close_path:
                    gc.close_path()
                gc.draw_path(STROKE)

        if len(self.points) > 0:
            with gc:
                # Draw the vertices.
                self._draw_points(gc)

    # -------------------------------------------------------------------------
    # Private interface
    # -------------------------------------------------------------------------

    def _draw_points(self, gc):
        "Draw the points of the line"

        # Shortcut out if we would draw transparently.
        if self.vertex_color_[3] != 0:
            with gc:
                gc.set_fill_color(self.vertex_color_)
                gc.set_line_dash(None)

                offset_points = [(x, y) for x, y in self.points]
                offset_points = resize(array(offset_points),
                                       (len(self.points), 2))
                offset = self.vertex_size / 2.0
                if hasattr(gc, "draw_path_at_points"):
                    path = gc.get_empty_path()
                    path.rect(-offset, -offset, self.vertex_size,
                              self.vertex_size)
                    gc.draw_path_at_points(offset_points, path, FILL_STROKE)
                else:
                    for x, y in offset_points:
                        gc.draw_rect(
                            (
                                x - offset,
                                y - offset,
                                self.vertex_size,
                                self.vertex_size,
                            ),
                            FILL,
                        )
Exemplo n.º 22
0
class Annotater(Component):

    color = ColorTrait((0.0, 0.0, 0.0, 0.2))
    style = PrefixList(["rectangular", "freehand"],
                       default_value="rectangular")
    annotation = Event

    traits_view = View(
        Group("<component>", id="component"),
        Group("<links>", id="links"),
        Group("color", "style", id="annotater", style="custom"),
    )

    # -------------------------------------------------------------------------
    # Mouse event handlers
    # -------------------------------------------------------------------------

    def _left_down_changed(self, event):
        event.handled = True
        self.window.mouse_owner = self
        self._cur_x, self._cur_y = event.x, event.y
        self._start_x, self._start_y = event.x, event.y

    def _left_up_changed(self, event):
        event.handled = True
        self.window.mouse_owner = None
        if self.xy_in_bounds(event):
            self.annotation = (
                min(self._start_x, event.x),
                min(self._start_y, event.y),
                abs(self._start_x - event.x),
                abs(self._start_y - event.y),
            )
        self._start_x = self._start_y = self._cur_x = self._cur_y = None
        self.redraw()

    def _mouse_move_changed(self, event):
        event.handled = True
        if self._start_x is not None:
            x = max(min(event.x, self.right - 1.0), self.x)
            y = max(min(event.y, self.top - 1.0), self.y)
            if (x != self._cur_x) or (y != self._cur_y):
                self._cur_x, self._cur_y = x, y
                self.redraw()

    # -------------------------------------------------------------------------
    # "Component" interface
    # -------------------------------------------------------------------------

    def _draw(self, gc):
        "Draw the contents of the control"
        if self._start_x is not None:
            with gc:
                gc.set_fill_color(self.color_)
                gc.begin_path()
                gc.rect(
                    min(self._start_x, self._cur_x),
                    min(self._start_y, self._cur_y),
                    abs(self._start_x - self._cur_x),
                    abs(self._start_y - self._cur_y),
                )
                gc.fill_path()
        return
Exemplo n.º 23
0
class EditField(Component):
    """ A simplified single-line editable text entry field for Enable.
    """

    #---------------------------------------------------------------------
    # Traits
    #---------------------------------------------------------------------

    # The text on display - with appropriate line breaks
    text = Property(depends_on=['_text_changed'])

    # The list of characters in this text field
    _text = List()

    # Even that fires when the text changes
    _text_changed = Event

    # The current index into the list of characters
    # This corresponds to the user's position
    index = Int(0)

    # Should we draw the cursor in the box?  This only occurs
    # when someone is in edit mode.
    _draw_cursor = Bool(False)

    # The font we're using - must be monospaced
    font = KivaFont("Courier 12")

    # Toggle normal/highlighted color of the text
    text_color = RGBAColor((0, 0, 0, 1.0))
    highlight_color = RGBAColor((.65, 0, 0, 1.0))

    # Toggle normal/highlighted background color
    bgcolor = RGBAColor((1.0, 1.0, 1.0, 1.0))
    highlight_bgcolor = ColorTrait("lightgray")

    # The text offset
    offset = Int(3)

    # The object to use to measure text extents
    metrics = Any

    # Events that get fired on certain key pressed events
    accept = Event
    cancel = Event

    # Can we edit this text field?
    can_edit = Bool(True)

    #---------------------------------------------------------------------
    # Public methods
    #---------------------------------------------------------------------

    def __init__(self, *args, **kwargs):
        super(EditField, self).__init__(*args, **kwargs)

        if self.metrics is None:
            self.metrics = font_metrics_provider()

        # If no bounds have been set, make sure it is wide enough to
        # display the text
        if self.height == 0 and self.width == 0 and len(self._text) > 0:
            self.update_bounds()

    def update_bounds(self):
        w, h = self.metrics.get_text_extent(self.text)[2:4]
        self.width = w + 2 * self.offset
        self.height = h + 2 * self.offset

    #---------------------------------------------------------------------
    # Interactor interface
    #---------------------------------------------------------------------

    def normal_left_dclick(self, event):
        # If we can't edit, just return.
        if not self.can_edit:
            return

        event.window.set_pointer('ibeam')
        self.event_state = 'edit'
        self._acquire_focus(event.window)
        event.handled = True
        self.request_redraw()

    def edit_left_up(self, event):
        self.event_state = "normal"
        event.handled = True
        self.request_redraw()

    def normal_character(self, event):
        # handle normal text entry
        char = event.character
        old_len = len(self._text)

        self._text.insert(self.index, char)
        self.index += 1
        self._text_changed = True

        if old_len != len(self._text):
            self.update_bounds()

        event.handled = True
        self.invalidate_draw()
        self.request_redraw()

    def normal_key_pressed(self, event):
        char = event.character
        old_len = len(self._text)

        #Normal characters
        if len(char) == 1:
            # leave unhandled, and let character event be generated
            return

        #Deletion
        elif char == "Backspace":
            if self.index > 0:
                del self._text[self.index - 1]
                self.index -= 1
                self._text_changed = True
        elif char == "Delete":
            if self.index < len(self._text):
                del self._text[self.index]
                self._text_changed = True

        #Cursor Movement
        elif char == "Left":
            if self.index > 0:
                self.index -= 1
        elif event.character == "Right":
            if self.index < len(self._text):
                self.index += 1
        elif event.character == "Home":
            self.index = 0
        elif event.character == "End":
            self.index = len(self._text)
        elif event.character == "Enter":
            self.accept = event
        elif char == "Escape":
            self.cancel = event

        if old_len != len(self._text):
            self.update_bounds()

        event.handled = True
        self.invalidate_draw()
        self.request_redraw()

    #---------------------------------------------------------------------
    # Component interface
    #---------------------------------------------------------------------

    def _draw_mainlayer(self, gc, view_bounds, mode="default"):

        gc.save_state()

        self.set_font(gc)
        x = self.x + self.offset
        y = self.y
        gc.show_text_at_point(self.text, x, y)

        if self._draw_cursor:
            x += self.metrics.get_text_extent(self.text[:self.index])[2]
            y2 = self.y2 - self.offset
            gc.set_line_width(2)
            gc.set_stroke_color((0, 0, 0, 1.0))
            gc.begin_path()
            gc.move_to(x, y)
            gc.line_to(x, y2)
            gc.stroke_path()

        gc.restore_state()

    def set_font(self, gc):
        gc.set_font(self.font)
        gc.set_fill_color(self.text_color)

    #---------------------------------------------------------------------
    # TextField interface
    #---------------------------------------------------------------------

    def _acquire_focus(self, window):
        self._draw_cursor = True
        self.border_visible = True
        window.focus_owner = self
        window.on_trait_change(self._focus_owner_changed, "focus_owner")
        self.request_redraw()

    def _focus_owner_changed(self, obj, name, old, new):
        if old == self and new != self:
            obj.on_trait_change(self._focus_owner_changed,
                                "focus_owner",
                                remove=True)
            self._draw_cursor = False
            self.border_visible = False
            self.request_redraw()

    #---------------------------------------------------------------------
    # Property get/set and Trait event handlers
    #---------------------------------------------------------------------

    def _get_text(self):
        """ Return the text to be displayed in the text field. """
        return "".join(self._text)

    def _set_text(self, val):
        """ Set the _text given a string. """
        self.index = 0
        if val == "":
            self._text = []
        else:
            self._text = list(val)

    def _accept_changed(self, old, new):
        new.window.focus_owner = None

    def _cancel_changed(self, old, new):
        new.window.focus_owner = None
Exemplo n.º 24
0
class LabelTraits(HasTraits):

    text = Str
    font = font_trait
    text_position = position_trait("left")
    color = ColorTrait("black")
    shadow_color = ColorTrait("white")
    style = engraving_trait

    #image = image_trait
    image_position = position_trait("left")
    image_orientation = orientation_trait

    spacing_height = spacing_trait
    spacing_width = spacing_trait
    padding_left = padding_trait
    padding_right = padding_trait
    padding_top = padding_trait
    padding_bottom = padding_trait
    margin_left = margin_trait
    margin_right = margin_trait
    margin_top = margin_trait
    margin_bottom = margin_trait
    border_size = border_size_trait
    border_color = ColorTrait("black")
    bg_color = ColorTrait("clear")

    enabled = Bool(True)
    selected = Bool(False)

    #---------------------------------------------------------------------------
    #  Trait view definitions:
    #---------------------------------------------------------------------------

    traits_view = View(
        Group('enabled', 'selected', id='component'),
        Group('text',
              ' ',
              'font',
              ' ',
              'color',
              ' ',
              'shadow_color',
              ' ',
              'style',
              id='text',
              style='custom'),
        Group('bg_color{Background Color}',
              '_',
              'border_color',
              '_',
              'border_size',
              id='border',
              style='custom'),
        Group(
            'text_position',
            '_',
            'image_position',
            '_',
            'image_orientation',
            ' ',  #'image',
            id='position',
            style='custom'),
        Group('spacing_height',
              'spacing_width',
              '_',
              'padding_left',
              'padding_right',
              'padding_top',
              'padding_bottom',
              '_',
              'margin_left',
              'margin_right',
              'margin_top',
              'margin_bottom',
              id='margin'))