Example #1
0
    def on_update(self):
        bp.text("Hello, world!")

        if bp.button("OK"):
            print(self.string.value)

        bp.input_text('string', self.string, 256)

        bp.slider_float("float", self.f, 0, 1)
Example #2
0
    def visualize(self):
        bimpy.begin(type(self).__name__ + " - " + str(id(self)), bimpy.Bool(True))
        bimpy.input_text("Text", self.__state["text"], 256)

        button_pressed = bimpy.button("Plot", bimpy.Vec2(40, 20))

        if button_pressed or self.__state["toggle"]:
            if button_pressed:
                self.__state["toggle"] ^= True
            if len(self.__state["text"].value) > 0:
                bimpy.plot_lines("Graph", self.encode(self.__state["text"].value.encode()))
        bimpy.end()
Example #3
0
 def render_widget(self):
     if bimpy.input_text(self.bimpy_name, self._bimpy_value, 20):
         t = self._bimpy_value.value
         his, ymd = t.split(' ')
         h, i, s = his.split(':')
         y, m, d = ymd.split('-')
         self._value = (0, int(s), int(i), int(h), 0, int(d), int(m),
                        int(y))
Example #4
0
    def object_inspector(self):
        has_selection = self.selected_node is not None
        bimpy.text("ID: %s" %
                   (str(self.selected_node.id) if has_selection else ''))

        nstr = bimpy.String(self.selected_node.name if has_selection else '')
        bimpy.input_text('Name', nstr, 256)

        nwidth = bimpy.Float(self.selected_node.width if has_selection else 0.)
        nheigth = bimpy.Float(
            self.selected_node.height if has_selection else 0.)
        bimpy.input_float2('size', nwidth, nheigth)

        nposx = bimpy.Float(self.selected_node.pos_x if has_selection else 0.)
        nposy = bimpy.Float(self.selected_node.pos_y if has_selection else 0.)
        bimpy.input_float2('position', nposx, nposy)

        ncolor = bimpy.Vec4(
            *[x / 255.
              for x in self.selected_node.color] if has_selection else (0, 0,
                                                                        0, 0))
        bimpy.color_edit("Color", ncolor)

        nradius = [
            self.selected_node.radius.x, self.selected_node.radius.y,
            self.selected_node.radius.z, self.selected_node.radius.w
        ] if has_selection else [0., 0., 0., 0.]
        nradius = [bimpy.Float(x) for x in nradius]

        bimpy.input_float4("radius", *nradius)

        if has_selection:
            self.selected_node.name = nstr.value
            self.selected_node.width = nwidth.value
            self.selected_node.height = nheigth.value
            self.selected_node.pos_x = nposx.value
            self.selected_node.pos_y = nposy.value
            self.selected_node.color = (int(255 * ncolor.x), int(
                255 * ncolor.y), int(255 * ncolor.z), int(255 * ncolor.w))
            self.selected_node.radius = getoolkit.vec4(
                *[x.value for x in nradius])
Example #5
0
    res = ((current_time) - (g_last_timestamp))
    g_last_timestamp = current_time
    return res


def fail(msg):
    print(((bcolors.FAIL) + ("{:8d} FAIL ".format(milli_since_last())) +
           (msg) + (bcolors.ENDC)))
    sys.stdout.flush()


def plog(msg):
    print(((bcolors.OKGREEN) + ("{:8d} LOG ".format(milli_since_last())) +
           (msg) + (bcolors.ENDC)))
    sys.stdout.flush()


args = docopt.docopt(__doc__, version="0.0.1")
if (args["--verbose"]):
    print(args)
ctx = b.Context()
ctx.init(600, 600, "Hello")
str = b.String()
f = b.Float()
while (not (ctx.should_close())):
    with ctx:
        b.text("hello world")
        if (b.button("OK")):
            print(str.value)
        b.input_text("string", str, 256)
        b.slider_float("float", f, (0.0e+0), (1.e+0))
Example #6
0
File: basic.py Project: zakx/bimpy
import bimpy

ctx = bimpy.Context()

ctx.init(600, 600, "Hello")

str = bimpy.String()
f = bimpy.Float();

while(not ctx.should_close()):
    with ctx:
        bimpy.text("Hello, world!")

        if bimpy.button("OK"):
            print(str.value)

        bimpy.input_text('string', str, 256)

        bimpy.slider_float("float", f, 0.0, 1.0)
