else
parent
c0e7e8f5fc
commit
c3c9727d49
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 568 KiB |
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
|
@ -0,0 +1,54 @@
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
HEADERS = {'User-Agent': 'archive_it commandline tool for archive.is submissions v1.1',
|
||||||
|
'Referer': 'http://archive.is/',
|
||||||
|
'Origin': 'http://archive.is'}
|
||||||
|
URL_SUBMIT = 'https://archive.is/submit/'
|
||||||
|
|
||||||
|
def archive(url, anyway=0):
|
||||||
|
data = {'url': url}
|
||||||
|
if anyway is 1:
|
||||||
|
data[anyway] = 1
|
||||||
|
response = requests.post(URL_SUBMIT, data=data, headers=HEADERS)
|
||||||
|
try:
|
||||||
|
if 'link' in response.headers:
|
||||||
|
time = extract_timestamp(response.headers['link'])
|
||||||
|
raise Exception('''
|
||||||
|
Link already archived: %s
|
||||||
|
Pass parameter `anyway=1` to overwrite.
|
||||||
|
''' % time)
|
||||||
|
response = response.headers['refresh']
|
||||||
|
response = response.split(';')
|
||||||
|
for item in response:
|
||||||
|
if 'archive.is' in item:
|
||||||
|
return item.split('=')[1]
|
||||||
|
except:
|
||||||
|
return response
|
||||||
|
|
||||||
|
def extract_timestamp(link):
|
||||||
|
times = link.split(';')
|
||||||
|
d = {}
|
||||||
|
for item in times:
|
||||||
|
if '=' in item:
|
||||||
|
x = items.split('=')
|
||||||
|
d[x[0]] = x[1]
|
||||||
|
return d.get('from', d)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
print('Use: > archive_it.py http://www.website.com/page')
|
||||||
|
quit()
|
||||||
|
url = sys.argv[1]
|
||||||
|
try:
|
||||||
|
response = archive(url)
|
||||||
|
if isinstance(response, str):
|
||||||
|
print(response)
|
||||||
|
elif isinstance(response, requests.models.Response):
|
||||||
|
print('Did not get the expected response. Here\'s what we got:')
|
||||||
|
print(response)
|
||||||
|
print(response.headers)
|
||||||
|
print(response.text)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
|
@ -35,20 +35,23 @@ def changebase(number, frombase, tobase):
|
||||||
result = int(number, frombase)
|
result = int(number, frombase)
|
||||||
return basex(result, tobase)
|
return basex(result, tobase)
|
||||||
|
|
||||||
def intinput(prompt, greaterthan=None):
|
def intinput(prompt, greaterthan=None, notequal=None):
|
||||||
''' Prompt for input until the user enters an int '''
|
''' Prompt for input until the user enters an int '''
|
||||||
while True:
|
while True:
|
||||||
result = input(prompt)
|
result = input(prompt)
|
||||||
try:
|
try:
|
||||||
i = int(result)
|
i = int(result)
|
||||||
if greaterthan is None or i > greaterthan:
|
if isinstance(notequal, int) and i == notequal:
|
||||||
return i
|
continue
|
||||||
|
if isinstance(greaterthan, int) and i < greaterthan:
|
||||||
|
continue
|
||||||
|
return i
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def configuration():
|
def configuration():
|
||||||
frombase = intinput(' From base: ', 1)
|
frombase = intinput(' From base: ', 1)
|
||||||
tobase = intinput(' To base: ', 1)
|
tobase = intinput(' To base: ', 1, frombase)
|
||||||
lower = intinput('Lower bound: ')
|
lower = intinput('Lower bound: ')
|
||||||
upper = intinput('Upper bound: ', lower)
|
upper = intinput('Upper bound: ', lower)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -9,6 +9,7 @@ class DataPoint:
|
||||||
self.color_outbound = '#999'
|
self.color_outbound = '#999'
|
||||||
self.color_crossbar = '#bbb'
|
self.color_crossbar = '#bbb'
|
||||||
self.color_point = '#000'
|
self.color_point = '#000'
|
||||||
|
self.color_point_out = '#000'
|
||||||
self.crossbar_count = 10
|
self.crossbar_count = 10
|
||||||
self.point_diameter = 4
|
self.point_diameter = 4
|
||||||
self.margin = 0.10
|
self.margin = 0.10
|
||||||
|
@ -27,6 +28,7 @@ class DataPoint:
|
||||||
|
|
||||||
self.countdown = -1
|
self.countdown = -1
|
||||||
self.lastbump = 0
|
self.lastbump = 0
|
||||||
|
self.resized = True
|
||||||
self.t.configure(bg='#f00')
|
self.t.configure(bg='#f00')
|
||||||
self.t.bind('<Configure>', self.movereplot)
|
self.t.bind('<Configure>', self.movereplot)
|
||||||
self.c = tkinter.Canvas(self.t)
|
self.c = tkinter.Canvas(self.t)
|
||||||
|
@ -35,6 +37,8 @@ class DataPoint:
|
||||||
self.reset()
|
self.reset()
|
||||||
self.previous_w = self.w
|
self.previous_w = self.w
|
||||||
self.previous_h = self.h
|
self.previous_h = self.h
|
||||||
|
self.previous_x = self.windowx
|
||||||
|
self.previous_y = self.windowy
|
||||||
self.clear_screen()
|
self.clear_screen()
|
||||||
self.draw_margin()
|
self.draw_margin()
|
||||||
self._started = autostart
|
self._started = autostart
|
||||||
|
@ -59,6 +63,14 @@ class DataPoint:
|
||||||
return self.h
|
return self.h
|
||||||
return self.t.winfo_height()
|
return self.t.winfo_height()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def margin_x(self):
|
||||||
|
return self.window_width * self.margin
|
||||||
|
|
||||||
|
@property
|
||||||
|
def margin_y(self):
|
||||||
|
return self.window_height * self.margin
|
||||||
|
|
||||||
def mainloop(self):
|
def mainloop(self):
|
||||||
self._started = True
|
self._started = True
|
||||||
self.t.mainloop()
|
self.t.mainloop()
|
||||||
|
@ -68,8 +80,8 @@ class DataPoint:
|
||||||
When the user expands the window, replot the graph after a
|
When the user expands the window, replot the graph after a
|
||||||
short delay.
|
short delay.
|
||||||
'''
|
'''
|
||||||
previous = (self.previous_w, self.previous_h)
|
previous = (self.previous_w, self.previous_h, self.previous_x, self.previous_y)
|
||||||
current = (self.window_width, self.window_height)
|
current = (self.window_width, self.window_height, self.t.winfo_x(), self.t.winfo_y())
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now - self.lastbump < 0.2:
|
if now - self.lastbump < 0.2:
|
||||||
# Go away.
|
# Go away.
|
||||||
|
@ -78,8 +90,12 @@ class DataPoint:
|
||||||
# Set.
|
# Set.
|
||||||
self.previous_w = current[0]
|
self.previous_w = current[0]
|
||||||
self.previous_h = current[1]
|
self.previous_h = current[1]
|
||||||
|
self.previous_x = current[2]
|
||||||
|
self.previous_y = current[3]
|
||||||
self.countdown = 1
|
self.countdown = 1
|
||||||
self.lastbump = now
|
self.lastbump = now
|
||||||
|
if previous[:2] != current[:2]:
|
||||||
|
self.resized = False
|
||||||
self.t.after(500, self.movereplot)
|
self.t.after(500, self.movereplot)
|
||||||
return
|
return
|
||||||
if self.countdown > -1:
|
if self.countdown > -1:
|
||||||
|
@ -89,7 +105,9 @@ class DataPoint:
|
||||||
self.t.after(500, self.movereplot)
|
self.t.after(500, self.movereplot)
|
||||||
if self.countdown == 0:
|
if self.countdown == 0:
|
||||||
# Plot.
|
# Plot.
|
||||||
self.plotpoints([])
|
if not self.resized:
|
||||||
|
self.plot_points([])
|
||||||
|
self.resized = True
|
||||||
return
|
return
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
|
@ -105,8 +123,6 @@ class DataPoint:
|
||||||
self.span_y = None
|
self.span_y = None
|
||||||
self.drawable_w = None
|
self.drawable_w = None
|
||||||
self.drawable_h = None
|
self.drawable_h = None
|
||||||
self.margin_x = self.window_width * self.margin
|
|
||||||
self.margin_y = self.window_height * self.margin
|
|
||||||
self.clear_screen()
|
self.clear_screen()
|
||||||
self.draw_margin()
|
self.draw_margin()
|
||||||
|
|
||||||
|
@ -161,6 +177,9 @@ class DataPoint:
|
||||||
hi_x = hi[0]
|
hi_x = hi[0]
|
||||||
hi_y = hi[1]
|
hi_y = hi[1]
|
||||||
|
|
||||||
|
if self.crossbar_count < 1:
|
||||||
|
self.crossbar_count = 1
|
||||||
|
|
||||||
if self.highest_x != self.lowest_x:
|
if self.highest_x != self.lowest_x:
|
||||||
# LOW X
|
# LOW X
|
||||||
self.c.create_text(low_x+5, low_y+5,
|
self.c.create_text(low_x+5, low_y+5,
|
||||||
|
@ -170,8 +189,6 @@ class DataPoint:
|
||||||
text=str(round(self.highest_x, 4)), anchor='nw')
|
text=str(round(self.highest_x, 4)), anchor='nw')
|
||||||
|
|
||||||
increment_x = (self.highest_x - self.lowest_x) / self.crossbar_count
|
increment_x = (self.highest_x - self.lowest_x) / self.crossbar_count
|
||||||
# crossbartop = (self.window_height - self.margin_y) - 5
|
|
||||||
# crossbarbot = (self.window_height - self.margin_y) + 5
|
|
||||||
crossbartop = self.margin_y
|
crossbartop = self.margin_y
|
||||||
crossbarbot = self.window_height - self.margin_y
|
crossbarbot = self.window_height - self.margin_y
|
||||||
for x in range(1, self.crossbar_count):
|
for x in range(1, self.crossbar_count):
|
||||||
|
@ -190,8 +207,6 @@ class DataPoint:
|
||||||
self.c.create_text(low_x-5, hi_y,
|
self.c.create_text(low_x-5, hi_y,
|
||||||
text=str(round(self.highest_y, 4)), anchor='e')
|
text=str(round(self.highest_y, 4)), anchor='e')
|
||||||
increment_y = (self.highest_y - self.lowest_y) / self.crossbar_count
|
increment_y = (self.highest_y - self.lowest_y) / self.crossbar_count
|
||||||
# crossbarlef = self.margin_x - 5
|
|
||||||
# crossbarrgt = self.margin_x + 5
|
|
||||||
crossbarlef = self.margin_x
|
crossbarlef = self.margin_x
|
||||||
crossbarrgt = self.window_width - self.margin_x
|
crossbarrgt = self.window_width - self.margin_x
|
||||||
for y in range(1, self.crossbar_count):
|
for y in range(1, self.crossbar_count):
|
||||||
|
@ -215,19 +230,24 @@ class DataPoint:
|
||||||
or vice-versa.
|
or vice-versa.
|
||||||
'''
|
'''
|
||||||
if not reverse:
|
if not reverse:
|
||||||
if len(self.POINTS) == 1:
|
if self.highest_x == self.lowest_x:
|
||||||
return (self.window_width/2, self.window_height/2)
|
x = self.window_width / 2
|
||||||
# Get percentage of the span
|
else:
|
||||||
x = ((x) - self.lowest_x) / self.span_x
|
# Get percentage of the span
|
||||||
y = ((y) - self.lowest_y) / self.span_y
|
x = ((x) - self.lowest_x) / self.span_x
|
||||||
# Flip y
|
# Use the percentage to get a location on the board
|
||||||
y = 1 - y
|
x *= self.drawable_w
|
||||||
# Use the percentage to get a location on the board
|
# Put into drawing area
|
||||||
x *= self.drawable_w
|
x += self.margin_x
|
||||||
y *= self.drawable_h
|
|
||||||
# Put into drawing area
|
if self.highest_y == self.lowest_y:
|
||||||
x += self.margin_x
|
y = self.window_height / 2
|
||||||
y += self.margin_y
|
else:
|
||||||
|
y = ((y) - self.lowest_y) / self.span_y
|
||||||
|
# Flip y
|
||||||
|
y = 1 - y
|
||||||
|
y *= self.drawable_h
|
||||||
|
y += self.margin_y
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if self.highest_x != self.lowest_x:
|
if self.highest_x != self.lowest_x:
|
||||||
|
@ -247,12 +267,13 @@ class DataPoint:
|
||||||
|
|
||||||
return (x, y)
|
return (x, y)
|
||||||
|
|
||||||
def plotpoints(self, points=[]):
|
def plot_points(self, points=[]):
|
||||||
'''
|
'''
|
||||||
Plot points onto the canvas.
|
Plot points onto the canvas.
|
||||||
var points = list, where each element is a 2-length tuple, where [0]
|
var points = list, where each element is a 2-length tuple, where [0]
|
||||||
is x and [1] is y coordinate.
|
is x and [1] is y coordinate.
|
||||||
'''
|
'''
|
||||||
|
original_len = len(self.POINTS)
|
||||||
for point in points:
|
for point in points:
|
||||||
self.POINTS.add(tuple(point))
|
self.POINTS.add(tuple(point))
|
||||||
|
|
||||||
|
@ -292,19 +313,19 @@ class DataPoint:
|
||||||
outline=self.color_point)
|
outline=self.color_point)
|
||||||
self.c.update()
|
self.c.update()
|
||||||
|
|
||||||
def plotpoint(self, x, y):
|
def plot_point(self, x, y):
|
||||||
self.plotpoints([[x, y]])
|
self.plot_points([[x, y]])
|
||||||
|
|
||||||
def set_origin(self, x, y):
|
def set_origin(self, x, y):
|
||||||
self.origin = (x, y)
|
self.origin = (x, y)
|
||||||
self.plotpoints([])
|
self.plot_points([])
|
||||||
|
|
||||||
|
|
||||||
def example(function):
|
def example(function):
|
||||||
dp = DataPoint()
|
dp = DataPoint()
|
||||||
points = list(range(100))
|
points = list(range(100))
|
||||||
points = [[p, function(p)] for p in points]
|
points = [[p, function(p)] for p in points]
|
||||||
dp.plotpoints(points)
|
dp.plot_points(points)
|
||||||
dp.mainloop()
|
dp.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,10 +351,9 @@ def example2():
|
||||||
(94, 22320), (95, 23703), (96, 40752), (97, 21730), (98, 27637),
|
(94, 22320), (95, 23703), (96, 40752), (97, 21730), (98, 27637),
|
||||||
(99, 45931), (100, 18443), (101, 20048), (102, 18097), (103, 11430)
|
(99, 45931), (100, 18443), (101, 20048), (102, 18097), (103, 11430)
|
||||||
]
|
]
|
||||||
dp.plotpoints(points)
|
dp.plot_points(points)
|
||||||
dp.mainloop()
|
dp.mainloop()
|
||||||
|
|
||||||
|
|
||||||
def examplefunction(x):
|
def examplefunction(x):
|
||||||
x -= 50
|
x -= 50
|
||||||
x *= 0.1
|
x *= 0.1
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
TKCube
|
||||||
|
=========
|
||||||
|
|
||||||
|
Not done yet.
|
|
@ -0,0 +1,117 @@
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import tkinter
|
||||||
|
|
||||||
|
class TKCube:
|
||||||
|
def __init__(self):
|
||||||
|
self.t = tkinter.Tk()
|
||||||
|
self.FACES = [
|
||||||
|
[[2, 2, 1], [2, -2, 1], [-2, -2, 1], [-2, 2, 1]],
|
||||||
|
[[2, -2, 1], [-2, -2, -1], [-2, 2, -1], [2, 2, -1]],
|
||||||
|
[[-2, -2, 1], [2, -2, 1], [2, -2, -1], [-2, -2, -1]],
|
||||||
|
[[-2, 2, 1], [2, 2, 1], [2, 2, -1], [-2, 2, -1]],
|
||||||
|
[[-2, -2, -1], [-2, 2, -1], [-2, 2, 1], [-2, -2, -1]],
|
||||||
|
[[2, -2, 1], [2, 2, 1], [2, 2, -1], [2, -2, -1]],
|
||||||
|
]
|
||||||
|
self.INFLATE_SCALE = 8
|
||||||
|
|
||||||
|
self.c = tkinter.Canvas(self.t, width=600, height=600, bg='#444')
|
||||||
|
self.c.pack(fill='both', expand=True)
|
||||||
|
self.t.bind('<Return>', self.render)
|
||||||
|
self.is_mouse_down = False
|
||||||
|
self.prev_mouse_x = None
|
||||||
|
self.prev_mouse_y = None
|
||||||
|
self.t.bind('<ButtonPress-1>', self.mouse_down)
|
||||||
|
self.t.bind('<ButtonRelease-1>', self.mouse_up)
|
||||||
|
self.t.bind('<Motion>', self.mouse_motion)
|
||||||
|
self.t.bind('<Up>', lambda event: self.arbitrarymove(0, -1))
|
||||||
|
self.t.bind('<Down>', lambda event: self.arbitrarymove(0, 1))
|
||||||
|
self.t.bind('<Left>', lambda event: self.arbitrarymove(-1, 0))
|
||||||
|
self.t.bind('<Right>', lambda event: self.arbitrarymove(1, 0))
|
||||||
|
self.render()
|
||||||
|
self.t.mainloop()
|
||||||
|
|
||||||
|
def arbitrarymove(self, deltax, deltay):
|
||||||
|
for face in self.FACES:
|
||||||
|
for point in face:
|
||||||
|
point[0] += deltax
|
||||||
|
point[1] += deltay
|
||||||
|
self.render()
|
||||||
|
|
||||||
|
def mouse_down(self, event):
|
||||||
|
self.is_mouse_down = True
|
||||||
|
|
||||||
|
def mouse_up(self, event):
|
||||||
|
self.is_mouse_down = False
|
||||||
|
|
||||||
|
def mouse_motion(self, event):
|
||||||
|
if not self.is_mouse_down:
|
||||||
|
return
|
||||||
|
if self.prev_mouse_x is None:
|
||||||
|
self.prev_mouse_x = event.x
|
||||||
|
self.prev_mouse_y = event.y
|
||||||
|
distance = math.sqrt( ((event.x - self.prev_mouse_x) ** 2) + ((event.y - self.prev_mouse_y) ** 2) )
|
||||||
|
self.prev_mouse_x = event.x
|
||||||
|
self.prev_mouse_y = event.y
|
||||||
|
print(distance)
|
||||||
|
|
||||||
|
def center_of_square(self, face):
|
||||||
|
x = 0; y = 0; z = 0
|
||||||
|
for point in face:
|
||||||
|
x += point[0]
|
||||||
|
y += point[1]
|
||||||
|
z += point[2]
|
||||||
|
return [x/4, y/4, z/4]
|
||||||
|
|
||||||
|
def plot_point_screen(self, x, y, diameter=4):
|
||||||
|
radius = diameter / 2
|
||||||
|
x1 = x - radius
|
||||||
|
y1 = y - radius
|
||||||
|
x2 = x + radius
|
||||||
|
y2 = y + radius
|
||||||
|
self.c.create_oval(x1, y1, x2, y2, fill='#000')
|
||||||
|
|
||||||
|
def render(self, *event):
|
||||||
|
self.c.delete('all')
|
||||||
|
rendered_faces = copy.deepcopy(self.FACES)
|
||||||
|
|
||||||
|
# Sort by depth from camera
|
||||||
|
# The sort key is the z value of the coordinate
|
||||||
|
# in the center of the face
|
||||||
|
rendered_faces.sort(key=lambda face: self.center_of_square(face)[2])
|
||||||
|
|
||||||
|
canvas_width_half = self.c.winfo_width() / 2
|
||||||
|
canvas_height_half = self.c.winfo_height() / 2
|
||||||
|
highest_z = max([max([point[2] for point in face]) for face in rendered_faces])
|
||||||
|
for face in self.FACES:
|
||||||
|
for point in face:
|
||||||
|
x = point[0]
|
||||||
|
y = point[1]
|
||||||
|
z = point[2]
|
||||||
|
|
||||||
|
# Push everything away from the camera so all z are <= 0
|
||||||
|
z -= highest_z
|
||||||
|
|
||||||
|
# Create vanishing point.
|
||||||
|
distance_camera = math.sqrt((x**2) + (y**2) + (z**2))
|
||||||
|
#if z != 0:
|
||||||
|
# factor = (abs(z) ** 0.2) - 1
|
||||||
|
# print(factor)
|
||||||
|
#else:
|
||||||
|
# factor = 0
|
||||||
|
x += x * factor
|
||||||
|
y += y * factor
|
||||||
|
|
||||||
|
# Inflate for display
|
||||||
|
x *= self.INFLATE_SCALE
|
||||||
|
y *= self.INFLATE_SCALE
|
||||||
|
z *= self.INFLATE_SCALE
|
||||||
|
|
||||||
|
# Shift the coordinates into the screen
|
||||||
|
x += canvas_width_half
|
||||||
|
y += canvas_height_half
|
||||||
|
self.plot_point_screen(x, y)
|
||||||
|
|
||||||
|
#print(rendered_faces)
|
||||||
|
t = TKCube()
|
|
@ -0,0 +1,21 @@
|
||||||
|
Texture Tile
|
||||||
|
============
|
||||||
|
|
||||||
|
Requires `pip install pillow`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Make it big!
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://github.com/voussoir/else/blob/master/.GitImages/texturetile01.png?raw=true" alt="texture tile"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Make it small!
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://github.com/voussoir/else/blob/master/.GitImages/texturetile02.png?raw=true" alt="texture tile"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Make it any size at all!
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://github.com/voussoir/else/blob/master/.GitImages/texturetile03.png?raw=true" alt="texture tile"/>
|
||||||
|
</p>
|
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
|
@ -0,0 +1,82 @@
|
||||||
|
import os
|
||||||
|
from PIL import Image
|
||||||
|
from PIL import ImageTk
|
||||||
|
import tkinter
|
||||||
|
|
||||||
|
class TextureTile:
|
||||||
|
def __init__(self):
|
||||||
|
self.windowtitle = 'Texture Tile'
|
||||||
|
|
||||||
|
self.t = tkinter.Tk()
|
||||||
|
self.t.title(self.windowtitle)
|
||||||
|
self.w = 450
|
||||||
|
self.h = 475
|
||||||
|
self.screenwidth = self.t.winfo_screenwidth()
|
||||||
|
self.screenheight = self.t.winfo_screenheight()
|
||||||
|
self.windowwidth = self.w
|
||||||
|
self.windowheight = self.h
|
||||||
|
self.windowx = (self.screenwidth-self.windowwidth) / 2
|
||||||
|
self.windowy = ((self.screenheight-self.windowheight) / 2) - 27
|
||||||
|
self.geometrystring = '%dx%d+%d+%d' % (self.windowwidth, self.windowheight, self.windowx, self.windowy)
|
||||||
|
self.t.geometry(self.geometrystring)
|
||||||
|
|
||||||
|
self.entry_filename = tkinter.Entry(self.t, font=('Consolas', 12))
|
||||||
|
self.button_load = tkinter.Button(self.t, text='Load', command=self.file_load_display)
|
||||||
|
self.frame_filearea = tkinter.Frame(self.t)
|
||||||
|
self.label_image = tkinter.Label(self.frame_filearea, bg='#222')
|
||||||
|
|
||||||
|
self.t.columnconfigure(0, weight=1)
|
||||||
|
self.t.rowconfigure(1, weight=1)
|
||||||
|
self.entry_filename.grid(row=0, column=0, sticky='ew')
|
||||||
|
self.button_load.grid(row=0, column=1, sticky='ne')
|
||||||
|
self.frame_filearea.grid(row=1, column=0, columnspan=2, sticky='nsew')
|
||||||
|
self.label_image.pack(expand=True, fill='both')
|
||||||
|
#self.entry_filename.pack(fill='x')
|
||||||
|
#self.button_load.pack()
|
||||||
|
#self.label_image.pack()
|
||||||
|
|
||||||
|
self.entry_filename.insert(0, os.getcwd())
|
||||||
|
self.entry_filename.bind('<Return>', self.file_load_display)
|
||||||
|
self.entry_filename.focus_set()
|
||||||
|
|
||||||
|
self.t.mainloop()
|
||||||
|
|
||||||
|
def file_load_display(self, *event):
|
||||||
|
filename = self.entry_filename.get()
|
||||||
|
# Open file or turn red
|
||||||
|
try:
|
||||||
|
image = Image.open(filename)
|
||||||
|
self.entry_filename.configure(bg='#fff')
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.entry_filename.configure(bg='#f00')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 9x the image
|
||||||
|
w = image.size[0]
|
||||||
|
h = image.size[1]
|
||||||
|
expanded = image.copy()
|
||||||
|
expanded = expanded.resize((w * 3, h * 3))
|
||||||
|
for x in range(3):
|
||||||
|
for y in range(3):
|
||||||
|
expanded.paste(image, (w*x, h*y))
|
||||||
|
|
||||||
|
# Resize 9x'ed image into frame
|
||||||
|
w = expanded.size[0]
|
||||||
|
h = expanded.size[1]
|
||||||
|
fw = self.label_image.winfo_width()
|
||||||
|
fh = self.label_image.winfo_height()
|
||||||
|
ratio = min(fw/w, fh/h)
|
||||||
|
|
||||||
|
w = int(w * ratio)
|
||||||
|
h = int(h * ratio)
|
||||||
|
|
||||||
|
expanded = expanded.resize((w, h))
|
||||||
|
image = ImageTk.PhotoImage(expanded)
|
||||||
|
self.label_image.configure(image=image)
|
||||||
|
self.label_image.dont_garbage_me_bro = image
|
||||||
|
r'C:\Users\Owner\AppData\Roaming\.MinecraftMulti\instances\Chocolate\minecraft\texturepacks\SixtyFox\textures\blocks\melon_top.png'
|
||||||
|
r'C:\users\owner\desktop\pi\imergers\ear.jpg'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
t = TextureTile()
|
|
@ -0,0 +1,9 @@
|
||||||
|
Toddo
|
||||||
|
======
|
||||||
|
|
||||||
|
Commandline to-do-list manager.
|
||||||
|
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://github.com/voussoir/else/blob/master/.GitImages/toddo01.png?raw=true" alt="to-do list manager"/>
|
||||||
|
</p>
|
Binary file not shown.
|
@ -0,0 +1,314 @@
|
||||||
|
import datetime
|
||||||
|
import shutil
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
SQL_ID = 0
|
||||||
|
SQL_TODOTABLE = 1
|
||||||
|
SQL_CREATED = 2
|
||||||
|
SQL_MESSAGE = 3
|
||||||
|
|
||||||
|
HELP_FULL = [
|
||||||
|
('> toddo', 'Display the todos from the current table'),
|
||||||
|
('> toddo all', 'Display the todos from all tables'),
|
||||||
|
('> toddo 4', 'Display the todo with ID 4'),
|
||||||
|
('> toddo add', 'Add a new todo via multi-line typing prompt'),
|
||||||
|
('> toddo add "message"', 'Add a new todo with this message'),
|
||||||
|
('> toddo remove 8', 'Remove the todo with ID 8'),
|
||||||
|
('> toddo table', 'Display the name of the current table'),
|
||||||
|
('> toddo table name', 'Switch to the table named "name"')
|
||||||
|
]
|
||||||
|
|
||||||
|
HELP_NOENTRIES = '''Your todo list is empty!
|
||||||
|
Use `toddo add` or `toddo add "message"` to make entries.'''
|
||||||
|
|
||||||
|
HELP_NOACTIVE = '''Table `%s` has no entries!
|
||||||
|
Use `toddo all` to see if there are entries for other tables.'''
|
||||||
|
|
||||||
|
HELP_REMOVE = '''Provide an ID number to remove.'''
|
||||||
|
|
||||||
|
class ToddoExc(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Toddo():
|
||||||
|
def __init__(self, dbname='C:/git/else/toddo/toddo.db'):
|
||||||
|
self.sql = sqlite3.connect(dbname)
|
||||||
|
self.cur = self.sql.cursor()
|
||||||
|
self.cur.execute('CREATE TABLE IF NOT EXISTS meta(key TEXT, val TEXT)')
|
||||||
|
self.cur.execute('CREATE TABLE IF NOT EXISTS todos(id INT, todotable TEXT, created INT, message TEXT)')
|
||||||
|
self.cur.execute('CREATE INDEX IF NOT EXISTS todoindex on todos(id)')
|
||||||
|
|
||||||
|
def add_todo(self, message=None):
|
||||||
|
'''
|
||||||
|
Create new entry in the database on the active todotable.
|
||||||
|
'''
|
||||||
|
if message is None:
|
||||||
|
message = multi_line_input()
|
||||||
|
message = str(message)
|
||||||
|
if message is '':
|
||||||
|
raise ToddoExc('Todos cannot be blank.')
|
||||||
|
|
||||||
|
todoid = self.increment_lastid()
|
||||||
|
todotable = self.get_todotable()
|
||||||
|
created = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
|
||||||
|
|
||||||
|
self.cur.execute('INSERT INTO todos VALUES(?, ?, ?, ?)', [todoid, todotable, created, message])
|
||||||
|
self.sql.commit()
|
||||||
|
return todoid
|
||||||
|
|
||||||
|
def remove_todo(self, idnumber):
|
||||||
|
'''
|
||||||
|
Drop todo from the database.
|
||||||
|
'''
|
||||||
|
idnumber = int(idnumber)
|
||||||
|
self.cur.execute('SELECT * FROM todos WHERE id=?', [idnumber])
|
||||||
|
todo = self.cur.fetchone()
|
||||||
|
if todo is None:
|
||||||
|
raise ToddoExc('Todo %d does not exist.' % idnumber)
|
||||||
|
activetable = self.get_todotable()
|
||||||
|
requestedtable = todo[SQL_TODOTABLE]
|
||||||
|
if requestedtable.lower() != activetable.lower():
|
||||||
|
raise ToddoExc('Todo %d is not part of the active table `%s`. It belongs to `%s`.' % (idnumber, activetable, requestedtable))
|
||||||
|
self.cur.execute('DELETE FROM todos WHERE id=?', [idnumber])
|
||||||
|
self.sql.commit()
|
||||||
|
return idnumber
|
||||||
|
|
||||||
|
def display_one_todo(self, idnumber):
|
||||||
|
'''
|
||||||
|
Make a nice display that shows a todo's entire contents.
|
||||||
|
'''
|
||||||
|
self.cur.execute('SELECT * FROM todos WHERE id=?', [idnumber])
|
||||||
|
todo = self.cur.fetchone()
|
||||||
|
if todo is None:
|
||||||
|
raise ToddoExc('Todo %d does not exist.' % idnumber)
|
||||||
|
|
||||||
|
message = todo[SQL_MESSAGE]
|
||||||
|
messageleft = len('Message: ')
|
||||||
|
width = shutil.get_terminal_size()[0] - (messageleft + 1)
|
||||||
|
message = nicewrap(message, width, messageleft)
|
||||||
|
|
||||||
|
return 'ID: %d\nTable: %s\nCreated: %s\nMessage: %s' % (
|
||||||
|
todo[SQL_ID], todo[SQL_TODOTABLE], human(todo[SQL_CREATED]), message)
|
||||||
|
|
||||||
|
def display_active_todos(self):
|
||||||
|
'''
|
||||||
|
Pass the active table name into display_todos_from_table
|
||||||
|
'''
|
||||||
|
todotable = self.get_todotable()
|
||||||
|
return self.display_todos_from_table(todotable)
|
||||||
|
|
||||||
|
def display_todos_from_table(self, todotable):
|
||||||
|
'''
|
||||||
|
Make a nice display from the database.
|
||||||
|
'''
|
||||||
|
if todotable is None:
|
||||||
|
self.cur.execute('SELECT * FROM todos ORDER BY id ASC')
|
||||||
|
else:
|
||||||
|
self.cur.execute('SELECT * FROM todos WHERE todotable=? ORDER BY id ASC', [todotable])
|
||||||
|
todos = self.cur.fetchall()
|
||||||
|
if len(todos) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
todos = [list(x) for x in todos]
|
||||||
|
|
||||||
|
longest_id = max(len(str(x[SQL_ID])) for x in todos)
|
||||||
|
longest_table = max(len(str(x[SQL_TODOTABLE])) for x in todos)
|
||||||
|
|
||||||
|
display = []
|
||||||
|
for todo in todos:
|
||||||
|
todoid = str(todo[SQL_ID])
|
||||||
|
todoid = (' '*(longest_id-len(todoid))) + todoid
|
||||||
|
|
||||||
|
timestamp = human(todo[SQL_CREATED])
|
||||||
|
|
||||||
|
todotable = todo[SQL_TODOTABLE]
|
||||||
|
todotable = (' '*(longest_table-len(todotable))) + todotable
|
||||||
|
|
||||||
|
message = todo[SQL_MESSAGE]
|
||||||
|
if '\n' in message:
|
||||||
|
message = message.split('\n')[0] + ' ...'
|
||||||
|
|
||||||
|
total = '%s : %s : %s : %s' % (todoid, todotable, timestamp, message)
|
||||||
|
terminal_width = shutil.get_terminal_size()[0]
|
||||||
|
if len(total) > terminal_width:
|
||||||
|
total = total[:(terminal_width-(len(total)+4))] + '...'
|
||||||
|
display.append(total)
|
||||||
|
|
||||||
|
return '\n'.join(display)
|
||||||
|
|
||||||
|
def switch_todotable(self, newtable=None):
|
||||||
|
'''
|
||||||
|
Update the meta with `newtable` as the new active todotable.
|
||||||
|
'''
|
||||||
|
self.cur.execute('SELECT val FROM meta WHERE key="todotable"')
|
||||||
|
activetable = self.cur.fetchone()
|
||||||
|
if not activetable:
|
||||||
|
activetable = self._install_default_todotable()
|
||||||
|
else:
|
||||||
|
activetable = activetable[0]
|
||||||
|
if newtable is None:
|
||||||
|
return activetable
|
||||||
|
self.cur.execute('UPDATE meta SET val=? WHERE key="todotable"', [newtable])
|
||||||
|
self.sql.commit()
|
||||||
|
return newtable
|
||||||
|
|
||||||
|
def increment_lastid(self, increment=False):
|
||||||
|
'''
|
||||||
|
Increment the lastid in the meta table, THEN return it.
|
||||||
|
'''
|
||||||
|
self.cur.execute('SELECT val FROM meta WHERE key="lastid"')
|
||||||
|
lastid = self.cur.fetchone()
|
||||||
|
if lastid is None:
|
||||||
|
self._install_default_lastid()
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
lastid = int(lastid[0]) + 1
|
||||||
|
self.cur.execute('UPDATE meta SET val=? WHERE key="lastid"', [lastid])
|
||||||
|
return lastid
|
||||||
|
|
||||||
|
def get_todotable(self):
|
||||||
|
self.cur.execute('SELECT val FROM meta WHERE key="todotable"')
|
||||||
|
todotable = self.cur.fetchone()
|
||||||
|
if todotable is None:
|
||||||
|
self._install_default_todotable()
|
||||||
|
todotable = 'default'
|
||||||
|
else:
|
||||||
|
todotable = todotable[0]
|
||||||
|
return todotable
|
||||||
|
|
||||||
|
def _install_default_lastid(self):
|
||||||
|
'''
|
||||||
|
This method assumes that "lastid" does not already exist.
|
||||||
|
If it does, it's your fault for calling this.
|
||||||
|
'''
|
||||||
|
self.cur.execute('INSERT INTO meta VALUES("lastid", 1)')
|
||||||
|
self.sql.commit()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def _install_default_todotable(self):
|
||||||
|
'''
|
||||||
|
This method assumes that "todotable" does not already exist.
|
||||||
|
If it does, it's your fault for calling this.
|
||||||
|
'''
|
||||||
|
self.cur.execute('INSERT INTO meta VALUES("todotable", "default")')
|
||||||
|
self.sql.commit()
|
||||||
|
return 'default'
|
||||||
|
|
||||||
|
def human(timestamp):
|
||||||
|
timestamp = datetime.datetime.utcfromtimestamp(timestamp)
|
||||||
|
timestamp = datetime.datetime.strftime(timestamp, '%d %b %Y %H:%M')
|
||||||
|
return timestamp
|
||||||
|
|
||||||
|
def multi_line_input():
|
||||||
|
print('Submit a ctrl+z to finish typing.')
|
||||||
|
userinput = ''
|
||||||
|
ctrlz = '\x1a'
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
additional = input('- ')
|
||||||
|
except EOFError:
|
||||||
|
# If you only enter a ctrlz
|
||||||
|
return userinput
|
||||||
|
|
||||||
|
if ctrlz in additional:
|
||||||
|
additional = additional.split(ctrlz)[0]
|
||||||
|
userinput += additional
|
||||||
|
break
|
||||||
|
|
||||||
|
userinput += additional + '\n'
|
||||||
|
|
||||||
|
return userinput.strip()
|
||||||
|
|
||||||
|
def nicewrap(message, width, paddingleft):
|
||||||
|
# http://stackoverflow.com/a/26538082 ##########################
|
||||||
|
message = '\n'.join(['\n'.join(textwrap.wrap(line, width,#######
|
||||||
|
break_long_words=True, replace_whitespace=False))##########
|
||||||
|
for line in message.split('\n')])##########################
|
||||||
|
################################################################
|
||||||
|
message = message.strip()
|
||||||
|
message = message.replace('\n', '\n' + (' '*paddingleft))
|
||||||
|
return message
|
||||||
|
|
||||||
|
def fullhelp():
|
||||||
|
longestleft = max(len(x[0]) for x in HELP_FULL)
|
||||||
|
width = shutil.get_terminal_size()[0] - 1
|
||||||
|
message = []
|
||||||
|
for item in HELP_FULL:
|
||||||
|
pad = width - (longestleft+ 3)
|
||||||
|
item = '%s : %s' % (item[0] + (' '*(longestleft - len(item[0]))), nicewrap(item[1], pad, longestleft + 3))
|
||||||
|
message.append(item)
|
||||||
|
message = '\n'.join(message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
toddo = Toddo()
|
||||||
|
|
||||||
|
# Look, no more IndexErrors
|
||||||
|
sys.argv += [None]*10
|
||||||
|
|
||||||
|
if isinstance(sys.argv[1], str):
|
||||||
|
sys.argv[1] = sys.argv[1].lower()
|
||||||
|
|
||||||
|
if sys.argv[1] is None:
|
||||||
|
message = toddo.display_active_todos()
|
||||||
|
if message is None:
|
||||||
|
table = toddo.get_todotable()
|
||||||
|
print(HELP_NOACTIVE % table)
|
||||||
|
else:
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
elif sys.argv[1] == 'all':
|
||||||
|
message = toddo.display_todos_from_table(None)
|
||||||
|
if message is None:
|
||||||
|
print(HELP_NOENTRIES)
|
||||||
|
else:
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
elif sys.argv[1] == 'add':
|
||||||
|
args = list(filter(None, sys.argv))
|
||||||
|
args = args[2:]
|
||||||
|
args = ' '.join(args)
|
||||||
|
if args == '':
|
||||||
|
args = None
|
||||||
|
message = toddo.add_todo(args)
|
||||||
|
if isinstance(message, int):
|
||||||
|
print('Added %d' % message)
|
||||||
|
|
||||||
|
elif sys.argv[1] == 'remove':
|
||||||
|
idnumber = sys.argv[2]
|
||||||
|
if idnumber is None or not idnumber.replace(',', '').isdigit():
|
||||||
|
print(HELP_REMOVE)
|
||||||
|
else:
|
||||||
|
message = []
|
||||||
|
ids = [int(x) for x in idnumber.split(',')]
|
||||||
|
for x in ids:
|
||||||
|
try:
|
||||||
|
t = toddo.remove_todo(x)
|
||||||
|
message.append('Removed %d' % t)
|
||||||
|
except ToddoExc as e:
|
||||||
|
message.append(e.args[0])
|
||||||
|
print('\n'.join(message))
|
||||||
|
|
||||||
|
elif sys.argv[1] == 'table':
|
||||||
|
currenttable = toddo.get_todotable()
|
||||||
|
message = toddo.switch_todotable(sys.argv[2])
|
||||||
|
if currenttable == message:
|
||||||
|
print('You are on table `%s`' % message)
|
||||||
|
else:
|
||||||
|
print('Switched to table `%s`' % message)
|
||||||
|
|
||||||
|
elif sys.argv[1].isdigit():
|
||||||
|
try:
|
||||||
|
message = toddo.display_one_todo(int(sys.argv[1]))
|
||||||
|
print(message)
|
||||||
|
except ToddoExc as e:
|
||||||
|
print(e.args[0])
|
||||||
|
|
||||||
|
elif sys.argv[1] == 'help':
|
||||||
|
print(fullhelp())
|
||||||
|
|
||||||
|
else:
|
||||||
|
print('Command not recognized.')
|
||||||
|
print(fullhelp())
|
Loading…
Reference in New Issue