mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
1996 lines
67 KiB
Python
Executable file
1996 lines
67 KiB
Python
Executable file
# Copyright 2025 - Solely by BrotherBoard
|
|
# Intended for personal use only
|
|
# Bug? Feedback? Telegram >> @BroBordd
|
|
|
|
"""
|
|
FileMan v1.0 - Advanced file manager
|
|
|
|
Adds a button to settings menu.
|
|
Experimental. Read code to know more.
|
|
"""
|
|
|
|
from babase import (
|
|
PluginSubsystem as SUB,
|
|
Plugin,
|
|
env
|
|
)
|
|
from bauiv1 import (
|
|
get_virtual_screen_size as res,
|
|
clipboard_set_text as COPY,
|
|
get_string_height as strh,
|
|
get_string_width as strw,
|
|
get_special_widget as zw,
|
|
get_replays_dir as rdir,
|
|
containerwidget as cw,
|
|
hscrollwidget as hsw,
|
|
screenmessage as SM,
|
|
buttonwidget as obw,
|
|
scrollwidget as sw,
|
|
SpecialChar as sc,
|
|
imagewidget as iw,
|
|
textwidget as tw,
|
|
gettexture as gt,
|
|
apptimer as teck,
|
|
AppTimer as tuck,
|
|
getsound as gs,
|
|
charstr as cs,
|
|
MainWindow,
|
|
open_url,
|
|
Call,
|
|
app
|
|
)
|
|
from os.path import (
|
|
basename,
|
|
getmtime,
|
|
splitext,
|
|
dirname,
|
|
getsize,
|
|
exists,
|
|
isfile,
|
|
isdir,
|
|
join,
|
|
sep
|
|
)
|
|
from os import (
|
|
listdir as ls,
|
|
getcwd,
|
|
rename,
|
|
remove,
|
|
access,
|
|
mkdir,
|
|
X_OK,
|
|
R_OK
|
|
)
|
|
from shutil import (
|
|
copytree,
|
|
rmtree,
|
|
copy,
|
|
move
|
|
)
|
|
from bascenev1 import new_replay_session as REP
|
|
from http.client import HTTPSConnection as GO
|
|
from datetime import datetime as DT
|
|
from mimetypes import guess_type
|
|
from random import uniform as UF
|
|
from threading import Thread
|
|
from pathlib import Path
|
|
|
|
|
|
class FileMan(MainWindow):
|
|
VER = '1.0'
|
|
INS = []
|
|
|
|
@classmethod
|
|
def resize(c):
|
|
c.clean()
|
|
[_.on_resize() for _ in c.INS]
|
|
|
|
@classmethod
|
|
def clean(c):
|
|
c.INS = [_ for _ in c.INS if not _.gn and _.p.exists()]
|
|
|
|
@classmethod
|
|
def loadc(c):
|
|
[setattr(c, f'COL{i}', _) for i, _ in enumerate(var('col'))]
|
|
|
|
def __del__(s):
|
|
s.__class__.clean()
|
|
|
|
def on_resize(s):
|
|
[_.delete() for _ in s.killme]
|
|
s.killme.clear()
|
|
c = s.uploadc
|
|
s.spyt = s.sharel = s.buf = s.uploadc = None
|
|
if c:
|
|
c.close()
|
|
s.fresh()
|
|
|
|
def __init__(s, src):
|
|
s.__class__.clean()
|
|
s.__class__.INS.append(s)
|
|
s.wop()
|
|
s.url = s.urlo = var('cwd')
|
|
s.urlbln = s.dro = s.gn = s.rlyd = s.flon = False
|
|
s.amoled = sum(s.COL5) == 0
|
|
s.pusho = s.sorti = 0
|
|
s.pushi = -0.1
|
|
s.sl = (None, None)
|
|
[setattr(s, _, None) for _ in ['pushe', 'eno', 'leno', 'clp', 'gab',
|
|
'clpm', 'rlydt', 'buf', 'uploadc', 'cursnd', 'rfl', 'rflo']]
|
|
[setattr(s, _, []) for _ in ['trash', 'btns', 'secs', 'docs', 'drkids', 'drol',
|
|
'okes', 'fkids', 'ftrash', 'statkids', 'fcons', 'flkids', 'killme']]
|
|
s.pushq = ''
|
|
# root
|
|
s.p = cw(
|
|
background=False,
|
|
toolbar_visibility='menu_minimal'
|
|
)
|
|
s.rect = iw(
|
|
texture=gt('softRect'),
|
|
opacity=[0.3, 0.85][s.amoled],
|
|
color=s.COL5,
|
|
parent=s.p
|
|
)
|
|
super().__init__(
|
|
root_widget=s.p,
|
|
transition='in_scale',
|
|
origin_widget=src
|
|
)
|
|
s.bg = iw(
|
|
texture=gt('white'),
|
|
parent=s.p,
|
|
position=(-2, 0),
|
|
color=s.COL5
|
|
)
|
|
s.bg2 = bw(
|
|
bg='empty',
|
|
parent=s.p,
|
|
oac=s.bga
|
|
)
|
|
# dock
|
|
s.docs = [iw(
|
|
color=s.COL1,
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
opacity=0.5
|
|
) for _ in range(3)]
|
|
# sections
|
|
s.secs = [tw(
|
|
parent=s.p,
|
|
text=_,
|
|
h_align='center',
|
|
color=s.COL4,
|
|
scale=0.7
|
|
) for _ in ['Action', 'Extra', 'New']]
|
|
# actions
|
|
s.gab = bw(
|
|
parent=s.p,
|
|
oac=s.cancel,
|
|
size=(0, 0),
|
|
selectable=False
|
|
)
|
|
r = []
|
|
for _ in range(6):
|
|
l = ['Copy', 'Move', 'Delete', 'Share', 'Rename', 'Open'][_]
|
|
r.append(bw(
|
|
parent=s.p,
|
|
label=l,
|
|
oac=Call(s.act, 0, _)
|
|
))
|
|
s.btns.append(r)
|
|
# extra
|
|
r = []
|
|
for _ in range(4):
|
|
l = ['Star', 'Sort', 'Filter', 'Theme'][_]
|
|
r.append(bw(
|
|
parent=s.p,
|
|
label=l,
|
|
oac=Call(s.act, 1, _)
|
|
))
|
|
s.btns.append(r)
|
|
s.fltxt = tw(
|
|
editable=True,
|
|
parent=s.p,
|
|
v_align='center',
|
|
glow_type='uniform',
|
|
allow_clear_button=False
|
|
)
|
|
s.flh = tw(
|
|
parent=s.p,
|
|
v_align='center',
|
|
color=s.COL0
|
|
)
|
|
s.gab2 = bw(
|
|
parent=s.p,
|
|
oac=s.unfl,
|
|
size=(0, 0),
|
|
selectable=False
|
|
)
|
|
# new
|
|
r = []
|
|
for _ in range(2):
|
|
l = ['File', 'Folder'][_]
|
|
r.append(bw(
|
|
parent=s.p,
|
|
label=l,
|
|
oac=Call(s.act, 2, _)
|
|
))
|
|
s.btns.append(r)
|
|
# back
|
|
s.bb = bw(
|
|
parent=s.p,
|
|
label=' '+cs(sc.BACK),
|
|
oac=s.bye
|
|
)
|
|
cw(s.p, cancel_button=s.bb)
|
|
# up
|
|
s.ub = bw(
|
|
parent=s.p,
|
|
label=cs(sc.SHIFT),
|
|
oac=s.up
|
|
)
|
|
# url
|
|
s.urlbg = bw(
|
|
parent=s.p,
|
|
oac=s.urled
|
|
)
|
|
s.urlt = tw(
|
|
color=s.COL2,
|
|
text=s.url,
|
|
v_align='center',
|
|
parent=s.p
|
|
)
|
|
s.urla = tw(
|
|
editable=True,
|
|
size=(0, 0),
|
|
parent=s.p,
|
|
text=s.url
|
|
)
|
|
s.trash.append(tuck(0.01, s.urlspy, repeat=True))
|
|
s.trash.append(tuck(0.1, s.urlbl, repeat=True))
|
|
# rf
|
|
s.rfb = bw(
|
|
parent=s.p,
|
|
label=cs(sc.PLAY_BUTTON),
|
|
oac=s.rf
|
|
)
|
|
# pre
|
|
s.preb = bw(
|
|
parent=s.p,
|
|
label=cs(sc.LOGO_FLAT),
|
|
oac=s.pre
|
|
)
|
|
# yes
|
|
s.yesbg = iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
opacity=0.5,
|
|
position=(20, 20)
|
|
)
|
|
s.yesbg2 = iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL5,
|
|
opacity=0.3,
|
|
)
|
|
s.yesp1 = sw(
|
|
parent=s.p,
|
|
border_opacity=0,
|
|
position=(17, 20)
|
|
)
|
|
s.yesp2 = cw(
|
|
parent=s.yesp1,
|
|
background=False
|
|
)
|
|
s.lmao = tw(
|
|
parent=s.yesp2,
|
|
text=''
|
|
)
|
|
# oke
|
|
s.okes = [tw(
|
|
parent=s.p,
|
|
text=_,
|
|
h_align='left',
|
|
color=s.COL4,
|
|
scale=0.7
|
|
) for _ in SRT()]
|
|
# drop
|
|
s.drbg = iw(
|
|
texture=gt('white'),
|
|
parent=s.p,
|
|
opacity=0.7,
|
|
color=s.COL5
|
|
)
|
|
s.drp1 = sw(
|
|
border_opacity=0,
|
|
parent=s.p
|
|
)
|
|
s.drp2 = cw(
|
|
background=False,
|
|
parent=s.drp1
|
|
)
|
|
# push
|
|
s.pushbg2 = iw(
|
|
color=s.COL5,
|
|
parent=s.p,
|
|
opacity=0,
|
|
texture=gt('softRect')
|
|
)
|
|
s.pushbg = iw(
|
|
color=s.COL1,
|
|
parent=s.p,
|
|
opacity=0,
|
|
texture=gt('white')
|
|
)
|
|
s.pusht = tw(
|
|
color=s.COL2,
|
|
parent=s.p,
|
|
h_align='center',
|
|
v_align='center'
|
|
)
|
|
s.trash.append(tuck(0.01, s.fpush, repeat=True))
|
|
# finally
|
|
s.fresh()
|
|
teck(0.5, lambda: s.push(f'FileMan v{s.VER} Ready!', du=1.5) if s.eno is None else 0)
|
|
|
|
def meh(s):
|
|
if s.sl[0] is None:
|
|
s.btw('Select something!')
|
|
return 1
|
|
if s.sl[1] == '..':
|
|
s.btw('What are you doing blud')
|
|
return 1
|
|
|
|
def btw(s, t, du=3):
|
|
s.snd('block')
|
|
s.push(t, color=s.COL3, du=du)
|
|
|
|
def act(s, i, j, gay=False):
|
|
if s.gn:
|
|
return
|
|
w = s.btns[i][j]
|
|
match i:
|
|
case 0:
|
|
match j:
|
|
case 0:
|
|
if s.clp:
|
|
if s.clpm != j:
|
|
s.btw("You're already doing something else!")
|
|
return
|
|
c = var('cwd')
|
|
chk = join(c, basename(s.clp))
|
|
st1, st2 = splitext(chk)
|
|
nn = st1+'_copy'+st2 if exists(chk) else chk
|
|
if exists(nn):
|
|
s.btw('A copy of this '+['file', 'folder']
|
|
[isdir(chk)]+' already exists!')
|
|
return
|
|
try:
|
|
[copy, copytree][isdir(s.clp)](s.clp, nn)
|
|
except Exception as e:
|
|
s.btw(str(e))
|
|
return
|
|
else:
|
|
GUN()
|
|
s.push('Pasted!')
|
|
s.clp = None
|
|
s.fresh()
|
|
else:
|
|
if s.meh():
|
|
return
|
|
s.clp = s.sl[1]
|
|
s.clpm = j
|
|
s.push(f'Copied! Now go to destination.')
|
|
GUN()
|
|
s.fresh(skip=True)
|
|
case 1:
|
|
if s.clp:
|
|
if s.clpm != j:
|
|
s.btw("You are already doing something else!")
|
|
return
|
|
c = var('cwd')
|
|
chk = join(c, basename(s.clp))
|
|
if exists(chk):
|
|
s.btw('There is a '+['file', 'folder']
|
|
[isdir(chk)]+' with the same name here.')
|
|
return
|
|
try:
|
|
move(s.clp, c)
|
|
except Exception as e:
|
|
s.btw(str(e))
|
|
return
|
|
else:
|
|
GUN()
|
|
s.push('Pasted!')
|
|
s.clp = None
|
|
s.fresh()
|
|
else:
|
|
if s.meh():
|
|
return
|
|
s.clp = s.sl[1]
|
|
s.clpm = j
|
|
s.push(f'Now go to destination and paste.')
|
|
GUN()
|
|
s.fresh(skip=True)
|
|
case 2:
|
|
if s.clpm:
|
|
s.btw("Finish what you're doing first!")
|
|
return
|
|
if s.meh():
|
|
return
|
|
h = s.sl[1]
|
|
bn = basename(h)
|
|
if not s.rlyd:
|
|
s.beep(1, 0)
|
|
s.push(f"Really delete "+["the file '"+bn+"'", "the whole '"+bn+"' folder"]
|
|
[isdir(h)]+" forever? Press again to confirm.", du=3, color=s.COL3)
|
|
s.rlydt = tuck(2.9, Call(setattr, s, 'rlyd', False))
|
|
s.rlyd = True
|
|
return
|
|
s.rlyd = False
|
|
s.rlydt = None
|
|
f = [remove, rmtree][isdir(h)]
|
|
try:
|
|
f(h)
|
|
except Exception as e:
|
|
s.btw(str(e))
|
|
return
|
|
else:
|
|
GUN()
|
|
s.push('Deleted!')
|
|
s.sl = (None, None)
|
|
s.fresh()
|
|
case 3:
|
|
if s.meh():
|
|
return
|
|
f = s.sl[1]
|
|
if isdir(f):
|
|
s.btw("You can't share a folder!")
|
|
return
|
|
s.wop()
|
|
o = w.get_screen_space_center()
|
|
xs, ys = 400, 170
|
|
p = s.uploadp = cw(
|
|
parent=zw('overlay_stack'),
|
|
scale_origin_stack_offset=o,
|
|
stack_offset=o,
|
|
size=(xs, ys),
|
|
background=False,
|
|
transition='in_scale'
|
|
)
|
|
s.killme.append(p)
|
|
iw(
|
|
parent=p,
|
|
size=(xs*1.2, ys*1.2),
|
|
texture=gt('softRect'),
|
|
opacity=[0.2, 0.55][s.amoled],
|
|
position=(-xs*0.1, -ys*0.1),
|
|
color=s.COL5
|
|
)
|
|
iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
opacity=0.7,
|
|
size=(xs, ys)
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label='Back',
|
|
oac=s.cupload,
|
|
position=(30, 15),
|
|
size=(xs-60, 30)
|
|
)
|
|
s.cpsharelb = bw(
|
|
parent=p,
|
|
label='...',
|
|
oac=s.cpsharel,
|
|
position=(30, 50),
|
|
size=(xs-60, 30)
|
|
)
|
|
s.opsharelb = bw(
|
|
parent=p,
|
|
label='...',
|
|
oac=s.opsharel,
|
|
position=(30, 85),
|
|
size=(xs-60, 30)
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label='Upload to bashupload.com',
|
|
oac=s.upload,
|
|
position=(30, 120),
|
|
size=(xs-60, 30)
|
|
)
|
|
case 4:
|
|
if s.meh():
|
|
return
|
|
t = s.fkids[s.sl[0]]
|
|
fp = s.sl[1]
|
|
if s.clp == j:
|
|
q = tw(query=t)
|
|
try:
|
|
if sep in q:
|
|
raise ValueError(
|
|
"You can't use directory separator in filename!")
|
|
Path(q)
|
|
except Exception as e:
|
|
s.btw(str(e) or 'Invalid filename!')
|
|
return
|
|
else:
|
|
if (basename(fp) == q) and not gay:
|
|
s.btw("Write a new name blud")
|
|
return
|
|
chk = join(var('cwd'), q)
|
|
if exists(chk):
|
|
s.btw(
|
|
f"There is a {['file', 'folder'][isdir(chk)]} with this name already!")
|
|
return
|
|
else:
|
|
nfp = join(dirname(fp), q)
|
|
try:
|
|
rename(fp, nfp)
|
|
except PermissionError:
|
|
if exists(nfp):
|
|
pass
|
|
else:
|
|
s.push('Permission denied!')
|
|
return
|
|
except Exception as e:
|
|
s.btw(str(e))
|
|
return
|
|
else:
|
|
s.push('Renamed!')
|
|
s.clp = None
|
|
GUN()
|
|
s.fresh(sl=nfp)
|
|
else:
|
|
if s.clpm:
|
|
s.btw("You didn't paste yet blud")
|
|
return
|
|
tw(t, editable=True, color=s.COL7)
|
|
cw(s.yesp2, visible_child=t)
|
|
s.clpm = s.clp = j
|
|
s.push('Now edit the filename, then press Done.')
|
|
if s.flon and s.rfl:
|
|
[_.delete() for _ in s.flkids[s.sl[0]]]
|
|
GUN()
|
|
s.fresh(skip=True)
|
|
case 5:
|
|
if s.meh():
|
|
return
|
|
if s.clpm:
|
|
s.btw("Press again when you're free!")
|
|
return
|
|
h = s.sl[1]
|
|
bn = basename(h)
|
|
if isdir(h):
|
|
s.cd(h)
|
|
s.snd('deek')
|
|
return
|
|
s.stat = 1000
|
|
s.wop()
|
|
k = s.fkids[s.sl[0]] if gay else w
|
|
|
|
def gcen(): return ((o := k.get_screen_space_center()),
|
|
(o[0]-s.size[0]/5, o[1]) if gay else o)[1]
|
|
o = gcen()
|
|
xs, ys = [_*0.6 for _ in s.size]
|
|
p = cw(
|
|
parent=zw('overlay_stack'),
|
|
scale_origin_stack_offset=o,
|
|
size=(xs, ys),
|
|
background=False,
|
|
transition='in_scale'
|
|
)
|
|
s.killme.append(p)
|
|
iw(
|
|
parent=p,
|
|
size=(xs*1.2, ys*1.2),
|
|
texture=gt('softRect'),
|
|
opacity=[0.3, 0.7][s.amoled],
|
|
position=(-xs*0.1, -ys*0.1),
|
|
color=s.COL5
|
|
)
|
|
iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
color=s.COL5,
|
|
opacity=0.7,
|
|
size=(xs, ys)
|
|
)
|
|
b = bw(
|
|
parent=p,
|
|
position=(20, ys-70),
|
|
label=' '+cs(sc.BACK),
|
|
size=(50, 50),
|
|
oac=Call(s.statbye, p, gcen)
|
|
)
|
|
cw(p, cancel_button=b)
|
|
ix = xs-250
|
|
iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
position=(90, ys-72),
|
|
size=(ix, 54),
|
|
opacity=0.5
|
|
)
|
|
tw(
|
|
parent=p,
|
|
h_align='center',
|
|
v_align='center',
|
|
position=(xs/2-60, ys-60),
|
|
text=basename(h),
|
|
maxwidth=ix-100
|
|
)
|
|
iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
opacity=0.5,
|
|
position=(20, 20),
|
|
size=(xs-40, ys-110)
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label=cs(sc.REWIND_BUTTON),
|
|
position=(xs-141, ys-70),
|
|
size=(50, 50),
|
|
oac=Call(s.stata, -1),
|
|
repeat=True
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label=cs(sc.FAST_FORWARD_BUTTON),
|
|
position=(xs-71, ys-70),
|
|
size=(50, 50),
|
|
oac=Call(s.stata, 1),
|
|
repeat=True
|
|
)
|
|
s.oops = 0
|
|
try:
|
|
with open(h, 'r') as f:
|
|
da = f.read()
|
|
except Exception as ex:
|
|
da = ''
|
|
s.oops = 1
|
|
if isinstance(ex, PermissionError):
|
|
kek = 'Permission denied!'
|
|
elif isinstance(ex, UnicodeDecodeError):
|
|
kek = 'No preview avaiable'
|
|
else:
|
|
kek = str(ex)
|
|
else:
|
|
if not da:
|
|
s.oops = 1
|
|
kek = 'No data'
|
|
if not s.oops:
|
|
fxs = xs-40
|
|
fys = ys-110
|
|
s.statsz = (fxs, fys)
|
|
p0 = s.statp0 = sw(
|
|
parent=p,
|
|
position=(20, 20),
|
|
size=(fxs, fys),
|
|
border_opacity=0,
|
|
capture_arrows=True
|
|
)
|
|
s.statda = da
|
|
s.statp = 0
|
|
s.statl = []
|
|
s.itw()
|
|
else:
|
|
ty = s.gtype(h)
|
|
if ty == 'Replay':
|
|
tw(
|
|
parent=p,
|
|
position=(xs/2-20, ys-150),
|
|
text='Press start to preview replay.\nKeep in mind that this will destroy the current FileMan session.',
|
|
h_align='center',
|
|
color=s.COL4,
|
|
maxwidth=xs-60
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label='Start',
|
|
oac=lambda: (b.activate(), teck(0.1, s.bye),
|
|
teck(0.3, Call(REP, h))),
|
|
position=(xs/2-75, ys/2-135),
|
|
size=(150, 40)
|
|
)
|
|
elif ty == 'Texture' and bn in TEX():
|
|
wd = min(xs-80, ys-150)
|
|
tex = gt(splitext(bn)[0])
|
|
iw(
|
|
parent=p,
|
|
texture=tex,
|
|
size=(wd, wd),
|
|
position=(xs/2-wd/2, 40)
|
|
)
|
|
elif ty == 'Audio' and bn in AUDIO():
|
|
tw(
|
|
parent=p,
|
|
position=(xs/2-20, ys-150),
|
|
text=f'Sound is recognized by filename, not data.\nPress the buttons below to play/pause',
|
|
h_align='center',
|
|
color=s.COL4,
|
|
maxwidth=xs-60
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label=cs(sc.PLAY_BUTTON),
|
|
oac=lambda: (getattr(s.cursnd, 'stop', lambda: 0)(), setattr(
|
|
s, 'cursnd', gs(splitext(bn)[0])), s.cursnd.play()),
|
|
position=(xs/2-30, ys/2-135),
|
|
size=(40, 40)
|
|
)
|
|
bw(
|
|
parent=p,
|
|
label=cs(sc.PAUSE_BUTTON),
|
|
oac=lambda: getattr(s.cursnd, 'stop', lambda: 0)(),
|
|
position=(xs/2+30, ys/2-135),
|
|
size=(40, 40)
|
|
)
|
|
else:
|
|
tw(
|
|
parent=p,
|
|
text=kek,
|
|
position=(xs/2-25, ys/2-35),
|
|
h_align='center',
|
|
v_align='center',
|
|
maxwidth=xs-100
|
|
)
|
|
case 1:
|
|
match j:
|
|
case 0:
|
|
star = var('star')
|
|
c = var('cwd')
|
|
if c in star:
|
|
star.remove(c)
|
|
s.push('Unstarred!')
|
|
else:
|
|
star.append(c)
|
|
s.push('Starred! (bomb top right)')
|
|
var('star', star)
|
|
GUN()
|
|
s.fresh(skip=True)
|
|
case 1:
|
|
xs, ys = 200, 230
|
|
s.wop()
|
|
|
|
def gcen(): return ((o := w.get_screen_space_center()),
|
|
(o[0]-s.size[0]/5, o[1]) if gay else o)[1]
|
|
o = gcen()
|
|
p = cw(
|
|
parent=zw('overlay_stack'),
|
|
scale_origin_stack_offset=o,
|
|
size=(xs, ys),
|
|
background=False,
|
|
transition='in_scale',
|
|
stack_offset=(o[0], o[1]),
|
|
on_outside_click_call=lambda: (cw(p, transition='out_scale'), s.laz())
|
|
)
|
|
s.killme.append(p)
|
|
iw(
|
|
parent=p,
|
|
size=(xs*1.2, ys*1.2),
|
|
texture=gt('softRect'),
|
|
opacity=[0.3, 0.7][s.amoled],
|
|
position=(-xs*0.1, -ys*0.1),
|
|
color=s.COL5
|
|
)
|
|
iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
color=s.COL5,
|
|
opacity=0.7,
|
|
size=(xs, ys)
|
|
)
|
|
by = 40
|
|
srt = SRT()
|
|
for _ in range(4):
|
|
bw(
|
|
position=(20, ys-20-by-(by+10)*_),
|
|
size=(xs-40, by),
|
|
label=srt[_],
|
|
oac=Call(s.surt, _, p),
|
|
parent=p
|
|
)
|
|
case 2:
|
|
s.flon = True
|
|
s.snd('deek')
|
|
s.fresh(skip=True)
|
|
case 3:
|
|
ox, oy = s.size
|
|
xs = ys = min(ox / 2, oy / 2)
|
|
xs *= 1.3
|
|
s.wop()
|
|
s.push(
|
|
'FileMan uses 12 main colors. Tap on a color to edit it. Press outside to cancel.', du=6)
|
|
o = w.get_screen_space_center()
|
|
|
|
def nuke():
|
|
cw(p, transition='out_scale')
|
|
s.laz()
|
|
s.push('Cancelled! Nothing was saved')
|
|
p = cw(parent=zw('overlay_stack'), scale_origin_stack_offset=o, size=(
|
|
xs, ys), stack_offset=(-100, 0), background=False, transition='in_scale', on_outside_click_call=nuke)
|
|
bw(parent=p, size=(xs+200, ys), bg='empty')
|
|
s.killme.append(p)
|
|
iw(parent=p, size=(xs * 1.2, ys * 1.2), texture=gt('softRect'),
|
|
opacity=[0.3, 0.7][s.amoled], position=(-xs * 0.1, -ys * 0.1), color=s.COL5)
|
|
iw(parent=p, texture=gt('white'), color=s.COL5,
|
|
opacity=0.7, size=(xs + 200, ys))
|
|
temp_colors, scl, sl = [getattr(s, f'COL{i}') for i in range(12)], [
|
|
0, 0, 0, 0], 0
|
|
kids, nubs, grad = [], [], []
|
|
|
|
def save():
|
|
if var('col') == temp_colors:
|
|
s.btw('At least change a color blud')
|
|
return
|
|
var('col', temp_colors)
|
|
GUN()
|
|
cw(p, transition='out_scale')
|
|
s.__class__.loadc()
|
|
s.bye()
|
|
SM('Reopen FileMan to see changes!')
|
|
|
|
def update_previews():
|
|
f3()
|
|
f4()
|
|
c = temp_colors[sl]
|
|
obw(kids[sl], color=c, textcolor=INV(c))
|
|
|
|
def f3():
|
|
[iw(l, position=(xs + scl[k] * ps - 16, 39 + qs * 5 - (qs) * k))
|
|
for k, l in enumerate(nubs)]
|
|
|
|
def f4():
|
|
c = temp_colors[sl]
|
|
[obw(l, color=(c[0] * (k / 19), c[1] * (k / 19), c[2] * (k / 19)))
|
|
for k, l in enumerate(grad)]
|
|
|
|
def f2(k, l):
|
|
nonlocal scl
|
|
scl[k] = l
|
|
val = l / 19.0
|
|
if k < 3:
|
|
c_list = list(temp_colors[sl])
|
|
c_list[k] = val
|
|
temp_colors[sl] = new_color = tuple(c_list)
|
|
scl[3] = int(max(new_color) * 19)
|
|
elif k == 3:
|
|
c = temp_colors[sl]
|
|
current_max = max(c)
|
|
if current_max > 0:
|
|
scale = val / current_max
|
|
temp_colors[sl] = new_color = (
|
|
c[0] * scale, c[1] * scale, c[2] * scale)
|
|
scl[:3] = [int(x * 19) for x in new_color]
|
|
update_previews()
|
|
|
|
def f(z, sh=0):
|
|
nonlocal sl, scl
|
|
[obw(_, label='') for _ in kids]
|
|
obw(kids[z], label=cs(sc.DPAD_CENTER_BUTTON))
|
|
sl = z
|
|
if not sh:
|
|
s.snd('deek')
|
|
c = temp_colors[sl]
|
|
scl[:3] = [int(x * 19) for x in c]
|
|
scl[3] = int(max(c) * 19) if any(c) else 0
|
|
update_previews()
|
|
bs, qs, ps = (ys - 60) / 3, (ys - 60) / 6, 9
|
|
for k in range(4):
|
|
for l in range(20):
|
|
ah = l / 19.0
|
|
b = obw(
|
|
parent=p, position=(xs + l * ps, 47 + qs * 5 - qs * k), size=(ps + 2, qs / 2), label='', texture=gt('white'), enable_sound=False, on_activate_call=Call(f2, k, l),
|
|
color=((ah, 0, 0) if k < 1 else (0, ah, 0) if k <
|
|
2 else (0, 0, ah) if k < 3 else (ah, ah, ah))
|
|
)
|
|
if k == 3:
|
|
grad.append(b)
|
|
nubs = [iw(parent=p, size=(35, 35), texture=gt('nub'),
|
|
color=(10, 10, 10), opacity=0.4) for _ in range(4)]
|
|
for x in range(4):
|
|
for y in range(3):
|
|
z = x * 3 + y
|
|
c = temp_colors[z]
|
|
kids.append(bw(parent=p, position=(
|
|
20 + (bs + 10) * x, 20 + (bs + 10) * y), size=(bs, bs), color=c, textcolor=INV(c), oac=Call(f, z)))
|
|
bw(parent=p, position=(xs + 5, 24 + qs),
|
|
size=(172, qs - 2), label='Save', oac=save)
|
|
|
|
def reset():
|
|
mem = COL()
|
|
if mem == temp_colors:
|
|
s.btw("Reset what? It's already at default")
|
|
return
|
|
for i, m in enumerate(mem):
|
|
temp_colors[i] = m
|
|
update_previews()
|
|
GUN()
|
|
s.push('Restored default colors! now press save')
|
|
bw(parent=p, position=(xs + 5, 18.5),
|
|
size=(172, qs - 3), label='Reset', oac=reset)
|
|
f(0, sh=1)
|
|
case 2:
|
|
match j:
|
|
case 0:
|
|
if s.clpm:
|
|
s.btw("You're already in the middle of something")
|
|
return
|
|
c = var('cwd')
|
|
n = join(c, 'new_file')
|
|
while exists(n):
|
|
n += '_again'
|
|
try:
|
|
Path(n).touch()
|
|
except PermissionError:
|
|
s.btw('Permission denied!')
|
|
return
|
|
except Exception as ex:
|
|
s.btw(str(ex))
|
|
return
|
|
s.fresh(sl=n)
|
|
# rename
|
|
s.act(0, 4, gay=True)
|
|
case 1:
|
|
if s.clpm:
|
|
s.btw("You're already in the middle of something")
|
|
return
|
|
c = var('cwd')
|
|
n = join(c, 'new_folder')
|
|
while exists(n):
|
|
n += '_again'
|
|
try:
|
|
mkdir(n)
|
|
except PermissionError:
|
|
s.btw('Permission denied!')
|
|
return
|
|
except Exception as ex:
|
|
s.btw(str(ex))
|
|
return
|
|
s.fresh(sl=n)
|
|
# rename
|
|
s.act(0, 4)
|
|
|
|
def surt(s, _, p):
|
|
if _ == s.sorti:
|
|
s.btw('Already sorted by '+SRT()[_]+'!')
|
|
return
|
|
s.sorti = _
|
|
GUN()
|
|
cw(p, transition='out_scale')
|
|
s.fresh(sl=s.sl[1])
|
|
|
|
def statbye(s, p, gcen):
|
|
try:
|
|
cen = gcen()
|
|
except:
|
|
p.delete()
|
|
else:
|
|
cw(p, transition='out_scale', scale_origin_stack_offset=cen)
|
|
s.laz()
|
|
s.statda = None
|
|
s.statl = []
|
|
s.statp = 0
|
|
|
|
def itw(s):
|
|
PYTHON_KEYWORDS = {
|
|
'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def',
|
|
'del', 'elif', 'else', 'except', 'False', 'finally', 'for', 'from',
|
|
'global', 'if', 'import', 'in', 'is', 'lambda', 'None', 'nonlocal',
|
|
'not', 'or', 'pass', 'raise', 'return', 'True', 'try', 'while', 'with', 'yield'
|
|
}
|
|
PYTHON_BUILTINS = {
|
|
'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
|
|
'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr',
|
|
'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview',
|
|
'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
|
|
'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted',
|
|
'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'
|
|
}
|
|
OPERATORS = {'+', '-', '*', '/', '%', '=', '!', '<', '>', '&', '|', '^', '~'}
|
|
BRACKETS = {'(', ')', '{', '}', '[', ']', ':', ',', '.'}
|
|
|
|
s.COL_KEYWORD = getattr(s, 'COL_KEYWORD', (1.5, 0.9, 0.4))
|
|
s.COL_BUILTIN = getattr(s, 'COL_BUILTIN', (0.7, 1.2, 1.8))
|
|
s.COL_STRING = getattr(s, 'COL_STRING', (0.5, 1.5, 0.5))
|
|
s.COL_NUMBER = getattr(s, 'COL_NUMBER', (1.2, 1.2, 0.5))
|
|
s.COL_OPERATOR = getattr(s, 'COL_OPERATOR', (1.5, 1.5, 1.5))
|
|
s.COL_BRACKET = getattr(s, 'COL_BRACKET', (0.9, 0.9, 0.9))
|
|
s.COL_END_MARKER = getattr(s, 'COL_END_MARKER', (1.8, 0.6, 0.6)) # Neon Red for the marker
|
|
|
|
da = s.statda
|
|
end_marker = f'[End of chunk | Press {cs(sc.FAST_FORWARD_BUTTON)}]'
|
|
if len(da) > s.stat:
|
|
if len(da) > s.statp + int(s.stat / 2):
|
|
da = da[s.statp:s.stat + s.statp] + end_marker
|
|
else:
|
|
da = da[s.statp:s.stat + s.statp]
|
|
az = sum(s.statl)
|
|
lines = [_.replace('\\n', '\\'+"~"+"n") for _ in da.splitlines()]
|
|
zc = len(str(az + len(lines)))
|
|
da = '\\n'.join([f"{str(i+1+az).zfill(zc)} | {_}" for i, _ in enumerate(lines)])
|
|
z = len(da)
|
|
p0 = s.statp0
|
|
fxs, fys = s.statsz
|
|
[_.delete() for _ in s.statkids]
|
|
s.statkids.clear()
|
|
hh = 35
|
|
m = max(da.replace('\\n', '') or ' ', key=GSW)
|
|
l = GSW(str(m)) / 1.5
|
|
l = max(15, l)
|
|
l = min(l, 20)
|
|
das = da.split('\\n')
|
|
mm = len(max(das, key=len) or '')
|
|
ldas = len(das)
|
|
s.statl.append(ldas)
|
|
rxs = max(l * mm + 30, fxs)
|
|
rys = max(hh * ldas, fys - 15)
|
|
pos = (0, rys - 40)
|
|
po = list(pos)
|
|
q0 = cw(parent=p0, size=(fxs, rys), background=False)
|
|
p1 = hsw(parent=q0, size=(fxs, rys), border_opacity=0)
|
|
q1 = cw(parent=p1, background=False, size=(rxs, fys))
|
|
s.statkids += [q0, p1, q1]
|
|
|
|
# --- Main Rendering Loop ---
|
|
i = 0
|
|
nc = 0
|
|
in_triple_comment = False
|
|
triple_quote_char = None
|
|
is_first_char_offset_applied = False # Flag for the critical offset
|
|
off = zc + 3
|
|
try:
|
|
mud = int(da[off] == '#')
|
|
except IndexError:
|
|
mud = 0
|
|
|
|
while i < z:
|
|
# -- Priority 1: The End Marker --
|
|
if not in_triple_comment and not mud and da.startswith(end_marker, i):
|
|
if not is_first_char_offset_applied:
|
|
po[0] -= l * 1.5
|
|
is_first_char_offset_applied = True
|
|
for c in end_marker:
|
|
big = nc < zc
|
|
po[0] += l
|
|
s.statkids.append(tw(text=c, position=(
|
|
po[0], po[1] - (3 if big else 0)), h_align='center', v_align='top', parent=q1, big=big, color=s.COL_END_MARKER))
|
|
nc += 1
|
|
i += len(end_marker)
|
|
continue
|
|
|
|
# -- Priority 2: Multi-line comment delimiters --
|
|
if i + 2 < z and da[i:i+3] in ('"'*3, "'"*3):
|
|
chunk = da[i:i+3]
|
|
if not in_triple_comment or chunk == triple_quote_char * 3:
|
|
if not is_first_char_offset_applied:
|
|
po[0] -= l * 1.5
|
|
is_first_char_offset_applied = True
|
|
if not in_triple_comment:
|
|
in_triple_comment = True
|
|
triple_quote_char = chunk[0]
|
|
else:
|
|
in_triple_comment = False
|
|
triple_quote_char = None
|
|
for _ in range(3):
|
|
big = nc < zc
|
|
po[0] += l
|
|
s.statkids.append(tw(text=da[i], position=(
|
|
po[0], po[1] - (3 if big else 0)), h_align='center', v_align='top', parent=q1, big=big, color=s.COL3 if big else s.COL0))
|
|
nc += 1
|
|
i += 1
|
|
continue
|
|
|
|
# -- Priority 3: Newlines --
|
|
if i + 1 < z and da[i:i+2] == '\\n':
|
|
po[0] = pos[0]-l*1.5
|
|
po[1] -= hh
|
|
nc = 0
|
|
try:
|
|
mud = int(da[i + 2 + off] == '#' and not in_triple_comment)
|
|
except IndexError:
|
|
mud = 0
|
|
i += 2
|
|
continue
|
|
|
|
# -- Priority 4: Render based on state (comment or code) --
|
|
# Apply the critical offset before rendering the first character
|
|
if not is_first_char_offset_applied:
|
|
po[0] -= l * 1.5
|
|
is_first_char_offset_applied = True
|
|
|
|
if in_triple_comment or mud:
|
|
big = nc < zc
|
|
color = (s.COL0 if big else s.COL3) if in_triple_comment else (
|
|
s.COL10 if big else s.COL11)
|
|
po[0] += l
|
|
s.statkids.append(tw(text=da[i], position=(
|
|
po[0], po[1] - (3 if big else 0)), h_align='center', v_align='top', parent=q1, big=big, color=color))
|
|
nc += 1
|
|
i += 1
|
|
continue
|
|
|
|
# -- Priority 5: Python Syntax Highlighting --
|
|
char = da[i]
|
|
token = char
|
|
token_color = s.COL2
|
|
if char in ("'", '"'):
|
|
k = i + 1
|
|
while k < z and (da[k] != char or da[k-1] == '\\'):
|
|
k += 1
|
|
token = da[i:k+1]
|
|
token_color = s.COL_STRING
|
|
elif char.isdigit() or (char == '.' and i + 1 < z and da[i+1].isdigit()):
|
|
k = i
|
|
while k < z and (da[k].isdigit() or da[k] == '.'):
|
|
k += 1
|
|
token = da[i:k]
|
|
token_color = s.COL_NUMBER
|
|
elif char.isalpha() or char == '_':
|
|
k = i
|
|
while k < z and (da[k].isalnum() or da[k] == '_'):
|
|
k += 1
|
|
token = da[i:k]
|
|
if token in PYTHON_KEYWORDS:
|
|
token_color = s.COL_KEYWORD
|
|
elif token in PYTHON_BUILTINS:
|
|
token_color = s.COL_BUILTIN
|
|
elif char in OPERATORS:
|
|
token_color = s.COL_OPERATOR
|
|
elif char in BRACKETS:
|
|
token_color = s.COL_BRACKET
|
|
|
|
for c in token:
|
|
big = nc < zc
|
|
po[0] += l
|
|
s.statkids.append(tw(text=c, position=(
|
|
po[0], po[1] - (3 if big else 0)), h_align='center', v_align='top', parent=q1, big=big, color=token_color))
|
|
nc += 1
|
|
i += len(token)
|
|
|
|
cw(q0, visible_child=tw(parent=q0, text='', position=(0, rys)))
|
|
cw(q1, visible_child=tw(parent=q1, text='', position=(0, rys)))
|
|
|
|
def stata(s, i):
|
|
if not s.oops:
|
|
n = s.statp + s.stat*i
|
|
ok = len(s.statda)
|
|
if ok <= n:
|
|
s.btw('Reached EOF!', du=1)
|
|
return
|
|
if n < 0:
|
|
s.btw('Already at first chunk!', du=1)
|
|
return
|
|
s.snd('deek')
|
|
s.statp = n
|
|
if i < 0:
|
|
[s.statl.pop(-1) for _ in [0, 0]]
|
|
s.itw()
|
|
else:
|
|
s.btw('No more open file buffers!')
|
|
|
|
def cpsharel(s):
|
|
l = s.vsharel()
|
|
if not l:
|
|
return
|
|
COPY(str(l))
|
|
s.ding(1, 1)
|
|
s.push(f"Copied '{l}' to clipboard!")
|
|
|
|
def opsharel(s):
|
|
l = s.vsharel()
|
|
if not l:
|
|
return
|
|
s.snd('deek')
|
|
open_url(l)
|
|
|
|
def vsharel(s):
|
|
l = getattr(s, 'sharel', 0)
|
|
if not l:
|
|
s.btw("Upload first!")
|
|
return
|
|
return l
|
|
|
|
def cupload(s):
|
|
c = s.uploadc
|
|
s.spyt = s.sharel = s.buf = s.uploadc = None
|
|
if c:
|
|
c.close()
|
|
s.ding(0, 0)
|
|
s.push('Cancelled!')
|
|
else:
|
|
s.laz()
|
|
cw(s.uploadp, transition='out_scale')
|
|
|
|
def upload(s):
|
|
f = s.sl[1]
|
|
s.ding(1, 0)
|
|
s.push('Uploading...')
|
|
Thread(target=Call(s._upload, f)).start()
|
|
s.spyt = tuck(0.2, Call(s.spy, s.on_upload), repeat=True)
|
|
|
|
def _upload(s, l):
|
|
try:
|
|
c = s.uploadc = GO('bashupload.com')
|
|
filename = basename(l)
|
|
url_path = '/' + filename
|
|
with open(l, 'rb') as f:
|
|
body = f.read()
|
|
headers = {'Content-Type': 'application/octet-stream'}
|
|
c.request('POST', url_path, body=body, headers=headers)
|
|
s.buf = c.getresponse().read().decode()
|
|
except Exception:
|
|
if s.uploadc:
|
|
s.buf = ''
|
|
finally:
|
|
if s.uploadc:
|
|
s.uploadc.close()
|
|
s.uploadc = s.sharel = None
|
|
|
|
def on_upload(s, t):
|
|
if not t:
|
|
s.btw("Couldn't upload")
|
|
return
|
|
s.sharel = t.splitlines()[5][5:]+'?download=1'
|
|
s.ding(0, 1)
|
|
s.push('Success!')
|
|
obw(s.cpsharelb, label='Copy Direct URL')
|
|
obw(s.opsharelb, label=s.sharel)
|
|
|
|
def ding(s, i, j):
|
|
a = ['Small', '']
|
|
x, y = a[i], a[j]
|
|
s.snd('ding'+x)
|
|
teck(0.1, gs('ding'+y).play)
|
|
|
|
def beep(s, i, j):
|
|
s.snd(f'raceBeep{str(i+1)}')
|
|
teck(0.1, gs(f'raceBeep{str(j+1)}').play)
|
|
|
|
def spy(s, f):
|
|
if s.buf is None:
|
|
return
|
|
b = s.buf
|
|
s.buf = None
|
|
f(b)
|
|
s.spyt = None
|
|
|
|
def cancel(s):
|
|
c = s.clp
|
|
s.clp = None
|
|
s.push('Cancelled!')
|
|
s.snd('deek')
|
|
s.fresh(skip=c != 4)
|
|
|
|
def fresh(s, skip=False, sl=None):
|
|
if s.gn:
|
|
return
|
|
rx, ry = res()
|
|
z = s.size = (rx*0.8, ry*0.8)
|
|
x, y = z
|
|
# root
|
|
cw(s.p, size=z)
|
|
iw(s.bg, size=z)
|
|
obw(s.bg2, size=z)
|
|
iw(s.rect, size=(x*1.2, y*1.2), position=(-x*0.1, -y*0.1))
|
|
# docks, secs, btns
|
|
h = (x-80)
|
|
f = y-191
|
|
v = 18
|
|
for i in range(3):
|
|
e = h/[2, 3, 6][i]
|
|
iw(s.docs[i], size=(e, 100), position=(v, f))
|
|
tw(s.secs[i], position=(v+e/2-23, f+1))
|
|
a = s.btns[i]
|
|
l = int(len(a)/2)
|
|
bh = (e-[6, 5, 4][i]*10-(l-1)*10)/l
|
|
for j in range(l):
|
|
for k in [0, l]:
|
|
zz = bh
|
|
of = 20
|
|
ga = (
|
|
(i == k == 0 and s.clpm == j)
|
|
or
|
|
(i == 0 and j == 1 and k == 3 and s.clpm == 4)
|
|
)
|
|
if ga and s.clp:
|
|
zz -= 40
|
|
of -= 2
|
|
po = v+of+(bh+20)*j, f+60-30*bool(k)
|
|
ww = a[j+k]
|
|
obw(ww, position=po, size=(zz, 25))
|
|
if not ga:
|
|
if i == 1 and j == k == 0:
|
|
obw(ww, label=['Star', 'Unstar'][var('cwd') in var('star')])
|
|
elif i == 1 and j == 0 and k:
|
|
tw(s.fltxt, position=(po[0]-2, po[1]-2))
|
|
tw(s.flh, position=(po[0], po[1]-2), max_height=37, maxwidth=zz-42)
|
|
obw(s.gab2, position=(po[0]+zz-32, po[1]))
|
|
if s.flon:
|
|
obw(ww, size=(0, 0), label='')
|
|
tw(s.fltxt, size=(zz-38, 27))
|
|
tw(s.flh, text='' if s.rfl else 'Write something...')
|
|
obw(s.gab2, size=(bh-(zz-38), 25), label='X')
|
|
if not s.fltk:
|
|
s.rflo = s.fltk = ''
|
|
s.fltk = tuck(0.1, s.onfl, repeat=True)
|
|
else:
|
|
obw(ww, size=(zz, 25), label='Filter')
|
|
tw(s.fltxt, size=(0, 0), text='')
|
|
tw(s.flh, text='')
|
|
obw(s.gab2, size=(0, 0), label='')
|
|
s.rfl = s.rflo = s.fltk = None
|
|
continue
|
|
he = bool(s.clp)
|
|
obw(s.gab, position=(po[0]+zz+11, po[1]),
|
|
size=(bh-3-zz, 25), label=['', 'X'][he], selectable=he)
|
|
obw(ww, label=[['Copy', 'Move', 0, 0, 'Rename']
|
|
[s.clpm], ['Paste', 'Done'][s.clpm == 4]][he])
|
|
if not he:
|
|
s.clpm = None
|
|
v += e+20
|
|
# back
|
|
f = y-70
|
|
obw(s.bb, position=(20, f), size=(50, 50))
|
|
# up
|
|
obw(s.ub, position=(90, f), size=(50, 50))
|
|
# url
|
|
e = x - 398
|
|
obw(s.urlbg, size=(e, 50), position=(195, f))
|
|
tw(s.urlt, position=(180, y-60), maxwidth=x-370)
|
|
# rf
|
|
obw(s.rfb, position=(251+e, f), size=(50, 50))
|
|
# pre
|
|
obw(s.preb, position=(323+e, f), size=(50, 50))
|
|
# skip the rest
|
|
if skip:
|
|
return
|
|
# drop
|
|
s.droc()
|
|
# oke
|
|
fly = 35
|
|
sx, sy = x-37, y-230
|
|
h = sx/6
|
|
v = 30
|
|
rat = [3, 1, 1, 1]
|
|
for i, _ in enumerate(s.okes):
|
|
j = rat[i]
|
|
tw(_, position=(v+[30, 0][i != 0], sy-15))
|
|
v += h*j
|
|
# push
|
|
s.rpush()
|
|
# files
|
|
p = s.yesp2
|
|
[_.delete() for _ in s.fkids]
|
|
s.fkids.clear()
|
|
[_.delete() for _ in s.ftrash]
|
|
s.ftrash.clear()
|
|
[_.delete() for _ in s.fcons]
|
|
s.fcons.clear()
|
|
[[i.delete() for i in j] for j in s.flkids]
|
|
s.flkids.clear()
|
|
fl = s.gfull()
|
|
u = s.rfl
|
|
if s.flon and s.rfl:
|
|
fl = [_ for _ in fl if (_ == '..') or (u in basename(_))]
|
|
cur = s.sl[1]
|
|
if cur:
|
|
if cur in fl:
|
|
sl = cur
|
|
else:
|
|
s.sl = (None, None)
|
|
# yes
|
|
rsy = len(fl)*fly
|
|
sw(s.yesp1, size=(sx, sy-40))
|
|
cw(s.yesp2, size=(sx, rsy))
|
|
tw(s.lmao, position=(0, rsy))
|
|
iw(s.yesbg, size=(sx, sy))
|
|
iw(s.yesbg2, size=(sx, 40), position=(20, sy-20))
|
|
# files
|
|
for i, _ in enumerate(fl):
|
|
if _ == sl:
|
|
s.sl = (i, _)
|
|
v = 15
|
|
hm = s.gdata(_)
|
|
for k in range(4):
|
|
j = rat[k]
|
|
e = h*j
|
|
ee = [30, 0][k != 0]
|
|
po = (v+ee, rsy-fly-fly*i)
|
|
t = tw(
|
|
parent=p,
|
|
size=(e-15-ee, fly),
|
|
position=po,
|
|
text=hm[k],
|
|
maxwidth=e-15-ee,
|
|
v_align='center',
|
|
selectable=True,
|
|
click_activate=True,
|
|
on_activate_call=Call(s._sl, i, _, fl),
|
|
glow_type='uniform',
|
|
allow_clear_button=False
|
|
)
|
|
if s.flon and u and not k:
|
|
ci = 0
|
|
bn = basename(_)
|
|
ret = []
|
|
while True:
|
|
nxt = bn.find(u, ci)
|
|
if nxt == -1:
|
|
break
|
|
bf = bn[:nxt]
|
|
ret.append(tw(
|
|
parent=p,
|
|
text=u,
|
|
position=(po[0]+GSW(bf), po[1]+3),
|
|
v_align='center'
|
|
))
|
|
ci = nxt + len(u)
|
|
s.flkids.append(ret)
|
|
if ee:
|
|
s.fcons.append(iw(
|
|
position=(po[0]-ee-8, po[1]+1),
|
|
texture=s.gtex(_),
|
|
size=(ee+1, ee+1),
|
|
parent=p
|
|
))
|
|
v += e
|
|
if k:
|
|
s.ftrash.append(t)
|
|
else:
|
|
s.fkids.append(t)
|
|
if _ == sl:
|
|
cw(s.yesp2, visible_child=t)
|
|
s.slco(fl)
|
|
|
|
def onfl(s):
|
|
s.rfl = tw(query=s.fltxt)
|
|
if s.rfl != s.rflo:
|
|
s.rflo = s.rfl
|
|
s.fresh(sl=s.sl[1])
|
|
|
|
def unfl(s):
|
|
s.flon = False
|
|
s.snd('deek')
|
|
s.fresh(sl=s.sl[1])
|
|
|
|
def gtex(s, _):
|
|
ty = s.gtype(_)
|
|
t = (
|
|
'replayIcon' if _ == '..' else
|
|
'folder' if isdir(_) else
|
|
'tv' if ty == 'Replay' else
|
|
'audioIcon' if ty == 'Audio' else
|
|
'graphicsIcon' if ty == 'Texture' else
|
|
'star' if ty == 'Mesh' else
|
|
'achievementOutline' if ty == 'Font' else
|
|
'file'
|
|
)
|
|
return gt(t)
|
|
|
|
def slco(s, fl):
|
|
# cancel rename
|
|
if s.clp == 4:
|
|
s.cancel()
|
|
sli = s.sl[0]
|
|
for i, g in enumerate(zip(fl, s.fkids, s.fcons)):
|
|
_, w, r = g
|
|
c = [(s.COL10, s.COL11), (s.COL8, s.COL9)][isdir(_)][sli == i]
|
|
tw(w, color=c, editable=False)
|
|
iw(r, color=c)
|
|
for i, z in enumerate(s.flkids):
|
|
for j in z:
|
|
tw(j, color=[s.COL0, s.COL3][sli == i])
|
|
|
|
def _sl(s, i, _, fl):
|
|
if s.sl[0] == i:
|
|
if isdir(_):
|
|
s.cd(_)
|
|
else:
|
|
s.act(0, 5, gay=True)
|
|
return
|
|
s.sl = (i, _)
|
|
s.slco(fl)
|
|
|
|
def gdata(s, _):
|
|
b = isdir(_)
|
|
try:
|
|
mt = DT.fromtimestamp(getmtime(_)).strftime('%m/%d/%Y %I:%M %p')
|
|
except:
|
|
mt = '?'
|
|
try:
|
|
sz = FMT(getsize(_))
|
|
except:
|
|
sz = '?'
|
|
return (
|
|
basename(_),
|
|
s.gtype(_),
|
|
'' if b else mt,
|
|
'' if b else sz
|
|
)
|
|
|
|
def gtype(s, _):
|
|
if isdir(_):
|
|
return ['Folder', 'Parent'][_ == '..']
|
|
f = 'File'
|
|
h = guess_type(_)[0] or f
|
|
if not '.' in _:
|
|
return h.title()
|
|
if h == f:
|
|
return {
|
|
'brp': 'Replay',
|
|
'bob': 'Mesh',
|
|
'cob': 'Mesh',
|
|
'ogg': 'Audio',
|
|
'ktx': 'Texture',
|
|
'fdata': 'Font'
|
|
}.get(_.split('.')[-1], f)
|
|
else:
|
|
return h.title()
|
|
|
|
def gfull(s):
|
|
c = var('cwd')
|
|
h = []
|
|
if dirname(c) != c:
|
|
h = ['..']
|
|
if not access(c, R_OK):
|
|
return h
|
|
items = [join(c, _) for _ in ls(c)]
|
|
da = {}
|
|
for item in items:
|
|
name, item_type, date_modified_str, _ = s.gdata(item)
|
|
try:
|
|
date_sortable = DT.strptime(
|
|
date_modified_str, '%m/%d/%Y %I:%M %p') if date_modified_str else DT.min
|
|
except:
|
|
date_sortable = DT.min
|
|
try:
|
|
mt = getmtime(item)
|
|
except:
|
|
mt = 0
|
|
da[item] = (basename(item).lower(), item_type.lower(), date_sortable, mt, isdir(item))
|
|
return h + sorted(items, key=lambda i: (
|
|
not da[i][4],
|
|
da[i][0] if s.sorti == 0 else
|
|
da[i][1] if s.sorti == 1 else
|
|
da[i][2] if s.sorti == 2 else
|
|
da[i][3]
|
|
))
|
|
|
|
def pre(s):
|
|
s.wop()
|
|
r = s._pre()
|
|
xs = 200
|
|
ys = 160
|
|
pc = s.preb.get_screen_space_center()
|
|
p = s.prep = cw(
|
|
parent=zw('overlay_stack'),
|
|
background=False,
|
|
transition='in_scale',
|
|
scale_origin_stack_offset=pc,
|
|
on_outside_click_call=lambda: (cw(p, transition='out_scale'), s.laz()),
|
|
size=(xs, ys),
|
|
stack_offset=(pc[0]-xs/2+27, pc[1]-ys/2+27)
|
|
)
|
|
s.killme.append(p)
|
|
iw(
|
|
parent=p,
|
|
size=(xs*1.2, ys*1.2),
|
|
texture=gt('softRect'),
|
|
opacity=[0.2, 0.55][s.amoled],
|
|
position=(-xs*0.1, -ys*0.1),
|
|
color=s.COL5
|
|
)
|
|
iw(
|
|
parent=p,
|
|
size=(xs, ys),
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
opacity=0.7
|
|
)
|
|
p2 = sw(
|
|
parent=p,
|
|
size=(xs, ys)
|
|
)
|
|
rys = 30*len(r)
|
|
p3 = cw(
|
|
parent=p2,
|
|
size=(xs, max(ys, rys)),
|
|
background=False
|
|
)
|
|
for i, _ in enumerate(r):
|
|
j, k = _
|
|
tw(
|
|
parent=p3,
|
|
size=(xs, 30),
|
|
position=(0, rys-30-30*i),
|
|
maxwidth=xs-20,
|
|
text=j,
|
|
click_activate=True,
|
|
selectable=True,
|
|
glow_type='uniform',
|
|
on_activate_call=Call(s.pres, k)
|
|
)
|
|
|
|
def pres(s, k):
|
|
GUN()
|
|
cw(s.prep, transition='out_scale')
|
|
s.cd(k)
|
|
|
|
def _pre(s):
|
|
e = app.env
|
|
c = e.cache_directory
|
|
d = dirname
|
|
f = join(d(c), 'ballistica_files', 'ba_data')
|
|
g = cs(sc.LOGO_FLAT)+' '
|
|
return [
|
|
*[(cs(sc.DPAD_CENTER_BUTTON)+' '+(basename(_) or _), _) for _ in var('star')],
|
|
(g+'Mods', e.python_directory_user),
|
|
(g+'Replays', rdir()),
|
|
(g+'Config', e.config_directory),
|
|
(g+'Cache', c),
|
|
(g+'Files', f),
|
|
(g+'Python', join(f, 'python')),
|
|
(g+'Meshes', join(f, 'meshes')),
|
|
(g+'Audio', join(f, 'audio')),
|
|
(g+'Textures', join(f, 'textures'))
|
|
]
|
|
|
|
def rf(s):
|
|
s.snd('ding')
|
|
s.fresh()
|
|
c = var('cwd')
|
|
s.push('Refreshed '+(basename(c) or c))
|
|
|
|
def up(s):
|
|
o = var('cwd')
|
|
n = dirname(o)
|
|
if o == n:
|
|
s.eno = 2
|
|
s.nah()
|
|
s.snd('block')
|
|
return
|
|
s.cd(n)
|
|
s.snd('deek')
|
|
|
|
def glike(s):
|
|
c = var('cwd')
|
|
if not access(c, R_OK):
|
|
s.eno = not access(c, X_OK)
|
|
s.nah()
|
|
return []
|
|
a = ls(c)
|
|
f = []
|
|
for _ in a:
|
|
j = join(c, _)
|
|
if isdir(j):
|
|
f.append(j)
|
|
r = [_ for _ in f if _.startswith(s.url)]
|
|
return r
|
|
|
|
def nah(s):
|
|
if s.eno == s.leno:
|
|
return
|
|
s.leno = s.eno
|
|
s.push([
|
|
"I can't list files here! Write next folder name manually.",
|
|
"I can't even enter there! Select another folder.",
|
|
"Already reached root!"
|
|
][s.eno], color=s.enoc(), du=[3, 3, 2][s.eno])
|
|
|
|
def enoc(s):
|
|
return [
|
|
s.COL7,
|
|
s.COL4,
|
|
s.COL2
|
|
][s.eno]
|
|
|
|
def drop(s, i):
|
|
if s.gn:
|
|
return
|
|
s.dro = i > 0
|
|
s.droc()
|
|
|
|
def droc(s):
|
|
s.drol = s.glike()
|
|
s.rdrop()
|
|
|
|
def rdrop(s):
|
|
if s.gn:
|
|
return
|
|
[_.delete() for _ in s.drkids]
|
|
s.drkids.clear()
|
|
l = len(s.drol)
|
|
if not s.dro or not s.drol or (l == 1 and s.drol[0] == s.url):
|
|
iw(s.drbg, size=(0, 0))
|
|
sw(s.drp1, size=(0, 0))
|
|
return
|
|
x, y = s.size
|
|
of = 20
|
|
ys = 30*l+of
|
|
fys = min(300, ys)
|
|
yp = y-71-fys
|
|
xs = x-325
|
|
xp = 160
|
|
iw(s.drbg, size=(xs, fys), position=(xp, yp))
|
|
sw(s.drp1, size=(xs, fys), position=(xp, yp))
|
|
cw(s.drp2, size=(xs, ys-of))
|
|
for i, _ in enumerate(s.drol):
|
|
p = (0, ys-30-30*i-of)
|
|
s.drkids.append(tw(
|
|
parent=s.drp2,
|
|
position=p,
|
|
text=_,
|
|
color=s.COL9,
|
|
selectable=True,
|
|
click_activate=True,
|
|
glow_type='uniform',
|
|
on_activate_call=Call(s.cd, _),
|
|
size=(GSW(_), 30)
|
|
))
|
|
s.drkids.append(tw(
|
|
parent=s.drp2,
|
|
position=p,
|
|
text=s.url,
|
|
color=s.COL4,
|
|
))
|
|
|
|
def push(s, t, color=None, du=2):
|
|
if s.gn:
|
|
return
|
|
s.rly = False
|
|
s.rlydt = None
|
|
tw(s.pusht, color=color or s.COL2)
|
|
s.pushe = tuck(du, s.upush)
|
|
s.pushi = 0.05
|
|
s.pushq = t
|
|
s.rpush()
|
|
|
|
def upush(s):
|
|
if s.gn:
|
|
return
|
|
s.pushi = -abs(s.pushi)
|
|
s.pushq = ''
|
|
s.rpush(1)
|
|
|
|
def rpush(s, mode=0):
|
|
if s.gn:
|
|
return
|
|
if mode:
|
|
tw(s.pusht, text=s.pushq, color=s.COL2)
|
|
return
|
|
x = s.size[0]
|
|
t = s.pushq
|
|
w = GSW(t+' '*3)
|
|
iw(s.pushbg, size=(w, 30), position=(x/2-w/2, 40))
|
|
iw(s.pushbg2, size=(w*1.1, 30*1.2), position=((x/2-w/2)-w*0.05, (40)-30*0.1))
|
|
tw(s.pusht, text=t, maxwidth=w*0.95, position=(x/2-25, 40))
|
|
|
|
def fpush(s):
|
|
if s.gn:
|
|
return
|
|
n = s.pusho + s.pushi
|
|
if not (1 >= n >= 0):
|
|
return
|
|
s.pusho = n
|
|
iw(s.pushbg, opacity=n)
|
|
iw(s.pushbg2, opacity=[n*0.4, n][s.amoled])
|
|
|
|
def urlbl(s):
|
|
if s.gn:
|
|
return
|
|
if s.p.get_selected_child() not in [s.ub, s.drp2, s.drp1, s.urlbg]+s.drkids:
|
|
s.urlbln = False
|
|
if s.dro:
|
|
s.drop(-1)
|
|
return
|
|
s.urlbln = not s.urlbln
|
|
if not s.dro:
|
|
s.drop(1)
|
|
|
|
def urlspy(s):
|
|
if s.gn:
|
|
return
|
|
s.url = tw(query=s.urla)
|
|
b1 = exists(s.url)
|
|
b2 = isdir(s.url)
|
|
g1 = access(var('cwd'), R_OK)
|
|
g2 = access(s.url, X_OK)
|
|
b = b1 and b2 and g1 and g2
|
|
av = not b1 and g1 and not g2 and s.drol
|
|
if b or av:
|
|
s.eno = None
|
|
q = s.url != s.urlo
|
|
if q:
|
|
s.droc()
|
|
lurl = var('cwd')
|
|
can = b1 and b2 and s.url != lurl
|
|
if can:
|
|
s.cd(s.url)
|
|
lurl = s.url
|
|
co = (
|
|
s.COL2 if b else
|
|
s.COL3 if av else
|
|
s.COL6 if not b1 else
|
|
s.enoc()
|
|
)
|
|
tw(s.urlt, text=s.url+[' ', '|'][s.urlbln or q], color=co)
|
|
s.urlo = s.url
|
|
if can or isdir(s.url):
|
|
return
|
|
# complete
|
|
f = dirname(s.url)
|
|
if not exists(f):
|
|
return
|
|
if f == lurl:
|
|
return
|
|
s.cd(f, dry=True)
|
|
|
|
def cd(s, t, dry=False):
|
|
if t == '..':
|
|
t = dirname(var('cwd'))
|
|
s.sl = (None, None)
|
|
if s.flon and s.rfl:
|
|
s.push("Filter is active! Press 'X' to cancel.", du=1.2, color=s.COL3)
|
|
var('cwd', t)
|
|
if s.eno != 1 and not access(t, X_OK):
|
|
s.eno = 1
|
|
s.nah()
|
|
0 if dry else tw(s.urla, text=t)
|
|
cw(s.yesp2, visible_child=s.lmao)
|
|
s.fresh()
|
|
|
|
def urled(s):
|
|
if s.gn:
|
|
return
|
|
s.snd('deek')
|
|
s.urla.activate()
|
|
|
|
def wop(s):
|
|
s.snd('powerup01')
|
|
|
|
def laz(s):
|
|
s.snd('laser')
|
|
|
|
def bye(s):
|
|
s.gn = True
|
|
s.trash.clear()
|
|
s.laz()
|
|
s.main_window_back()
|
|
s.__class__.clean()
|
|
del s
|
|
|
|
def snd(s, t):
|
|
s.sn = gs(t)
|
|
s.sn.play()
|
|
teck(UF(0.13, 0.15), s.sn.stop)
|
|
|
|
def bga(s):
|
|
s.urlbln = False
|
|
|
|
|
|
# Tools and Resources
|
|
# Lambda means it won't be stored in memory unless called
|
|
def UI(): return app.ui_v1
|
|
|
|
|
|
def SCL(a, b, c=None): return [a, b, c][UI().uiscale.value] or b
|
|
def GSW(t): return strw(t, suppress_warning=True)
|
|
def GSH(t): return strh(t, suppress_warning=True)
|
|
|
|
|
|
def FMT(size): return (
|
|
f"{size / 1024**3:.1f} GB" if size >= 1024**3 else (
|
|
f"{size / 1024**2:.1f} MB" if size >= 1024**2 else (
|
|
f"{size / 1024:.1f} KB" if size >= 1024 else f"{size} B"))
|
|
)
|
|
def GUN(): return gs('gunCocking').play()
|
|
|
|
|
|
def BASE(): return join(dirname(app.env.cache_directory), 'ballistica_files', 'ba_data')
|
|
def AUDIO(): return ls(join(BASE(), 'audio'))
|
|
def TEX(): return ls(join(BASE(), 'textures'))
|
|
|
|
|
|
def SRT(): return ['Name', 'Type', 'Date Modifed', 'Size']
|
|
def INV(c): return ((1-c[0])*2, (1-c[1])*2, (1-c[2])*2)
|
|
|
|
|
|
def COL(): return [
|
|
(0.5, 0.5, 0),
|
|
(0.17, 0.17, 0.17),
|
|
(1, 1, 1),
|
|
(1, 1, 0),
|
|
(0.6, 0.6, 0.6),
|
|
(0, 0, 0),
|
|
(1, 0, 0),
|
|
(1, 0, 1),
|
|
(0.5, 0.25, 0),
|
|
(1, 0.5, 0),
|
|
(0, 0.5, 0.5),
|
|
(0, 1, 1)
|
|
]
|
|
|
|
# Config
|
|
|
|
|
|
def var(s, v=None):
|
|
cfg = app.config
|
|
s = 'fm_'+s
|
|
return cfg.get(s, v) if v is None else (cfg.__setitem__(s, v), cfg.commit())
|
|
|
|
|
|
def con(v, t):
|
|
if var(v) is None:
|
|
var(v, t)
|
|
|
|
|
|
# Default
|
|
con('cwd', getcwd())
|
|
con('star', [])
|
|
con('col', COL())
|
|
|
|
# Patches
|
|
f = SUB.on_screen_size_change
|
|
SUB.on_screen_size_change = lambda *a, **k: (FileMan.resize(), f(*a, **k))
|
|
bw = lambda *a, color=None, textcolor=None, oac=None, bg='white', label='', **k: obw(
|
|
*a,
|
|
on_activate_call=oac,
|
|
texture=gt(bg),
|
|
label=label,
|
|
enable_sound=False,
|
|
color=color or FileMan.COL1,
|
|
textcolor=textcolor or FileMan.COL2,
|
|
**k
|
|
)
|
|
|
|
# brobord collide grass
|
|
# ba_meta require api 9
|
|
# ba_meta export babase.Plugin
|
|
|
|
|
|
class byBordd(Plugin):
|
|
def on_app_running(s):
|
|
FileMan.loadc()
|
|
teck(0.1, s.kang)
|
|
|
|
def kang(s):
|
|
from bauiv1lib.settings.allsettings import AllSettingsWindow as m
|
|
i = '__init__'
|
|
o = getattr(m, i)
|
|
setattr(m, i, lambda z, *a, **k: (o(z, *a, **k), s.mk(z))[0])
|
|
|
|
def fix(s, p):
|
|
m = __import__('logging')
|
|
i = 'exception'
|
|
o = getattr(m, i)
|
|
setattr(m, i, lambda *a, **k: 0 if s.b == p.get_selected_child() else o(*a, **k))
|
|
|
|
def mk(s, z):
|
|
s.fix(z._root_widget)
|
|
x, y = SCL((1000, 800), (900, 450))
|
|
s.b = obw(
|
|
position=(x*0.7, y*SCL(0.5, 0.9)),
|
|
parent=z._root_widget,
|
|
icon=gt('folder'),
|
|
size=(100, 30),
|
|
button_type='square',
|
|
label='Man',
|
|
enable_sound=False,
|
|
color=FileMan.COL1,
|
|
textcolor=FileMan.COL2,
|
|
on_activate_call=lambda: s.run(z)
|
|
)
|
|
|
|
def run(s, z):
|
|
z.main_window_replace(new_window=FileMan(s.b))
|