~nch/glue

6c754b5eabfe7dccbbf5a3a321d88bbb73847220 — nc a month ago a32fb30
implement drag and drop using reactive programming (rxpy) and a relational table structure (pandas)
1 files changed, 100 insertions(+), 0 deletions(-)

A drag_and_drop.py
A drag_and_drop.py => drag_and_drop.py +100 -0
@@ 0,0 1,100 @@
import sdl2
import sdl2.ext
import pandas as pd
import numpy as np
import rx
from rx import operators as ops
from rx.subject import Subject
from rx.scheduler.mainloop import PyGameScheduler
from pysm import StateMachine, Event, State

from dataclasses import dataclass
from typing import *

sdl2.ext.init()
win = sdl2.ext.Window('drag and drop', size=(800, 600))
win.show()

boxes = pd.DataFrame(columns=['x', 'y', 'w', 'h'])

def insert_many(df, ts):
    n = len(ts[list(ts.keys())[0]])
    cols = list(df.columns)
    results = [None] * n

    for i in range(n):
        results[i] = insert(df, tuple(ts[c][i] for c in cols))

    return results

def insert(df, t):
    id_ = len(df)
    df.loc[id_] = t
    return id_

def in_bb(bb, pos):
    bx, by, bw, bh = bb
    x, y = pos
    return bx < x < bx + bw and by < y < by + bh

renderer = sdl2.ext.Renderer(win)

mouse_move = Subject()
mouse_down = Subject()
mouse_up = Subject()

scheduler = PyGameScheduler(None)

### program logic

insert_many(boxes, {
    'x': np.random.randint(400, size=15),
    'y': np.random.randint(400, size=15),
    'w': np.repeat(30, 15),
    'h': np.repeat(30, 15)
    })

def find_box_at(pos):
    px, py = pos
    r = boxes[(boxes.x < px) & (px < boxes.x + boxes.w) &
              (boxes.y < py) & (py < boxes.y + boxes.h)]
    if len(r) > 0:
        return r.iloc[0].name
    else:
        return None

box_click = mouse_down.pipe(ops.map(find_box_at), ops.filter(lambda x: x is not None))

def move_box(id_, p):
    w, h = boxes.loc[id_, ['w', 'h']]
    boxes.loc[id_, ['x', 'y']] = p[0] - w // 2, p[1] - h // 2

drag = mouse_move.pipe(
        ops.combine_latest(box_click),
        ops.take_until(mouse_up),
        ops.repeat()).subscribe(lambda x: move_box(x[1], x[0]))

### main loop

running = True
while running:
    renderer.clear()
    for id_, row in boxes.iterrows():
        x, y, w, h = row
        renderer.draw_rect([(x, y, w, h)], (255, 255, 255))
    events = sdl2.ext.get_events()
    for event in events:
        if event.type == sdl2.SDL_QUIT:
            running = False
        if event.type == sdl2.SDL_MOUSEMOTION:
            mouse_move.on_next((event.motion.x, event.motion.y))
        if event.type == sdl2.SDL_MOUSEBUTTONDOWN:
            mouse_down.on_next((event.motion.x, event.motion.y))
        if event.type == sdl2.SDL_MOUSEBUTTONUP:
            mouse_up.on_next((event.motion.x, event.motion.y))

    scheduler.run()

    renderer.present()
    win.refresh()