556 lines
26 KiB
Plaintext
556 lines
26 KiB
Plaintext
# init python:
|
|
# def catch_character_call(label, called):
|
|
# if called:
|
|
# if label.startswith(("her_main", "cho_main", "ast_main", "ton_main", "sus_main", "lun_main", "hoo_main")):
|
|
# editor.catch(label)
|
|
|
|
# def lookup(what):
|
|
# if isinstance(what, (int, str, float, bool)):
|
|
# return None
|
|
|
|
# for k, v in store.__dict__.iteritems():
|
|
# if k.startswith("_"):
|
|
# continue
|
|
|
|
# if v == what:
|
|
# return k
|
|
# return None
|
|
|
|
# class ExpressionEditor(NoRollback):
|
|
# transforms = ("move_fade", "sprite_fly_idle")
|
|
|
|
# char = {"her_main": "hermione",
|
|
# "ton_main": "tonks",
|
|
# "ast_main": "astoria",
|
|
# "cho_main": "cho",
|
|
# "sus_main": "susan",
|
|
# "lun_main": "luna",
|
|
# "hoo_main": "hooch",
|
|
# }
|
|
|
|
# def __init__(self):
|
|
# self.label = None
|
|
# self.line = None
|
|
# self.line_contents = None
|
|
# self.args = None
|
|
|
|
# self._file = None
|
|
# self._file_contents = None
|
|
|
|
# self.define_expressions()
|
|
# self.changes = _dict()
|
|
|
|
# def launch_editor(self, file=None, line=None):
|
|
# """Launches external text editor."""
|
|
# if renpy.in_rollback() or renpy.in_fixed_rollback():
|
|
# return
|
|
|
|
# renpy.launch_editor([file], line)
|
|
# return
|
|
|
|
# def overwrite_statement(self):
|
|
|
|
# # Backup file contents
|
|
# with open(self._file, "r") as f:
|
|
# self._file_contents = f.readlines()
|
|
|
|
# found = False
|
|
|
|
# try:
|
|
# new = self.get_new_statement()
|
|
# old = self.line_contents
|
|
|
|
# # Overwrite the file contents
|
|
# with open(self._file, "w") as f:
|
|
# for n, l in enumerate(self._file_contents, 1):
|
|
# if n == self.line and l.partition("#")[0].strip() == old:
|
|
# found = True
|
|
|
|
# f.writelines(l.replace(old, new))
|
|
|
|
# # Is it a new line, or have we already edited it?
|
|
# if n not in self.changes.get(self._file, _list()):
|
|
# self.changes.setdefault(self._file, _dict()).setdefault(n, [old, new, self.args, self.char[self.label], None])
|
|
# else:
|
|
# self.changes[self._file][n] = [old, new, self.args, self.char[self.label], None]
|
|
|
|
# self.line_contents = new
|
|
# else:
|
|
# f.writelines(l)
|
|
|
|
# if not found:
|
|
# renpy.notify("Line {} contents changed unexpectedly, no changes were made.".format(self.line))
|
|
# return
|
|
# except:
|
|
# # Restore backup
|
|
# with open(self._file, "w") as f:
|
|
# for l in self._file_contents:
|
|
# f.writelines(l)
|
|
# renpy.notify("An error occurred, no changes were made.")
|
|
# return
|
|
|
|
# renpy.notify("Saved.")
|
|
# return
|
|
|
|
# def get_new_statement(self):
|
|
# text = "\"\", " if not self.args["text"] else "\"{}\", ".format(self.args["text"].replace("\"", "\\\""))
|
|
|
|
# mouth = "" if self.args["mouth"] == False else "\"{}\", ".format(self.args["mouth"])
|
|
# eyes = "" if self.args["eyes"] == False else "\"{}\", ".format(self.args["eyes"])
|
|
# eyebrows = "" if self.args["eyebrows"] == False else "\"{}\", ".format(self.args["eyebrows"])
|
|
# pupils = "" if self.args["pupils"] == False else "\"{}\", ".format(self.args["pupils"])
|
|
# hair = "" if self.label != "ton_main" or self.args["hair"] in (None, "(No change)") else "hair=\"{}\", ".format(self.args["hair"])
|
|
|
|
# cheeks = "" if self.args["cheeks"] in (None, "(No change)") else "cheeks=\"{}\", ".format(self.args["cheeks"])
|
|
# tears = "" if self.args["tears"] in (None, "(No change)") else "tears=\"{}\", ".format(self.args["tears"])
|
|
# emote = "" if self.args["emote"] == None else "emote=\"{}\", ".format(self.args["emote"])
|
|
# face = "" if self.args["face"] == None else "face=\"{}\", ".format(self.args["face"])
|
|
|
|
# xpos = self.args["xpos"]
|
|
# if xpos == None:
|
|
# xpos = ""
|
|
# else:
|
|
# xpos = "xpos={}, ".format(xpos) if is_integer(xpos) else "xpos=\"{}\", ".format(xpos)
|
|
|
|
# ypos = self.args["ypos"]
|
|
# if ypos == None:
|
|
# ypos = ""
|
|
# else:
|
|
# ypos = "ypos={}, ".format(ypos) if is_integer(ypos) else "ypos=\"{}\", ".format(ypos)
|
|
|
|
# flip = "" if self.args["flip"] == None else "flip={}, ".format(self.args["flip"])
|
|
# trans = "" if self.args["trans"] == None else "trans={}, ".format(self.args["trans"])
|
|
# animation = "" if self.args["animation"] == False else "animation={}".format(self.args["animation"])
|
|
|
|
# new = "call {}({}{}{}{}{}{}{}{}{}{}{}{}{}{}{})".format(self.label, text, mouth, eyes, eyebrows, pupils, hair, cheeks, tears, emote, face, xpos, ypos, flip, trans, animation)
|
|
|
|
# new = new.replace(", )", ")")
|
|
# return new
|
|
|
|
# def catch(self, label):
|
|
# # Get file and line number
|
|
# stack = renpy.get_return_stack()[-1]
|
|
# node = renpy.game.script.namemap.get(stack, None)
|
|
|
|
# # Console call fallback
|
|
# if node.filename == "<string>":
|
|
# return
|
|
|
|
# self._file = config.basedir+"/"+node.filename
|
|
# self.line = node.linenumber
|
|
# self.label = label
|
|
|
|
|
|
# if self.changes.get(self._file, _dict()).get(self.line, None):
|
|
# # Get arguments from cache
|
|
# self.args = self.changes[self._file][self.line][2]
|
|
# else:
|
|
# # Get arguments from node
|
|
# node = renpy.game.script.lookup_or_none(self.label)
|
|
# self.args = _dict([(k, getattr(store, k)) for k in node.parameters.apply(None, None).iterkeys()])
|
|
|
|
# if self.args["cheeks"] == None:
|
|
# self.args["cheeks"] = "(No change)"
|
|
# if self.args["tears"] == None:
|
|
# self.args["tears"] = "(No change)"
|
|
# if self.label == "ton_main":
|
|
# if self.args["hair"] == None:
|
|
# self.args["hair"] = "(No change)"
|
|
|
|
# # Lookup transition name (Reverse lookup)
|
|
# trans_arg = self.args["trans"]
|
|
|
|
# if trans_arg:
|
|
# self.args["trans"] = lookup(trans_arg)
|
|
|
|
# #_transitions = _dict([(obj.callable, name) for (name, obj) in store.__dict__.iteritems() if name in self.transitions])
|
|
# #self.args["trans"] = _transitions[self.args["trans"].callable]
|
|
|
|
# # Lookup transform name
|
|
# anim_arg = self.args["animation"]
|
|
|
|
# if not anim_arg in (False, None):
|
|
# #self.args["animation"] = lookup(anim_arg)
|
|
|
|
# _transforms = _dict([(obj, name) for (name, obj) in store.__dict__.iteritems() if isinstance(obj, renpy.atl.ATLTransformBase)])
|
|
# self.args["animation"] = _transforms[anim_arg]
|
|
|
|
# # Check for already made changes and hijack the line.
|
|
# if self.changes.get(self._file, _dict()).get(self.line, None):
|
|
# self.line_contents = self.changes[self._file][self.line][1]
|
|
# else:
|
|
# # Read file and find the line in question
|
|
# with open(self._file, "U") as f:
|
|
# for n, l in enumerate(f, 1):
|
|
# if n == self.line:
|
|
# l = l.partition("#")[0].strip() # Ignore comments and strip spaces
|
|
# if l.startswith("call {}".format(self.label)):
|
|
# self.line_contents = l
|
|
# break
|
|
# return
|
|
|
|
# def set_data(self, arg, val):
|
|
# if not isinstance(val, basestring):
|
|
# return
|
|
|
|
# if self.args[arg] != val:
|
|
# self.args[arg] = val
|
|
# self.overwrite_statement()
|
|
|
|
# def get_tooltip(self, file, line):
|
|
|
|
# if self.changes[file][line][4] == None:
|
|
# imagepath = config.basedir.replace("\\", "/")
|
|
# args = self.changes[file][line][2]
|
|
# char = self.changes[file][line][3]
|
|
|
|
# if char == "hermione":
|
|
# hair = her_hair_base
|
|
# box = (450, 275, 320, 240)
|
|
# elif char == "tonks":
|
|
# hair = ton_hair_base_new
|
|
# box = (450, 275, 320, 240)
|
|
# elif char == "astoria":
|
|
# hair = ast_hair_base
|
|
# box = (450, 320, 280, 240)
|
|
# elif char == "cho":
|
|
# hair = cho_hair_ponytail1
|
|
# box = (450, 310, 280, 240)
|
|
# elif char == "susan":
|
|
# hair = sus_hair_base
|
|
# box = (450, 310, 280, 240)
|
|
# elif char == "luna":
|
|
# hair = lun_hair_base
|
|
# box = (450, 310, 280, 240)
|
|
# elif char == "hooch":
|
|
# hair = hoo_hair_base
|
|
# box = (370, 240, 280, 240)
|
|
|
|
# sprites = [imagepath+"/game/characters/"+char+"/body/base/front.webp"]
|
|
|
|
# if not "No change" in args["cheeks"]:
|
|
# sprites.append(imagepath+"/game/characters/"+char+"/face/cheeks/"+args["cheeks"]+".webp")
|
|
# sprites.append(imagepath+"/game/characters/"+char+"/face/eyes/"+args["eyes"]+".webp")
|
|
# if not any(x in args["eyes"] for x in ("closed", "happyCl")):
|
|
# m = imagepath+"/game/characters/"+char+"/face/eyes/"+args["eyes"]+"_mask.webp"
|
|
# sprites.append(AlphaMask(imagepath+"/game/characters/"+char+"/face/pupils/"+args["pupils"]+".webp", m))
|
|
# sprites.append(imagepath+"/game/characters/"+char+"/face/eyebrows/"+args["eyebrows"]+".webp")
|
|
# if not "No change" in args["tears"]:
|
|
# sprites.append(imagepath+"/game/characters/"+char+"/face/tears/"+args["tears"]+".webp")
|
|
# sprites.append(imagepath+"/game/characters/"+char+"/face/mouth/"+args["mouth"]+".webp")
|
|
|
|
# # Hair
|
|
# sprites.append(hair.get_back()[0])
|
|
# if hair.back_outline:
|
|
# sprites.append(hair.back_outline)
|
|
# sprites.append(hair.get_image())
|
|
|
|
# sprites = tuple(itertools.chain.from_iterable(((0,0), x) for x in sprites))
|
|
|
|
# self.changes[file][line][4] = At(Crop(box, Composite((1010, 1200), *sprites)), Transform(zoom=0.5))
|
|
# return self.changes[file][line][4]
|
|
|
|
# def set_expressions(self):
|
|
# if not self.char or not self.label:
|
|
# return
|
|
|
|
# c = getattr(renpy.store, self.char[self.label])
|
|
|
|
# cheeks = None if self.args["cheeks"] in (None, "(No change)") else self.args["cheeks"]
|
|
# tears = None if self.args["tears"] in (None, "(No change)") else self.args["tears"]
|
|
|
|
# if self.label == "ton_main":
|
|
# hair = None if self.args["hair"] in (None, "(No change)") else self.args["hair"]
|
|
|
|
# # Hardcoded for tonks
|
|
# if hair:
|
|
# if hair in ("neutral", "basic", "reset"):
|
|
# target_color = tonks_haircolor
|
|
# elif hair in ("red", "angry", "furious"):
|
|
# target_color = [[164, 34, 34, 255], [219, 83, 83, 255]]
|
|
# elif hair in ("orange", "upset", "annoyed"):
|
|
# target_color = [[228, 93, 34, 255], [246, 193, 170, 255]]
|
|
# elif hair in ("yellow", "happy", "cheerful"):
|
|
# target_color = [[255, 213, 23, 255], [255, 239, 167, 255]]
|
|
# elif hair in ("green", "disgusted"):
|
|
# target_color = [[111, 205, 75, 255], [200, 237, 186, 255]]
|
|
# elif hair in ("blue", "sad"):
|
|
# target_color = [[64, 75, 205, 255], [182, 186, 237, 255]]
|
|
# elif hair == "purple":
|
|
# target_color = [[205, 75, 205, 255], [237, 186, 237, 255]]
|
|
# elif hair in ("white", "scared"):
|
|
# target_color = [[238, 238, 241, 255], [249, 249, 250, 255]]
|
|
# elif hair in ("pink", "horny"):
|
|
# target_color = [[255, 105, 180, 255], [251, 205, 222, 255]]
|
|
|
|
# tonks.get_equipped("hair").set_color(target_color)
|
|
|
|
# c.set_face(mouth=self.args["mouth"], eyes=self.args["eyes"], eyebrows=self.args["eyebrows"], pupils=self.args["pupils"], cheeks=cheeks, tears=tears)
|
|
|
|
# def get_expressions(self, type):
|
|
# return sorted(self.expressions[self.char[self.label]][type])
|
|
|
|
# def define_expressions(self):
|
|
# def scan_files(char):
|
|
# dirs = {
|
|
# "mouth": None,
|
|
# "eyes": None,
|
|
# "eyebrows": None,
|
|
# "pupils": None,
|
|
# "cheeks": None,
|
|
# "tears": None,
|
|
# "hair": ["(No change)", "neutral", "angry", "upset", "happy", "disgusted", "sad", "purple", "scared", "horny"],
|
|
# }
|
|
|
|
# for k, v in dirs.iteritems():
|
|
# if k == "hair":
|
|
# continue
|
|
|
|
# path = "{}/game/characters/{}/face/{}/".format(config.basedir, char, k)
|
|
|
|
# if not os.path.exists(path):
|
|
# os.makedirs(path)
|
|
|
|
# dirs[k] = list(x.rsplit(".webp")[0] for x in os.listdir(path) if x.endswith(".webp") and not "_mask" in x and not "_skin" in x)
|
|
|
|
# dirs["cheeks"] += ["(No change)"]
|
|
# dirs["tears"] += ["(No change)"]
|
|
|
|
# return _dict(dirs)
|
|
|
|
# self.expressions = _dict([(x, scan_files(x)) for x in self.char.itervalues()])
|
|
|
|
# def editor_reset():
|
|
# editor.changes = _dict()
|
|
|
|
# if config.developer and not renpy.mobile:
|
|
# editor = ExpressionEditor()
|
|
|
|
# config.label_callback = catch_character_call
|
|
# config.after_load_callbacks.append(editor_reset)
|
|
# config.interact_callbacks.append(editor.set_expressions)
|
|
|
|
# screen editor():
|
|
# layer "interface"
|
|
# tag editor
|
|
# zorder 0
|
|
# style_prefix "editor"
|
|
|
|
# default minimised = False
|
|
# default minimised_history = False
|
|
# default minimised_cg = False
|
|
# default frame_size = (250, 500)
|
|
|
|
# default expressions = ("mouth", "eyes", "eyebrows", "pupils", "cheeks", "tears", "hair")
|
|
|
|
# if config.developer and not _menu:
|
|
|
|
# # Editor
|
|
# drag:
|
|
# drag_name "editor"
|
|
# draggable True
|
|
# drag_offscreen False
|
|
# drag_handle (0, 0, 1.0, 26)
|
|
# pos (50, 50)
|
|
|
|
# window:
|
|
# background "#00000080"
|
|
# xysize (frame_size if not minimised else (250, 28))
|
|
|
|
# button action NullAction() style "empty" ypos 18
|
|
|
|
# text "Expression Editor {size=-2}ver 0.2{/size}" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised else "Minimise")
|
|
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
|
|
|
|
# frame:
|
|
# style "empty"
|
|
# xysize (236, 2)
|
|
# pos (0, 18)
|
|
# background "#FFFFFF80"
|
|
|
|
# if not minimised:
|
|
# if editor.label:
|
|
# $ f = editor._file.split("/")[-1]
|
|
# $ l = editor.line
|
|
|
|
# vbox:
|
|
# ypos 24
|
|
|
|
# for i in expressions:
|
|
# if i == "hair" and not editor.label == "ton_main":
|
|
# pass
|
|
# else:
|
|
# text i size 14 color "#fff" outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# hbox:
|
|
# xpos 12
|
|
# box_wrap True
|
|
|
|
# for j in editor.get_expressions(i):
|
|
# textbutton j:
|
|
# selected (j == editor.args[i])
|
|
# action Function(editor.set_data, i, j)
|
|
# text_size 8
|
|
# text_selected_color "#009900"
|
|
# text_xalign 0.5
|
|
# xminimum 32
|
|
|
|
# # History
|
|
# drag:
|
|
# drag_name "editor_history"
|
|
# draggable True
|
|
# drag_offscreen False
|
|
# drag_handle (0, 0, 1.0, 26)
|
|
# pos (300, 50)
|
|
# frame:
|
|
# background "#00000080"
|
|
# xysize (frame_size if not minimised_history else (250, 28))
|
|
# button action NullAction() style "empty" xysize (frame_size if not minimised_history else (250, 28)) ypos 18
|
|
|
|
# text "History" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised_history", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised_history else "Minimise")
|
|
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
|
|
|
|
# frame:
|
|
# style "empty"
|
|
# xysize (236, 2)
|
|
# pos (0, 18)
|
|
# background "#FFFFFF80"
|
|
|
|
# if not minimised_history:
|
|
# if editor.changes:
|
|
# $ n = 0
|
|
# $ nn = 0
|
|
# for k, v in editor.changes.iteritems():
|
|
# $ n += 1
|
|
# $ nn += len(v)
|
|
# text "[nn] changes in [n] files" size 10 color "#FFF" xalign 0.5 ypos 26 outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# frame:
|
|
# style "empty"
|
|
# xsize 236
|
|
# ymaximum 400
|
|
# yfill True
|
|
# ypos 42
|
|
|
|
# side "c r":
|
|
# area (0, 0, 236, 400)
|
|
|
|
# viewport id "editor_history":
|
|
# draggable False
|
|
# mousewheel True
|
|
|
|
# vbox:
|
|
# for fn in editor.changes.iterkeys():
|
|
# text (fn.split("/")[-1]) size 10 color "#FFF" xalign 0.5 outlines [(1, "#00000080", 1, 0)]
|
|
# frame style "empty" xysize (236, 2) background "#FFFFFF80"
|
|
|
|
# for l in editor.changes[fn].iterkeys():
|
|
# textbutton "Line [l]":
|
|
# text_size 10
|
|
# text_color "#FFF"
|
|
# text_outlines [(1, "#00000080", 1, 0)]
|
|
# if editor.line == l:
|
|
# background "#FFFFFF80"
|
|
# tooltip editor.get_tooltip(fn, l)
|
|
# action Function(editor.launch_editor, file=fn, line=l)
|
|
# vbar value YScrollValue("editor_history") xsize 10
|
|
# else:
|
|
# text "No history." size 15 color "#FFF" align (0.5, 0.5) outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# # CG poser
|
|
|
|
# if renpy.get_screen("animatedCG"):
|
|
# drag:
|
|
# drag_name "editor_cg"
|
|
# draggable True
|
|
# drag_offscreen False
|
|
# drag_handle (0, 0, 1.0, 26)
|
|
# pos (550, 50)
|
|
# frame:
|
|
# background "#00000080"
|
|
# xysize (frame_size if not minimised_cg else (250, 28))
|
|
# button action NullAction() style "empty" xysize (frame_size if not minimised_cg else (250, 28)) ypos 18
|
|
|
|
# text "CG Poser" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
|
|
|
|
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised_cg", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised_history else "Minimise")
|
|
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
|
|
|
|
# frame:
|
|
# style "empty"
|
|
# xysize (236, 2)
|
|
# pos (0, 18)
|
|
# background "#FFFFFF80"
|
|
|
|
# if not minimised_cg:
|
|
|
|
# $ x, y = camera.pos
|
|
# $ zoom = camera.zoom
|
|
# $ rotate = camera.rotate
|
|
# default pos_step = 5
|
|
# default zoom_step = 0.05
|
|
# default rotate_step = 5
|
|
# vbox:
|
|
# text "Pos Step ({})".format(pos_step) color "#fff"
|
|
# hbox:
|
|
# textbutton "-":
|
|
# action SetScreenVariable("pos_step", max(pos_step-5, 5))
|
|
# textbutton "+":
|
|
# action SetScreenVariable("pos_step", min(pos_step+5, 100))
|
|
# text "Pos (x={}, y={})".format(x, y) color "#fff"
|
|
# hbox:
|
|
# textbutton "X-":
|
|
# action [SetVariable("camera.pos", (x-pos_step, y)), Function(camera.redraw, 0)]
|
|
# textbutton "X+":
|
|
# action [SetVariable("camera.pos", (x+pos_step, y)), Function(camera.redraw, 0)]
|
|
# hbox:
|
|
# textbutton "Y-":
|
|
# action [SetVariable("camera.pos", (x, y-pos_step)), Function(camera.redraw, 0)]
|
|
# textbutton "Y+":
|
|
# action [SetVariable("camera.pos", (x, y+pos_step)), Function(camera.redraw, 0)]
|
|
|
|
# null height 20
|
|
|
|
# text "Zoom Step ({})".format(zoom_step) color "#fff"
|
|
# hbox:
|
|
# textbutton "-":
|
|
# action SetScreenVariable("zoom_step", max(zoom_step-0.01, 0.01))
|
|
# textbutton "+":
|
|
# action SetScreenVariable("zoom_step", min(zoom_step+0.01, 0.25))
|
|
# text "Zoom (zoom={})".format(zoom) color "#fff"
|
|
# hbox:
|
|
# textbutton "-":
|
|
# action [SetVariable("camera.zoom", zoom-zoom_step), Function(camera.redraw, 0)]
|
|
# textbutton "+":
|
|
# action [SetVariable("camera.zoom", zoom+zoom_step), Function(camera.redraw, 0)]
|
|
|
|
# null height 20
|
|
|
|
# text "Rotate Step ({})".format(rotate_step) color "#fff"
|
|
# hbox:
|
|
# textbutton "-":
|
|
# action SetScreenVariable("rotate_step", max(rotate_step-1, 1))
|
|
# textbutton "+":
|
|
# action SetScreenVariable("rotate_step", min(rotate_step+1, 1))
|
|
# text "Rotate ({})".format(rotate) color "#fff"
|
|
# hbox:
|
|
# textbutton "-":
|
|
# action [SetVariable("camera.rotate", rotate-rotate_step), Function(camera.redraw, 0)]
|
|
# textbutton "+":
|
|
# action [SetVariable("camera.rotate", rotate+rotate_step), Function(camera.redraw, 0)]
|
|
|
|
# null height 50
|
|
# textbutton "Copy to Clipboard" action [Function(set_clipboard, "$ camera.set(zoom={}, pos=({}, {}), rotate={}, t=1.0)".format(zoom, x, y, rotate)), Notify("Copied!")]
|
|
|
|
# style editor_button is empty:
|
|
# margin (3, 3)
|
|
|
|
# style editor_button_text:
|
|
# color "#cccccc"
|
|
# hover_color "#ffffff"
|
|
# outlines [(1, "#00000080", 1, 0)]
|