Example #7
0
def sample(cfg, logger):
    torch.cuda.set_device(0)
    model = Model(startf=cfg.MODEL.START_CHANNEL_COUNT,
                  layer_count=cfg.MODEL.LAYER_COUNT,
                  maxf=cfg.MODEL.MAX_CHANNEL_COUNT,
                  latent_size=cfg.MODEL.LATENT_SPACE_SIZE,
                  truncation_psi=cfg.MODEL.TRUNCATIOM_PSI,
                  truncation_cutoff=cfg.MODEL.TRUNCATIOM_CUTOFF,
                  mapping_layers=cfg.MODEL.MAPPING_LAYERS,
                  channels=cfg.MODEL.CHANNELS,
                  generator=cfg.MODEL.GENERATOR,
                  encoder=cfg.MODEL.ENCODER)
    model.cuda(0)
    model.eval()
    model.requires_grad_(False)

    decoder = model.decoder
    encoder = model.encoder
    mapping_tl = model.mapping_d
    mapping_fl = model.mapping_f
    dlatent_avg = model.dlatent_avg

    logger.info("Trainable parameters generator:")
    count_parameters(decoder)

    logger.info("Trainable parameters discriminator:")
    count_parameters(encoder)

    arguments = dict()
    arguments["iteration"] = 0

    model_dict = {
        'discriminator_s': encoder,
        'generator_s': decoder,
        'mapping_tl_s': mapping_tl,
        'mapping_fl_s': mapping_fl,
        'dlatent_avg': dlatent_avg
    }

    checkpointer = Checkpointer(cfg, model_dict, {}, logger=logger, save=False)

    extra_checkpoint_data = checkpointer.load()

    model.eval()

    layer_count = cfg.MODEL.LAYER_COUNT

    def encode(x):
        Z, _ = model.encode(x, layer_count - 1, 1)
        Z = Z.repeat(1, model.mapping_f.num_layers, 1)
        return Z

    def decode(x):
        layer_idx = torch.arange(2 * layer_count)[np.newaxis, :, np.newaxis]
        ones = torch.ones(layer_idx.shape, dtype=torch.float32)
        coefs = torch.where(layer_idx < model.truncation_cutoff, ones, ones)
        # x = torch.lerp(model.dlatent_avg.buff.data, x, coefs)
        return model.decoder(x, layer_count - 1, 1, noise=True)

    path = 'dataset_samples/faces/realign1024x1024'

    paths = list(os.listdir(path))
    paths.sort()
    paths_backup = paths[:]
    randomize = bimpy.Bool(True)
    current_file = bimpy.String("")

    ctx = bimpy.Context()

    attribute_values = [bimpy.Float(0) for i in indices]

    W = [
        torch.tensor(np.load("principal_directions/direction_%d.npy" % i),
                     dtype=torch.float32) for i in indices
    ]

    rnd = np.random.RandomState(5)

    def loadNext():
        img = np.asarray(Image.open(path + '/' + paths[0]))
        current_file.value = paths[0]
        paths.pop(0)
        if len(paths) == 0:
            paths.extend(paths_backup)

        if img.shape[2] == 4:
            img = img[:, :, :3]
        im = img.transpose((2, 0, 1))
        x = torch.tensor(np.asarray(im, dtype=np.float32),
                         device='cpu',
                         requires_grad=True).cuda() / 127.5 - 1.
        if x.shape[0] == 4:
            x = x[:3]

        needed_resolution = model.decoder.layer_to_resolution[-1]
        while x.shape[2] > needed_resolution:
            x = F.avg_pool2d(x, 2, 2)
        if x.shape[2] != needed_resolution:
            x = F.adaptive_avg_pool2d(x,
                                      (needed_resolution, needed_resolution))

        img_src = ((x * 0.5 + 0.5) * 255).type(torch.long).clamp(
            0, 255).cpu().type(torch.uint8).transpose(0,
                                                      2).transpose(0,
                                                                   1).numpy()

        latents_original = encode(x[None, ...].cuda())
        latents = latents_original[0, 0].clone()
        latents -= model.dlatent_avg.buff.data[0]

        for v, w in zip(attribute_values, W):
            v.value = (latents * w).sum()

        for v, w in zip(attribute_values, W):
            latents = latents - v.value * w

        return latents, latents_original, img_src

    def loadRandom():
        latents = rnd.randn(1, cfg.MODEL.LATENT_SPACE_SIZE)
        lat = torch.tensor(latents).float().cuda()
        dlat = mapping_fl(lat)
        layer_idx = torch.arange(2 * layer_count)[np.newaxis, :, np.newaxis]
        ones = torch.ones(layer_idx.shape, dtype=torch.float32)
        coefs = torch.where(layer_idx < model.truncation_cutoff, ones, ones)
        dlat = torch.lerp(model.dlatent_avg.buff.data, dlat, coefs)
        x = decode(dlat)[0]
        img_src = ((x * 0.5 + 0.5) * 255).type(torch.long).clamp(
            0, 255).cpu().type(torch.uint8).transpose(0,
                                                      2).transpose(0,
                                                                   1).numpy()
        latents_original = dlat
        latents = latents_original[0, 0].clone()
        latents -= model.dlatent_avg.buff.data[0]

        for v, w in zip(attribute_values, W):
            v.value = (latents * w).sum()

        for v, w in zip(attribute_values, W):
            latents = latents - v.value * w

        return latents, latents_original, img_src

    latents, latents_original, img_src = loadNext()

    ctx.init(1800, 1600, "Styles")

    def update_image(w, latents_original):
        with torch.no_grad():
            w = w + model.dlatent_avg.buff.data[0]
            w = w[None, None, ...].repeat(1, model.mapping_f.num_layers, 1)

            layer_idx = torch.arange(model.mapping_f.num_layers)[np.newaxis, :,
                                                                 np.newaxis]
            cur_layers = (7 + 1) * 2
            mixing_cutoff = cur_layers
            styles = torch.where(layer_idx < mixing_cutoff, w,
                                 latents_original)

            x_rec = decode(styles)
            resultsample = ((x_rec * 0.5 + 0.5) * 255).type(torch.long).clamp(
                0, 255)
            resultsample = resultsample.cpu()[0, :, :, :]
            return resultsample.type(torch.uint8).transpose(0,
                                                            2).transpose(0, 1)

    im_size = 2**(cfg.MODEL.LAYER_COUNT + 1)
    im = update_image(latents, latents_original)
    print(im.shape)
    im = bimpy.Image(im)

    display_original = True

    seed = 0

    while not ctx.should_close():
        with ctx:
            new_latents = latents + sum(
                [v.value * w for v, w in zip(attribute_values, W)])

            if display_original:
                im = bimpy.Image(img_src)
            else:
                im = bimpy.Image(update_image(new_latents, latents_original))

            bimpy.begin("Principal directions")
            bimpy.columns(2)
            bimpy.set_column_width(0, im_size + 20)
            bimpy.image(im)
            bimpy.next_column()

            for v, label in zip(attribute_values, labels):
                bimpy.slider_float(label, v, -40.0, 40.0)

            bimpy.checkbox("Randomize noise", randomize)

            if randomize.value:
                seed += 1

            torch.manual_seed(seed)

            if bimpy.button('Next'):
                latents, latents_original, img_src = loadNext()
                display_original = True
            if bimpy.button('Display Reconstruction'):
                display_original = False
            if bimpy.button('Generate random'):
                latents, latents_original, img_src = loadRandom()
                display_original = False

            if bimpy.input_text(
                    "Current file", current_file,
                    64) and os.path.exists(path + '/' + current_file.value):
                paths.insert(0, current_file.value)
                latents, latents_original, img_src = loadNext()

            bimpy.end()
