diff --git a/plugins/utilities.json b/plugins/utilities.json index c62659e..c2ae124 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -179,6 +179,20 @@ "2.7": null } }, + "fileman": { + "description": "Advanced file manager. Adds a button to settings menu. Experimental. Read code to know more.", + "external_url": "https://brobordd.github.io/byBordd", + "authors": [ + { + "name": "BrotherBoard", + "email": "brobordd@gmail.com", + "discord": "BrotherBoard" + } + ], + "versions": { + "1.0": null + } + }, "plugtools": { "description": "Live Plugin Action. Beta. Adds a dev console tab for plugin management. For full features, read the first lines in the py file, or look in the source.", "external_url": "https://brobordd.github.io/byBordd", diff --git a/plugins/utilities/fileman.py b/plugins/utilities/fileman.py new file mode 100755 index 0000000..58fb580 --- /dev/null +++ b/plugins/utilities/fileman.py @@ -0,0 +1,1771 @@ +# 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 + gcen = lambda: ((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() + gcen = lambda: ((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 +UI = lambda: app.ui_v1 +SCL = lambda a,b,c=None: [a,b,c][UI().uiscale.value] or b +GSW = lambda t: strw(t,suppress_warning=True) +GSH = lambda t: strh(t,suppress_warning=True) +FMT = lambda size: ( + 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")) +) +GUN = lambda: gs('gunCocking').play() +BASE = lambda: join(dirname(app.env.cache_directory),'ballistica_files','ba_data') +AUDIO = lambda: ls(join(BASE(),'audio')) +TEX = lambda: ls(join(BASE(),'textures')) +SRT = lambda: ['Name','Type','Date Modifed','Size'] +INV = lambda c: ((1-c[0])*2,(1-c[1])*2,(1-c[2])*2) +COL = lambda: [ + (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))