Esempio n. 1
0
async def show_pleple_window(name, plot_info, multi_resolution_signals,
                             plot_gl_resources, plot_gl_canvas) -> IMGui[None]:
    with window(name):
        window_width, window_height = im.get_content_region_available()
        window_width, window_height = int(window_width), int(window_height)

        if (window_width, window_height) != (plot_gl_canvas.width_px,
                                             plot_gl_canvas.height_px):
            print("\t### resizing canvas  {} -> {}".format(
                (plot_gl_canvas.width_px, plot_gl_canvas.height_px),
                (window_width, window_height)),
                  flush=True)
            del plot_gl_canvas
            plot_gl_canvas = aplt.init_plot_canvas(window_width, window_height)
            await emit(___new_canvas_(plot_gl_canvas))

        canvas_width = plot_gl_canvas.width_px
        canvas_height = plot_gl_canvas.height_px

        should_redraw = True
        if should_redraw:
            aplt.draw_plot_to_canvas_multires(
                plot_gl_canvas,
                plot_info,
                multi_resolution_signals,
                plot_gl_resources,
                line_color=aplt.WHITE,
                background_color=aplt.TRANSPARENT_BLACK)

        im.image(plot_gl_canvas.texture_id,
                 canvas_width,
                 canvas_height,
                 uv0=(0, 1),
                 uv1=(1, 0))
Esempio n. 2
0
async def signal_plot_window(
        plot_box_state: PlotBoxState, m_inputs: List[Maybe[Signal]],
        ui_settings: Dict[str, Any]) -> Eff[[ACTIONS], IMGui[None]]:

    m_signal = m_inputs[0]
    assert ((type(m_signal.val) == Signal)
            if m_signal.is_Just() else True), repr(m_signal)

    PLOT_WINDOW_FLAGS = 0 if ui_settings[
        'plot_window_movable'] else im.WINDOW_NO_MOVE
    plot_name = "Plot (id={id})###{id}".format(id=plot_box_state.id_)

    with window(name=plot_name, flags=PLOT_WINDOW_FLAGS):
        plot_width = -1.  # auto
        plot_height = im.get_content_region_available().y - 20

        await signal_plot(plot_box_state,
                          m_signal,
                          width=plot_width,
                          height=plot_height,
                          ui_settings=ui_settings)

        if m_signal.is_Nothing():
            im.text(" ")
        elif m_signal.is_Just():
            signal = m_signal.val
            im.text_colored(str(signal), 0.8, 0.8, 0.8)

        return get_window_rect()
Esempio n. 3
0
async def signal_source_window(
        source_state: SourceState, signal_data: PMap_[SignalId, Signal],
        signal_names: PMap_[SignalId, str]) -> Eff[[ACTIONS], IMGui[None]]:

    source_name = "Source (id={id})###{id}".format(id=source_state.id_)

    with window(name=source_name):

        # signal selector

        if len(signal_data) > 0:
            signal_ids = signal_data.keys()
            visible_signal_names = {
                sig_id: signal_names[sig_id]
                for sig_id in signal_ids
            }

            # disambiguate signals with duplicate names
            duplicated_signal_names = {
                sig_id: sig_name
                for (sig_id, sig_name) in visible_signal_names.items()
                if list(visible_signal_names.values()).count(sig_name) > 1
            }
            disambiguated_signal_names = {
                sig_id: "{name} ({id})".format(name=sig_name, id=sig_id)
                for (sig_id, sig_name) in duplicated_signal_names.items()
            }
            visible_signal_names.update(disambiguated_signal_names)
            # now `visible_signal_names` is an invertible mapping
            labels = sorted(visible_signal_names.values())
            prev_o_selected_signal_name = None if source_state.is_Empty(
            ) else visible_signal_names[source_state.signal_id]

            changed, o_selected_signal_name = str_combo_with_none(
                "signal", prev_o_selected_signal_name, labels)
            if changed:
                if o_selected_signal_name != None:
                    # invert `visible_signal_names` to find the signal id
                    signal_name_to_id = {
                        sig_name: sig_id
                        for (sig_id, sig_name) in visible_signal_names.items()
                    }
                    selected_signal_id = signal_name_to_id[
                        o_selected_signal_name]
                    await emit(
                        SourceAction.SelectSignal(id_=source_state.id_,
                                                  signal_id=selected_signal_id)
                    )
                else:
                    await emit(SourceAction.SetEmpty(id_=source_state.id_))
        else:
            im.text("No signals available")

        return util.get_window_rect()