Example #8
0
def show_demo_window():
    bp.begin_root(menu=True)

    #  Menu Bar
    if bp.begin_menu_bar():
        if bp.begin_menu("Menu"):
            bp.end_menu()

        if bp.begin_menu("Examples"):
            bp.end_menu()

        if bp.begin_menu("Tools"):
            bp.end_menu()

        bp.end_menu_bar()

    global clicked
    if bp.button("Button"):
        clicked += 1
    if clicked & 1:
        bp.same_line()
        bp.text("Thanks for clicking me!")

    bp.checkbox("checkbox", check)

    bp.radio_button("radio a", e, 0)
    bp.same_line()
    bp.radio_button("radio b", e, 1)
    bp.same_line()
    bp.radio_button("radio c", e, 2)

    #  Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
    for i in range(7):
        if i > 0:
            bp.same_line()
        bp.push_id_int(i)
        bp.push_style_color(bp.Colors.Button, bp.Vec4(i / 7.0, 0.6, 0.6, 1.0))
        bp.push_style_color(bp.Colors.ButtonHovered,
                            bp.Vec4(i / 7.0, 0.7, 0.7, 1.0))
        bp.push_style_color(bp.Colors.ButtonActive,
                            bp.Vec4(i / 7.0, 0.8, 0.8, 1.0))
        bp.button("Click")
        bp.pop_style_color(3)
        bp.pop_id()

    #  Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
    bp.align_text_to_frame_padding()
    bp.text("Hold to repeat:")
    bp.same_line()

    #  Arrow buttons with Repeater
    spacing = bp.get_style().item_inner_spacing.x
    bp.push_button_repeat(True)

    global counter
    if bp.arrow_button("##left", bp.Direction.Left):
        counter -= 1

    bp.same_line(0.0, spacing)
    if bp.arrow_button("##right", bp.Direction.Right):
        counter += 1

    bp.pop_button_repeat()
    bp.same_line()
    bp.text("%d" % counter)

    bp.text("Hover over me")
    if bp.is_item_hovered():
        bp.set_tooltip("I am a tooltip")

    bp.same_line()
    bp.text("- or me")
    if bp.is_item_hovered():
        bp.begin_tooltip()
        bp.text("I am a fancy tooltip")
        arr = [0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2]
        bp.plot_lines("Curve", arr)
        bp.end_tooltip()

    bp.separator()

    bp.label_text("label", "Value")

    #  Using the _simplified_ one-liner Combo() api here
    #  See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api.
    items = [
        "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII",
        "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO"
    ]
    bp.combo("combo", item_current, items)
    bp.same_line()
    help_marker(
        "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"
    )

    #  To wire InputText() with std::string or any other custom string type,
    #  see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
    bp.input_text("input text", str0, 128)
    bp.same_line()
    help_marker(
        "USER:\nHold SHIFT or use mouse to select text.\n"
        "CTRL+Left/Right to word jump.\n"
        "CTRL+A or double-click to select all.\n"
        "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
        "CTRL+Z,CTRL+Y undo/redo.\n"
        "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp)."
    )

    bp.end()
