Page MenuHomePhorge

No OneTemporary

diff --git a/CHANGELOG b/CHANGELOG
index fffb668..3069bd3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,31 +1,33 @@
Copyright (C) 2022 LANNOCC (Shawn A. Wilson [lannocc@yahoo.com])
@%@~LICENSE:MIT~@%@
+saw_073022_6 - Window movement (Linux).
+
saw_073022_5 - Version bump: tested on Linux and Win7.
saw_073022_4 - Print containment on Windows.
saw_073022_3 - Normalized mouse input across platforms.
saw_073022_2 - Mouse input on Windows.
saw_073022_1 - Input wrangling and exception propagation.
saw_072922_3 - Version bump: tested on Linux and Win7.
saw_072922_2 - Beginning Windows backend.
saw_072922_1 - A possible approach to multiple backends.
saw_072822_6 - Some window fun.
saw_072822_5 - Bump version for pip platform dependency test.
saw_072822_4 - Test commit (turned on GPG sign in Windows).
saw_072822_3 - Add Windows support to mouse test script.
saw_072822_2 - Add a mouse test script.
saw_072822_1 - Initial commit (just termio.py from my vipy project).
diff --git a/appscii/app.py b/appscii/app.py
index 8b7ee86..fd814f5 100644
--- a/appscii/app.py
+++ b/appscii/app.py
@@ -1,86 +1,105 @@
from .backend import core
from threading import Thread, current_thread
class Application:
def __init__(self):
self.go = False
self.error = None
self.core = core.Application(self)
self.windows = [ ]
+ self.mouse = (False, False, False) # mouse buttons (left, mid, right)
+ self.moving = None
def exit(self):
self.core.exit()
if self.error:
raise self.error
def run(self):
self.go = True
self.inputs = Thread(target=self.wrap(self.core.inputs),
name='inputs', daemon=True)
self.inputs.start()
- self.refresh_all()
-
self.on_run()
def stop(self, error=None):
if error:
if self.error:
- try:
- raise self.error
+ try: raise self.error
except Exception as e:
- try:
- raise error
+ try: raise error
except Exception as e:
self.error = e
else:
self.error = error
self.go = False
def wrap(self, fn):
def wrapped():
- try:
- fn()
-
+ try: fn()
except Exception as e:
try: raise ThreadException() from e
except Exception as e: self.stop(e)
return wrapped
- def refresh(self):
- self.core.refresh()
+ @property
+ def w(self):
+ return self.core.w
- def refresh_all(self):
- self.refresh()
- for win in self.windows:
- win.refresh()
+ @property
+ def h(self):
+ return self.core.h
def on_run(self):
#raise RuntimeError('yikes')
+
+ #from time import sleep
+ #sleep(1)
+ #self.windows[0].move_to(42, 9)
+
self.inputs.join()
def on_key(self, key):
if key == 27: # escape
self.stop()
def on_mouse(self, x, y, left, mid, right, scroll):
- # this is just for testing:
+ if self.moving:
+ win, mx, my = self.moving
+ if not left:
+ self.moving = None
+
+ if x != mx or y != my:
+ win.move_by(x - mx, y - my)
+ if self.moving:
+ self.moving = (win, x, y)
+
+ elif left and not self.mouse[0]: # left button pushed
+ for win in self.windows:
+ if x >= win.x and x < win.x + win.w \
+ and y >= win.y and y < win.y + win.h:
+ #win.on_mouse(x, y, left, mid, right, scroll)
+
+ self.moving = (win, x, y)
+ break
+
+ self.mouse = (left, mid, right)
+
+ # FIXME this is just for testing (assumes we have at least one window):
self.windows[0].print(f'{x},{y}: {left},{mid},{right},{scroll}')
- self.windows[0].refresh()
- #self.refresh_all()
- pass
class ThreadException(Exception):
def __init__(self):
t = current_thread()
super().__init__('from thread ' \
+ f'"{t.name}"' if t.name else f'{t.ident}')
diff --git a/appscii/backend/curses.py b/appscii/backend/curses.py
index 8e61cf0..b55acf3 100644
--- a/appscii/backend/curses.py
+++ b/appscii/backend/curses.py
@@ -1,114 +1,150 @@
import curses
class Application:
def __init__(self, shell):
self.shell = shell
self.screen = curses.initscr()
curses.flushinp()
curses.curs_set(0)
curses.noecho()
curses.cbreak()
self.screen.keypad(True)
curses.set_escdelay(99)
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
self.mbtns = [False, False, False] # mouse buttons (left, mid, right)
def exit(self):
self.screen.keypad(False)
curses.nocbreak()
curses.echo()
curses.curs_set(1)
curses.flushinp()
curses.endwin()
- def refresh(self):
- self.screen.refresh()
-
def inputs(self):
while self.shell.go:
#raise RuntimeError('my bad')
key = self.screen.getch()
if key == curses.KEY_MOUSE:
_, x, y, _, btn = curses.getmouse()
mbtns = self.mbtns
if btn & curses.BUTTON1_PRESSED:
mbtns[0] = True
elif btn & curses.BUTTON1_RELEASED:
mbtns[0] = False
if btn & curses.BUTTON2_PRESSED:
mbtns[1] = True
elif btn & curses.BUTTON2_RELEASED:
mbtns[1] = False
if btn & curses.BUTTON3_PRESSED:
mbtns[2] = True
elif btn & curses.BUTTON3_RELEASED:
mbtns[2] = False
if btn & curses.BUTTON1_CLICKED \
or btn & curses.BUTTON1_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, True, mbtns[1], mbtns[2], 0)
self.shell.on_mouse(x, y, False, mbtns[1], mbtns[2], 0)
if btn & curses.BUTTON1_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, True, mbtns[1], mbtns[2], 0)
self.shell.on_mouse(x, y, False, mbtns[1], mbtns[2], 0)
elif btn & curses.BUTTON2_CLICKED \
or btn & curses.BUTTON2_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, mbtns[0], True, mbtns[2], 0)
self.shell.on_mouse(x, y, mbtns[0], False, mbtns[2], 0)
if btn & curses.BUTTON2_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, mbtns[0], True, mbtns[2], 0)
self.shell.on_mouse(x, y, mbtns[0], False, mbtns[2], 0)
elif btn & curses.BUTTON3_CLICKED \
or btn & curses.BUTTON3_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], True, 0)
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], False, 0)
if btn & curses.BUTTON3_DOUBLE_CLICKED:
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], True, 0)
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], False, 0)
elif btn & curses.BUTTON4_PRESSED:
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], mbtns[2], 1)
elif btn & 2097152:
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], mbtns[2], -1)
else:
self.shell.on_mouse(x, y, mbtns[0], mbtns[1], mbtns[2], 0)
else:
self.shell.on_key(key)
+ @property
+ def w(self):
+ return curses.COLS
+
+ @property
+ def h(self):
+ return curses.LINES
+
class Window:
def __init__(self, app, x, y, w, h):
+ self.app = app
+ assert w >= 2 and h >= 2
+ assert x >= 0 and x + w <= curses.COLS
+ assert y >= 0 and y + h <= curses.LINES
+
win = curses.newwin(h, w, y, x)
win.keypad(True)
win.box()
self.border = win
win = win.derwin(h - 2, w - 2, 1, 1)
win.keypad(True)
win.scrollok(True)
self.content = win
+ self.app.screen.refresh()
+ self.border.refresh()
+
self.newline = ''
def print(self, txt, end):
self.content.addstr(f'{self.newline}{txt}')
self.newline = '\n' if end else ''
+ self.content.refresh()
- def refresh(self):
+ @property
+ def x(self):
+ return self.border.getbegyx()[1]
+
+ @property
+ def y(self):
+ return self.border.getbegyx()[0]
+
+ @property
+ def w(self):
+ return self.border.getmaxyx()[1]
+
+ @property
+ def h(self):
+ return self.border.getmaxyx()[0]
+
+ def set_pos(self, x, y):
+ assert x >= 0 and x + self.w <= self.app.w
+ assert y >= 0 and y + self.h <= self.app.h
+
+ self.app.screen.clear()
+ self.app.screen.refresh()
+ self.border.mvwin(y, x)
+ self.content.mvwin(y + 1, x + 1)
self.border.refresh()
- self.content.refresh()
diff --git a/appscii/win.py b/appscii/win.py
index add2887..7be34d5 100644
--- a/appscii/win.py
+++ b/appscii/win.py
@@ -1,18 +1,46 @@
from .backend import core
class Window:
def __init__(self, app, x, y, w, h):
self.app = app
self.core = core.Window(app.core, x, y, w, h)
self.app.windows.append(self)
- def refresh(self):
- self.core.refresh()
-
def print(self, txt='', end=True):
self.core.print(txt, end)
- #def scroll(self, lines):
- # self.core.scroll(lines)
+ @property
+ def x(self):
+ return self.core.x
+
+ @property
+ def y(self):
+ return self.core.y
+
+ @property
+ def w(self):
+ return self.core.w
+
+ @property
+ def h(self):
+ return self.core.h
+
+ def move_to(self, x, y):
+ self.core.set_pos(x, y)
+
+ def move_by(self, dx, dy):
+ x = self.x + dx
+ if x < 0: x = 0
+ elif x + self.w > self.app.w: x = self.app.w - self.w
+
+ y = self.y + dy
+ if y < 0: y = 0
+ elif y + self.h > self.app.h: y = self.app.h - self.h
+
+ self.move_to(x, y)
+
+ #def on_mouse(self, x, y, left, mid, right, scroll):
+ # # FIXME this is just for testing:
+ # self.print(f'{x},{y}: {left},{mid},{right},{scroll}')

File Metadata

Mime Type
text/x-diff
Expires
Mon, Sep 14, 10:03 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3651
Default Alt Text
(10 KB)

Event Timeline