Esempio n. 4
0
async def filter_box_window(filter_box_state: FilterBoxState,
                            ui_settings) -> Eff[[ACTIONS], IMGui[None]]:

    name = None
    if filter_box_state.filter_state.is_Filter():
        filter_id = filter_box_state.filter_state.filter_id
        filter = available_filters[filter_id]
        name = "{f_name} (id={id})###{id}".format(f_name=filter.name,
                                                  id=filter_box_state.id_)
    else:
        name = "Filter###{id}".format(id=filter_box_state.id_)

    with window(name=name):

        # # filter type combo
        # filter_ids = sorted(available_filters.keys())
        # o_filter_id = None if filter_box_state.filter_state.is_NoFilter() else  filter_box_state.filter_state.filter_id

        # changed, o_filter_id = str_combo_with_none("filter", o_filter_id, filter_ids)
        # if changed:
        # 	if o_filter_id != None:
        # 		await emit( SetFilter(id_=filter_box_state.id_, filter_id=o_filter_id) )
        # 	else:
        # 		await emit( UnsetFilter(id_=filter_box_state.id_) )

        # param inputs
        slider_power = ui_settings['filter_slider_power']

        if filter_box_state.filter_state.is_Filter():

            filter_id = filter_box_state.filter_state.filter_id
            filter_params = filter_box_state.filter_state.params
            filter = available_filters[filter_id]

            for param_name in sorted(filter.func_sig):
                changed, new_param_val = im.slider_float(
                    param_name,
                    filter_params[param_name],
                    min_value=0.001,
                    max_value=95.,
                    power=slider_power)
                if changed:
                    await emit(
                        FilterAction.SetParam(id_=filter_box_state.id_,
                                              name=param_name,
                                              value=new_param_val))

        else:
            im.text("No filter selected")

        return util.get_window_rect()
Esempio n. 5
0
def debug_window() -> IMGui[None]:
    with window(name="debug"):
        debug_window_draw_start_t_s = glfw.get_time()

        if debug_dict['crash'] is not None:
            origin = debug_dict['crash']['origin']
            cause = debug_dict['crash']['cause']
            exception = debug_dict['crash']['exception']
            with window(name="Crash report"):
                im.text(
                    'Exception raised during `{}`. State rolled back'.format(
                        origin))
                im.text('Caused by:')
                im.text('\t' + repr(cause))

                im.text('\n' + str(exception.__cause__) if exception.
                        __cause__ is not None else '')
                for line in traceback.format_tb(exception.__traceback__):
                    im.text(line)
                im.text("{}: {}".format(
                    type(exception).__qualname__,
                    str.join(', ', map(repr, exception.args))))

                if im.button('close'):
                    debug_dict['crash'] = None

        # print some general app state
        # im.text("actions: "+str(frame_actions))
        im.text("mouse:   " + str(get_mouse_position()))
        im.text("click:   " + str(im.is_mouse_clicked(button=0)))
        im.text("down:    " + str(im.is_mouse_down(button=0)))
        im.text(
            "cl+down: " +
            str(im.is_mouse_clicked(button=0) and im.is_mouse_down(button=0)))
        im.text("drag:    " + str(im.is_mouse_dragging(button=0)))
        im.text("drag-d:  " + str(im.get_mouse_drag_delta()))
        im.new_line()

        # print the avg durations of ranges set with `debug_log_time`
        show_avg_durations_of_recorded_ranges()

        # print the values in dicts logged with `debug_log_dict`
        for name, sequence in debug_dict['sequences'].items():
            im.new_line()
            show_sequence(sequence, name=name)

        # print the values in dicts logged with `debug_log_dict`
        for name, dictionary in debug_dict['dicts'].items():
            im.new_line()
            # d = order_dict_by_key(stringify_keys(flatten_dict(dictionary)))

            show_varied_dict(dictionary, name=name)

        # print all other values in debug (set with `debug_log`)
        im.new_line()
        show_varied_dict(debug_dict['values'])

        # print how long it took to draw the debug window (hehe)
        debug_window_draw_end_t_s = glfw.get_time()
        debug_window_draw_dur_ms = (debug_window_draw_end_t_s -
                                    debug_window_draw_start_t_s) * 1000
        im.new_line()
        im.text(
            "drawing debug took {:4.1f} ms".format(debug_window_draw_dur_ms))