Example #9
0
with ctx:
    bimpy.themes.set_light_theme()

taille_cible = bimpy.Int(150)

largeur_cible = bimpy.Int(150)

while not ctx.should_close():
    ctx.new_frame()

    bimpy.set_next_window_pos(bimpy.Vec2(0, 0), bimpy.Condition.Once)
    bimpy.set_next_window_size(bimpy.Vec2(800, 400), bimpy.Condition.Once)
    bimpy.begin("Controls")

    bimpy.input_text("Nom du fichier", nom, 15)

    if bimpy.button("Visualisation"):
        while (i < 1000000):
            num = i / 1000000
            bimpy.progress_bar(num)
            bimpy.end()
            ctx.render()
            i = i + 1
    if bimpy.button("Debut du Scan"):
        a = 2
    if bimpy.button("Visualisation du resultat"):
        a = 3
    bimpy.text("Choix des formats de sortie")

    bimpy.checkbox("VTK", vtk)
Example #10
0
import sys
import os

if os.path.exists("../cmake-build-debug/"):
    print('Running Debugging session!')
    sys.path.insert(0, "../cmake-build-debug/")

import bimpy as bp

ctx = bp.Context()

ctx.init(600, 600, "Hello")

str = bp.String()
f = bp.Float()

while not ctx.should_close():
    with ctx:
        bp.begin_root("")

        bp.text("Hello, world!")

        if bp.button("OK"):
            print(str.value)

        bp.input_text('string', str, 256)

        bp.slider_float("float", f, 0.0, 1.0)

        bp.end()
Example #11
0
import bimpy as bp

context = bp.Context()
context.init(600, 600, "Hello, Bimpy!")
label_content = bp.String()
spinner_content = bp.Float()

while not context.should_close():
    with context:
        bp.text("Hello, Bimpy!")

        if bp.button("Ok"):
            print("Hello!")

        bp.input_text("string", label_content, 256)
        bp.slider_float("float", spinner_content, 0.0, 1.0)
Example #12
0
system_user = getpass.getuser()

# gui setup with bimpy
# render new window
ctx = bimpy.Context()
# init main window
ctx.init(1280, 720, "Haus Management")
max_height = ctx.height()
max_width = ctx.width()

string = bimpy.String()
f = bimpy.Float()
i = bimpy.Int()

while (not ctx.should_close()):
    # display new window and set pos and size
    ctx.new_frame()

    bimpy.set_next_window_pos(bimpy.Vec2(10, 10), bimpy.Condition.Once)
    bimpy.set_next_window_size(bimpy.Vec2(max_width - 20, max_height - 20),
                               bimpy.Condition.Once)

    bimpy.begin("Willkommen {} es ist der {}".format(
        system_user,
        datetime.now().strftime('%d.%m.%Y um %H:%M:%S')))

    bimpy.input_text('Besitzer', string, 25)

    bimpy.end()
    ctx.render()
Example #13
0
        ser.write([data])
        out = ser.read()


while not ctx.should_close():
    ctx.new_frame()

    bimpy.set_next_window_pos(bimpy.Vec2(0, 0), bimpy.Condition.Once)
    bimpy.set_next_window_size(bimpy.Vec2(800, 400), bimpy.Condition.Once)
    bimpy.begin("Controls")

    bimpy.input_int("Hauteur de la cible en mm", taille_cible)

    bimpy.input_int("Largeur de la cible en mm", largeur_cible)

    bimpy.input_text("Nom du fichier", stri, 15)

    if bimpy.button("Visualisation"):
        print("La touche Q permet de quitter l'application de visualisation")
        print("La touche R permet une remise a zero de la visualisation")
        print(
            "La touche P permet de mettre en pause l'application de visualisation"
        )
        print("La touche F permet d'activer ou de desactive le post-prcessing")
        print("La touche D permet de reduire la qualite de prise de la camera")
        pyglet.app.run()

    if bimpy.button("Debut du Scan"):
        nom = str(stri.value)
        capture(nom)
    if bimpy.button("Visualisation du resultat"):
Example #14
0
        glPopAttrib()

        #Draws point coordinates.
        glut_string(
            0, 2,
            'Current Point: {}, {}'.format(self.values[0][self.point_index],
                                           self.values[1][self.point_index]))


while (not ctx.should_close()):
    ctx.new_frame()

    bimpy.set_next_window_size(bimpy.Vec2(269, 58), bimpy.Condition.Once)
    bimpy.begin(
        '',
        flags=(bimpy.WindowFlags.AlwaysAutoResize
               | bimpy.WindowFlags.NoTitleBar | bimpy.WindowFlags.NoMove))
    bimpy.input_text('Equation', equation, 256)
    bimpy.input_float('X Min Boundary', x_min)
    bimpy.input_float('X Max Boundary', x_max)
    if bimpy.button('Draw graph'):
        graph_window(equation.value,
                     -5,
                     5,
                     width=700,
                     height=600,
                     caption='Graph Display')
        pyglet.app.run()
    bimpy.end()

    ctx.render()