Esempio n. 6
0
async def draw() -> Eff[[ACTIONS], None]:
    global state

    im.show_metrics_window()
    im.show_test_window()

    # ------------------------
    # t_flags = 0
    # t_flags = (
    # 	  im.WINDOW_NO_TITLE_BAR
    # 	| im.WINDOW_NO_MOVE
    # 	| im.WINDOW_NO_RESIZE
    # 	| im.WINDOW_NO_COLLAPSE
    # 	| im.WINDOW_NO_FOCUS_ON_APPEARING
    # 	| im.WINDOW_NO_BRING_TO_FRONT_ON_FOCUS
    # )
    # with window(name="test", flags=t_flags):
    # 	im.button("bloop")
    # 	pos = util.point_offset(im.get_window_position(), im.Vec2(40, 80))
    # 	im.set_next_window_position(pos.x, pos.y)
    # 	with window(name="a window"):
    # 		im.text("I'm a window")

    # 	top_left = im.get_item_rect_min()
    # 	size = im.get_item_rect_size()
    # 	bottom_right = util.point_offset(top_left, size)
    # 	im.text('TL: '+str(top_left))
    # 	im.text('BR: '+str(bottom_right))
    # 	util.add_rect(im.get_window_draw_list(), util.Rect(top_left, bottom_right), (1.,1.,1.,1.))

    debug_log("test_drew", False)
    with window("test") as (expanded, _):
        only_draw_if(expanded)

        debug_log("test_drew", True)  # only_draw_if didn't abort, overwrite
        US = ui['settings']

        opts = ['first', 'second', 'third']
        default_state = ('no_selection', None)

        US.setdefault('selectable_state', default_state)
        US.setdefault('selectable_added', [])
        if not im.is_window_focused():
            US['selectable_state'] = default_state

        changed, selection_changed, selectable_state = double_click_listbox(
            US['selectable_state'], opts)
        if changed:
            US['selectable_state'] = selectable_state

        o_ix = selectable_state[1]
        im.text_colored(
            "[ {!s:<10} ] {}".format(opts[o_ix] if o_ix is not None else "---",
                                     "(!)" if selection_changed else ""),
            *(0.3, 0.8, 0.5))
        im.text("")
        im.text("{!r:<5} {!r:<5} {}".format(changed, selection_changed,
                                            selectable_state))

        if selectable_state[0] == 'double_clicked':
            US['selectable_added'].append(opts[selectable_state[1]])
        im.text(str(US['selectable_added']))

        c = im.is_mouse_clicked()
        dc = im.is_mouse_double_clicked()
        im.text("{!r:<5} {!r:<5} {!r:<5}".format(c, dc, c and dc))
        im.text("focused: " + repr(im.is_window_focused()))

    with window(name="signals"):
        if im.button("load example"):
            await emit(FileAction.Load(filename=example_file_path))

        if len(state.data.signals) > 0:

            def right_pad(s: str, limit: int) -> str:
                n_spaces = max(0, limit - len(s))
                return s + (' ' * n_spaces)

            for sig_id, sig_name in sorted(state.data.signal_names.items(),
                                           key=lambda pair: pair[1]):
                im.text_colored(right_pad(sig_name, 5), 0.2, 0.8, 1)
                im.same_line()
                signal = state.data.signals[sig_id]
                im.text(str(signal))
        else:
            im.text("No signals loaded")

    # -------------------------
    # with window(name="modules"):
    # 	modules = sorted(
    #		rlu.all_modules(dir=pathlib.Path.cwd()),
    #		key=lambda mod: (getattr(mod, '__reload_incarnation__', -1), mod.__name__)
    #	)
    # 	for mod in modules:
    # 		incarnation_text = str(getattr(mod, '__reload_incarnation__', '-'))
    # 		im.text("{mod}[{inc}]".format(mod=mod.__name__, inc=incarnation_text))

    with window(name="settings"):
        ui_settings = ui['settings']
        changed, move = im.checkbox("move plots",
                                    ui_settings['plot_window_movable'])
        if changed:
            ui_settings['plot_window_movable'] = move

        # im.same_line()
        changed, option = str_combo(
            "resample", ui_settings['plot_resample_function'],
            ['numpy_interp', 'scipy_zoom', 'crude_downsample'])
        if changed:
            ui_settings['plot_resample_function'] = option

        # im.same_line()
        changed, option = str_combo("plots", ui_settings['plot_draw_function'],
                                    ['imgui', 'manual'])
        if changed:
            ui_settings['plot_draw_function'] = option

        changed, val = im.slider_float('filter_slider_power',
                                       ui_settings['filter_slider_power'],
                                       min_value=1.,
                                       max_value=5.,
                                       power=1.0)
        if changed:
            ui_settings['filter_slider_power'] = val

        if im.button("reload"):
            await emit(AppRunnerAction.Reload())

        # im.same_line()
        # im.button("bla bla bla")

        # im.same_line()
        # im.button("ple ple ple")

        im.text("state | ")

        im.same_line()
        if im.button("dump##state"):
            await emit(AppStateAction.SaveState)

        im.same_line()
        if im.button("load##state"):
            await emit(AppStateAction.LoadState)

        im.same_line()
        if im.button("reset##state"):
            await emit(AppStateAction.ResetState)

        im.text("history | ")

        im.same_line()
        if im.button("dump##history"):
            await emit(AppStateAction.SaveUserActionHistory)

        im.same_line()
        if im.button("load##history"):
            await emit(AppStateAction.LoadUserActionHistory)

        im.same_line()
        if im.button("reset##history"):
            await emit(AppStateAction.ResetUserActionHistory)

        im.same_line()
        if im.button("run##history"):
            await emit(AppStateAction.RunHistory)

    # TODO: Window positions can theoretically be accessed
    # after being drawn using internal APIs.
    # See:
    #	imgui_internal.h > ImGuiWindow (search "struct IMGUI_API ImGuiWindow")
    #	imgui.cpp        > ImGui::GetCurrentContext()
    #
    # (sort-of pseudocode example)
    #
    # foo_id = None
    #
    # with window("foo"):
    # 	foo_id = GetCurrentWindow().ID
    # 	...
    #
    # ...
    #
    # with window("accessing other windows"):
    # 	windows = imgui.GetCurrentContext().Windows
    # 	foo_win = windows[ windows.find(lambda win: win.ID = foo_id) ]
    # 	im.text( "pos:{}, size:{}".format(foo_win.Pos, foo_win.Size) )

    # ----------------------------
    # await ng.graph_window(state.graph)

    prev_color_window_background = im.get_style().color(
        im.COLOR_WINDOW_BACKGROUND)

    im.set_next_window_position(0, 100)
    with color({im.COLOR_WINDOW_BACKGROUND: (0., 0., 0., 0.05)}), \
      window(name="nodes",
       flags = (
          im.WINDOW_NO_TITLE_BAR
        # | im.WINDOW_NO_MOVE
        # | im.WINDOW_NO_RESIZE
        | im.WINDOW_NO_COLLAPSE
        | im.WINDOW_NO_FOCUS_ON_APPEARING
        | im.WINDOW_NO_BRING_TO_FRONT_ON_FOCUS
       )
      ):
        box_positions = {}
        inputs = ng.get_inputs(state.graph, state.data.box_outputs)

        with color({im.COLOR_WINDOW_BACKGROUND: prev_color_window_background}):

            # source boxes
            for (id_, box_state) in state.source_boxes.items():
                pos = await signal_source_window(box_state, state.data.signals,
                                                 state.data.signal_names)
                box_positions[id_] = pos

            # filter boxes
            for (id_, box_state) in state.filter_boxes.items():
                pos = await filter_box_window(box_state,
                                              ui_settings=ui_settings)
                box_positions[id_] = pos

            # signal plot 1
            for (id_, box_state) in state.plots.items():
                pos = await signal_plot_window(box_state,
                                               inputs[id_],
                                               ui_settings=ui_settings)
                box_positions[id_] = pos

        # connections between boxes
        link_selection = state.link_selection

        prev_cursor_screen_pos = im.get_cursor_screen_position()

        # get slot coords and draw slots
        with color({im.COLOR_CHECK_MARK: (0, 0, 0, 100 / 255)}):
            draw_list = im.get_window_draw_list()
            SPACING = 20.
            slot_center_positions = {}

            for (id_, position) in box_positions.items():
                node = state.graph.nodes[id_]

                left_x = position.top_left.x
                right_x = position.bottom_right.x
                top_y = position.top_left.y

                for slot_ix in range(node.n_inputs):
                    pos = im.Vec2(left_x - 20 - 3,
                                  top_y + 30 + slot_ix * SPACING)
                    im.set_cursor_screen_position(pos)

                    slot = ng.InputSlotId(id_, slot_ix)
                    was_selected = (slot == link_selection.dst_slot)

                    changed, selected = im.checkbox(
                        "##in{}{}".format(id_, slot_ix), was_selected)
                    if changed:
                        await emit(LinkSelectionAction.ClickInput(slot))

                    center_pos = util.rect_center(
                        util.get_item_rect())  # bounding rect of prev widget
                    slot_center_positions[('in', id_, slot_ix)] = center_pos

                for slot_ix in range(node.n_outputs):
                    pos = im.Vec2(right_x + 3, top_y + 30 + slot_ix * SPACING)
                    im.set_cursor_screen_position(pos)

                    slot = ng.OutputSlotId(id_, slot_ix)
                    was_selected = (slot == link_selection.src_slot)

                    changed, selected = im.checkbox(
                        "##out{}{}".format(id_, slot_ix), was_selected)
                    if changed:
                        await emit(LinkSelectionAction.ClickOutput(slot))

                    center_pos = util.rect_center(
                        util.get_item_rect())  # bounding rect of prev widget
                    slot_center_positions[('out', id_, slot_ix)] = center_pos

        # end drawing slots

        # draw links
        for (src, dst) in state.graph.links:
            src_pos = slot_center_positions[('out', src.node_id, src.ix)]
            dst_pos = slot_center_positions[('in', dst.node_id, dst.ix)]
            draw_list.add_line(*src_pos,
                               *dst_pos,
                               col=im.get_color_u32_rgba(0.5, 0.5, 0.5, 1.),
                               thickness=2.)

        im.set_cursor_screen_position(prev_cursor_screen_pos)
    # end nodes window

    im.show_style_editor()