Example #15
0
def main():

    parser = ArgumentParser(description="Preview animations")

    parser.add_argument("--version",
                        action="version",
                        version="%(prog)s " + __version__)
    parser.add_argument("--width",
                        dest="width",
                        type=int,
                        default=DEF_WIDTH,
                        help="frame width (default: %s)" % DEF_WIDTH)
    parser.add_argument("--height",
                        dest="height",
                        type=int,
                        default=DEF_HEIGHT,
                        help="frame height (default: %s)" % DEF_HEIGHT)
    parser.add_argument("--scale",
                        dest="scale",
                        type=int,
                        default=DEF_SCALE,
                        help="scale preview (default: %s)" % DEF_SCALE)
    parser.add_argument("--double-w",
                        dest="dw",
                        action="store_true",
                        help="double width for 2:1")
    parser.add_argument(
        "--mtime",
        dest="mtime",
        type=int,
        default=DEF_MTIME,
        help="seconds between checks for changes (default: %s)" % DEF_MTIME)

    parser.add_argument("image", help="image to convert")

    args = parser.parse_args()

    def load_image(filename):
        @with_retry
        def load():
            return Image.open(filename).convert("RGB")

        try:
            image = load()
        except IOError:
            parser.error("failed to open the image")

        (w, h) = image.size

        if w % args.width or h % args.height:
            parser.error("%s size is not multiple of tile size (%s, %s)" %
                         (filename, args.width, args.height))

        frames = []
        for y in range(0, h, args.height):
            for x in range(0, w, args.width):
                frames.append((x, y, x + args.width, y + args.height))

        return image, frames

    image, frames = load_image(args.image)
    frame_list = list(range(len(frames)))

    def scale_image(scale, frameno):
        scale_w = scale if not args.dw else scale * 2
        current = image.resize((args.width * scale_w, args.height * scale),
                               box=frames[frame_list[frameno]],
                               resample=0)
        return bimpy.Image(current)

    ctx = bimpy.Context()

    ctx.init(320, 420, "Preview animation")
    orig = bimpy.Image(image)
    scale = bimpy.Int(args.scale)
    fps = bimpy.Int(args.scale)
    frame_list_str = bimpy.String(','.join(map(str, frame_list)))
    im = scale_image(scale.value, 0)

    cur_frame = 0
    paused = False
    start_time = time()
    check_mtime = time()
    last_mtime = os.stat(args.image).st_mtime
    while (not ctx.should_close()):

        if time() - check_mtime > args.mtime:
            if os.stat(args.image).st_mtime != last_mtime:
                last_mtime = os.stat(args.image).st_mtime
                image, frames = load_image(args.image)
                cur_frame = 0
                start_time = time()
                if any([f >= len(frames) for f in frame_list]):
                    frame_list = list(range(len(frames)))
                    frame_list_str = bimpy.String(','.join(map(
                        str, frame_list)))

        ctx.new_frame()
        bimpy.set_next_window_pos(bimpy.Vec2(10, 10), bimpy.Condition.Once)
        bimpy.set_next_window_size(bimpy.Vec2(300, 400), bimpy.Condition.Once)
        bimpy.begin("Image: %s" % args.image)

        if not paused:
            if time() - start_time >= 1. / fps.value:
                start_time = time()
                cur_frame += 1
                if cur_frame == len(frame_list):
                    cur_frame = 0
                im = scale_image(scale.value, cur_frame)

        bimpy.image(orig)
        bimpy.image(im)
        bimpy.text("Frame: %02d" % frame_list[cur_frame])

        if bimpy.slider_int("Scale", scale, 1, 20):
            im = scale_image(scale.value, cur_frame)
        if bimpy.slider_int("FPS", fps, 1, 30):
            start_time = time()
            cur_frame = 0
        if bimpy.input_text("Frames", frame_list_str, 64,
                            bimpy.InputTextFlags.EnterReturnsTrue):
            try:
                new_frame_list = [
                    int(i.strip()) for i in frame_list_str.value.split(",")
                ]
                frame_list = new_frame_list
                start_time = time()
                cur_frame = 0
            except Exception as ex:
                print("Error parsing frame list: %s" % ex)

        if bimpy.button("Play" if paused else "Pause"):
            paused = not paused

        bimpy.end()
        ctx.render()
Example #16
0
COL_COUNT = 8
saved = ""
saved_time = 0
credentials = oauth2.SpotifyClientCredentials(*get_credentials())
while (not ctx.should_close()):
    with ctx:
        # bimpy.themes.set_light_theme()
        bimpy.set_next_window_pos(bimpy.Vec2(20, 20), bimpy.Condition.Once)
        bimpy.set_next_window_size(bimpy.Vec2(600, 600), bimpy.Condition.Once)
        bimpy.begin(
            "Track Listing", bimpy.Bool(True),
            bimpy.WindowFlags.HorizontalScrollbar
            | bimpy.WindowFlags.NoSavedSettings)
        bimpy.text('Spotify Playlist URI')
        bimpy.same_line()
        bimpy.input_text('', playlist_url, 255)
        if not playlist_downloading and not imgs_downloading:
            if bimpy.button("Fetch##Fetcher"):
                # data = fetch_playlist() # this blocks so let's use a thread
                thread = threading.Thread(target=fetch_playlist,
                                          args=(playlist_url.value.strip(), ))
                thread.start()
        elif imgs_downloading:
            bimpy.button("Fetching album covers...")
        elif playlist_downloading:
            bimpy.button("Fetching...")

        if data:
            bimpy.columns(2, "tracks")
            bimpy.text("Track")
            bimpy.next_column()