Esempio n. 7
0
async def graph_window(graph: Graph) -> Eff[[ACTIONS], IMGui[None]]:
    with window(name="Graph"):

        # maybe use im.selectable?

        # sources

        labels = sorted(
            [str((slot.node_id, slot.ix)) for slot in output_slots(graph)])
        prev_o_source = SELECTED_SLOTS_CONNECT['source']
        prev_o_source_txt = str(
            (prev_o_source.node_id,
             prev_o_source.ix)) if prev_o_source is not None else None

        changed, o_source_txt = str_combo_with_none("src##connect",
                                                    prev_o_source_txt, labels)
        if changed:
            o_source = OutputSlotId(
                *eval(o_source_txt)) if o_source_txt is not None else None
            SELECTED_SLOTS_CONNECT['source'] = o_source

        # dests

        labels = sorted(
            [str((slot.node_id, slot.ix)) for slot in free_input_slots(graph)])
        prev_o_dest = SELECTED_SLOTS_CONNECT['dest']
        prev_o_dest_txt = str(
            (prev_o_dest.node_id,
             prev_o_dest.ix)) if prev_o_dest is not None else None

        changed, o_dest_txt = str_combo_with_none("dst##connect",
                                                  prev_o_dest_txt, labels)
        if changed:
            o_dest = InputSlotId(
                *eval(o_dest_txt)) if o_dest_txt is not None else None
            SELECTED_SLOTS_CONNECT['dest'] = o_dest

        # buttons
        conn = im.button("Connect")
        if (conn and SELECTED_SLOTS_CONNECT['source'] is not None
                and SELECTED_SLOTS_CONNECT['dest'] is not None):
            await emit(
                GraphAction.Connect(SELECTED_SLOTS_CONNECT['source'],
                                    SELECTED_SLOTS_CONNECT['dest']))
            SELECTED_SLOTS_CONNECT['source'] = None
            SELECTED_SLOTS_CONNECT['dest'] = None

        # -----------------------------

        # sources

        labels = sorted([
            str((slot.node_id, slot.ix)) for slot in used_output_slots(graph)
        ])
        prev_o_source = SELECTED_SLOTS_DISCONNECT['source']
        prev_o_source_txt = str(
            (prev_o_source.node_id,
             prev_o_source.ix)) if prev_o_source is not None else None

        changed, o_source_txt = str_combo_with_none("src##disconnect",
                                                    prev_o_source_txt, labels)
        if changed:
            o_source = OutputSlotId(
                *eval(o_source_txt)) if o_source_txt is not None else None
            SELECTED_SLOTS_DISCONNECT['source'] = o_source

        # dests

        labels = sorted([
            str((slot.node_id, slot.ix)) for slot in filled_input_slots(graph)
        ])
        prev_o_dest = SELECTED_SLOTS_DISCONNECT['dest']
        prev_o_dest_txt = str(
            (prev_o_dest.node_id,
             prev_o_dest.ix)) if prev_o_dest is not None else None

        changed, o_dest_txt = str_combo_with_none("dst##disconnect",
                                                  prev_o_dest_txt, labels)
        if changed:
            o_dest = InputSlotId(
                *eval(o_dest_txt)) if o_dest_txt is not None else None
            SELECTED_SLOTS_DISCONNECT['dest'] = o_dest

        conn = im.button("Disconnect")
        if (conn and SELECTED_SLOTS_DISCONNECT['source'] is not None
                and SELECTED_SLOTS_DISCONNECT['dest'] is not None):
            await emit(
                GraphAction.Disconnect(SELECTED_SLOTS_DISCONNECT['source'],
                                       SELECTED_SLOTS_DISCONNECT['dest']))
            SELECTED_SLOTS_DISCONNECT['source'] = None
            SELECTED_SLOTS_DISCONNECT['dest'] = None

        # ----------------------------------

        im.text(graph_repr(graph))