mirror of
https://github.com/bendtherules/pyFun.git
synced 2026-08-18 13:52:46 +00:00
323 lines
12 KiB
Python
323 lines
12 KiB
Python
# Utility functions
|
|
# ToDo: Put everything in a class as staticmethods when imported, if
|
|
# name=__main__, keep them local
|
|
from pygame import locals as pygame_consts
|
|
from functools import partial
|
|
import inspect
|
|
import logging
|
|
import types
|
|
import pygame
|
|
from uniquelist import uniquelist
|
|
|
|
|
|
def register(list_to_register=None):
|
|
''' Used as decorator: Adds the function (or anything else) to list_to_register '''
|
|
def temp_func(what_to_register):
|
|
list_to_register.append(what_to_register)
|
|
return what_to_register
|
|
return temp_func
|
|
|
|
KW_EVENTS_IB = {
|
|
"QUIT": pygame_consts.QUIT,
|
|
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
|
|
"KEY_DOWN": pygame_consts.KEYDOWN,
|
|
"KEY_UP": pygame_consts.KEYUP,
|
|
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
|
|
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
|
|
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
|
|
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
|
|
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
|
|
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
|
|
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
|
|
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
|
|
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
|
|
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
|
|
# "USER_EVENT": pygame_consts.USEREVENT,
|
|
# think of begin_step, step and end_step
|
|
}
|
|
|
|
# Make kw_events_user automatically
|
|
|
|
LIST_EVENTS_USER = ["BEGIN_STEP", "STEP", "DRAW", "END_STEP"]
|
|
|
|
KW_EVENTS_USER = {}
|
|
KW_EVENTS_ALL = {}
|
|
|
|
|
|
def populate_KW_EVENTS_USER(LIST_EVENTS_USER=LIST_EVENTS_USER):
|
|
'''Populates KW_EVENTS_USER and also updates KW_EVENTS_ALL'''
|
|
tmp_event_numb = pygame_consts.USEREVENT
|
|
for tmp_event_name in LIST_EVENTS_USER:
|
|
KW_EVENTS_USER[tmp_event_name] = tmp_event_numb
|
|
tmp_event_numb += 1
|
|
global KW_EVENTS_ALL
|
|
KW_EVENTS_ALL = {}
|
|
for tmp_event_name in KW_EVENTS_IB:
|
|
KW_EVENTS_ALL[tmp_event_name] = KW_EVENTS_IB[tmp_event_name]
|
|
for tmp_event_name in KW_EVENTS_USER:
|
|
KW_EVENTS_ALL[tmp_event_name] = KW_EVENTS_USER[tmp_event_name]
|
|
# populated by default, may be repopulated later
|
|
populate_KW_EVENTS_USER()
|
|
|
|
CUE_EVENTS_IB = "unordered IB events here"
|
|
LIST_EVENTS_ORDERED = [KW_EVENTS_USER["BEGIN_STEP"], CUE_EVENTS_IB, KW_EVENTS_USER["STEP"],
|
|
KW_EVENTS_USER["DRAW"], KW_EVENTS_USER["END_STEP"]]
|
|
|
|
|
|
def sort_events(ev1, ev2):
|
|
ev_args = [ev1, ev2]
|
|
args_pos = [None, None]
|
|
# fix next line
|
|
for tmp_index in range(len(ev_args)):
|
|
tmp_ev = ev_args[tmp_index]
|
|
if (tmp_ev.type in KW_EVENTS_IB.values()):
|
|
args_pos[tmp_index] = LIST_EVENTS_ORDERED.index(CUE_EVENTS_IB)
|
|
elif (tmp_ev.type in KW_EVENTS_USER.values()):
|
|
args_pos[tmp_index] = LIST_EVENTS_ORDERED.index(tmp_ev.type)
|
|
tmp_diff = args_pos[0] - args_pos[1]
|
|
# convert -ve to -1, 0 to 0, +ve to +1
|
|
if tmp_diff == 0:
|
|
tmp_diff_unit = 0
|
|
else:
|
|
tmp_diff_unit = tmp_diff / abs(tmp_diff)
|
|
return tmp_diff_unit
|
|
|
|
|
|
def append_user_events(list_):
|
|
for temp_ev_name in LIST_EVENTS_USER:
|
|
temp_ev_numb = KW_EVENTS_USER[temp_ev_name]
|
|
list_.append(pygame.event.Event(temp_ev_numb))
|
|
return list_
|
|
|
|
|
|
def fuzzy_match_event_name(string, event_or_action):
|
|
str_upper = string.upper()
|
|
if not (str_upper in KW_EVENTS_ALL):
|
|
event_or_action = event_or_action.lower()
|
|
if event_or_action.lower() == "event" or event_or_action.lower() == "action":
|
|
# STR_STARTER becomes event_ or action_
|
|
STR_STARTER = event_or_action.upper() + "_"
|
|
else:
|
|
raise AttributeError(
|
|
"event_or_action arg must be 'event' or 'action'.")
|
|
str_normalized = str_upper[
|
|
str_upper.find(STR_STARTER) + len(STR_STARTER):]
|
|
for tmp_event_name in KW_EVENTS_ALL:
|
|
# tmp event is the event_name, keys of KW_EVENTS
|
|
tmp_event_name_normalized = tmp_event_name.replace("_", "")
|
|
if str_normalized.startswith(tmp_event_name) or str_normalized.startswith(tmp_event_name_normalized):
|
|
return tmp_event_name
|
|
else:
|
|
return str_upper
|
|
|
|
|
|
class Action(object):
|
|
|
|
""" pygame.event.Action(type, dict): return Action
|
|
pygame.Action.Action(type, **attributes): return Action
|
|
"""
|
|
|
|
def __init__(self, type, *args, **kwargs):
|
|
super(Action, self).__init__()
|
|
self.type = type
|
|
_dict = {}
|
|
if len(args) == 1:
|
|
_dict.update(args[0])
|
|
elif len(args) > 1:
|
|
raise TypeError(
|
|
"Max one non-keyword argument allowed (which is set to dict)")
|
|
if kwargs:
|
|
_dict.update(kwargs)
|
|
if _dict:
|
|
self.dict = _dict
|
|
|
|
|
|
def copy_func(f, name=None):
|
|
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
|
|
f.func_defaults, f.func_closure)
|
|
|
|
|
|
def selfie_depreceated(f):
|
|
"""Decorate function `f` to pass a reference to the function
|
|
as the first argument"""
|
|
return partial(f, f)
|
|
|
|
|
|
def selfie(f):
|
|
"""Decorate function `f` to pass a reference to the function
|
|
as the first argument"""
|
|
return f.__get__(f, type(f))
|
|
|
|
|
|
def sync_func(func1, func2):
|
|
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
|
|
func1.func_code = func2.func_code
|
|
func1.func_defaults = func2.func_defaults
|
|
func1.func_dict = func2.func_dict
|
|
func1.func_doc = func2.func_doc
|
|
func1.func_name = func2.func_name
|
|
|
|
|
|
class meta_accessor_class(type):
|
|
|
|
''' This metaclass allows class access to any function (or as extended use, to metaclasses)'''
|
|
# Using metaclass and decorator to allow class access during class creation time
|
|
# No method defined within the class should have "_process_meta" as arg
|
|
# Potential problems: Using closures, function.func_globals is read-only
|
|
# Doesnt get appropiate globals, maybe pass it (or the reqd global vars)
|
|
# as param on func defn
|
|
def __new__(cls, name, base, clsdict):
|
|
temp_cls = type.__new__(cls, name, base, clsdict)
|
|
temp_cls.list_instance = uniquelist()
|
|
temp_cls.list_check_func = uniquelist()
|
|
# dict_action_func -> dict of action funcs, key=event_numb like KEYDOWN
|
|
temp_cls.dict_action_func = {}
|
|
methods = inspect.getmembers(temp_cls, inspect.ismethod)
|
|
for (method_name, method_obj) in methods:
|
|
if fuzzy_match_event_name(method_name, "action"):
|
|
temp_cls.register_event(method_obj)
|
|
return temp_cls
|
|
|
|
|
|
@selfie
|
|
def run_dec_on_meta(self, what_to_do):
|
|
'''Runs decorator (what_to_do) passed to it during meta with args, cls=>class and func=>function which this is used on'''
|
|
# make copies of this func and instead of params use .vars. Should accept
|
|
# *args,*kwargs to main_func. Next step: multiple funcs, think.
|
|
|
|
def inter_run_dec_on_meta(*args, **kwargs):
|
|
# this intermediate func is used to produce func_process_meta for each
|
|
# time
|
|
def func_process_meta(self, *args, **kwargs):
|
|
if not hasattr(self, "_process_meta"):
|
|
# changing own's state, should be restored at last step before
|
|
# meta-return
|
|
self._process_meta = False
|
|
#(below) unneccesary here
|
|
if not hasattr(self, "__old_args") and not hasattr(self, "__old_kwargs"):
|
|
self.__old_args = None
|
|
self.__old_kwargs = None
|
|
if not self._process_meta:
|
|
# as long as not being meta-processed
|
|
# its not really main_func, really its just what_to_do's param
|
|
if (self.__old_args or self.__old_kwargs):
|
|
self.what_to_do = partial(
|
|
self.what_to_do, *(self.__old_args), **(self.__old_kwargs))
|
|
self.__old_args = args
|
|
self.__old_kwargs = kwargs
|
|
return selfie(self)
|
|
else:
|
|
self.main_func = self.__old_args[0]
|
|
return self
|
|
|
|
func_process_meta.__old_args = args
|
|
func_process_meta.__old_kwargs = kwargs
|
|
func_process_meta.what_to_do = what_to_do
|
|
func_process_meta.selfie = True
|
|
func_process_meta = selfie(func_process_meta)
|
|
return func_process_meta
|
|
return inter_run_dec_on_meta
|
|
|
|
|
|
def run_func_on_meta(run_func):
|
|
'''Runs func (run_func) passed to it during meta with arg, cls.
|
|
run_func remains a method of the class.'''
|
|
run_func._run_meta = True
|
|
return run_func
|
|
|
|
|
|
def register_event(event_name=None, func_to_register=None, cls=None):
|
|
'''
|
|
@fun_Class.register_event() # @fun_Class.register_event === @fun_Class.register_event()
|
|
def event_key_down(ev):
|
|
pass
|
|
OR
|
|
# event_name=KEYDOWN (or "key_down")
|
|
@fun_Class.register_event(event_name)
|
|
def whatever(ev):
|
|
pass
|
|
OR
|
|
fun_Class.register_event(event_name,func)
|
|
'''
|
|
if (event_name is None) and (func_to_register is None):
|
|
# i.e No param passed, used as decorator (1st step of ex. 1)
|
|
logging.info("Nothing passed")
|
|
return register_event
|
|
elif (not(event_name is None)) and (func_to_register is None):
|
|
# i.e. one param is passed, maybe func or (str or int)
|
|
logging.info("Event Name only passed")
|
|
if isinstance(event_name, str):
|
|
# i.e. 1st parm-> str , is event name, acts as decorator
|
|
# (2nd ex.)
|
|
# dont hardcode func name- use metaclass
|
|
logging.info("Event Name is event_name")
|
|
return partial(cls.register_event, event_name)
|
|
elif hasattr(event_name, "__call__"):
|
|
# first param is func, actually func_to_register.
|
|
# So get event_name from func_name (2nd step of 1st ex.)
|
|
logging.info("Event Name is actually func")
|
|
func_to_register = event_name
|
|
event_name = fuzzy_match_event_name(
|
|
func_to_register.func_name, "action")
|
|
return register_event(event_name=event_name, func_to_register=func_to_register, cls=cls)
|
|
else:
|
|
raise TypeError("event_name must be str or func")
|
|
else:
|
|
# Both params present
|
|
logging.info("Both param passed")
|
|
|
|
if isinstance(event_name, str):
|
|
event_name = fuzzy_match_event_name(event_name, "action")
|
|
|
|
logging.info("Registering func")
|
|
if not (event_name in cls.dict_action_func):
|
|
cls.dict_action_func[event_name] = []
|
|
cls.dict_action_func[event_name].append(func_to_register)
|
|
|
|
return func_to_register
|
|
|
|
|
|
def register_class(game_class, cls=None):
|
|
''' Register this class on mega_class.
|
|
Calls _regitser_class_ on mega_class with arg cls'''
|
|
if cls is None:
|
|
return partial(register_class, game_class)
|
|
game_class.register_class(cls)
|
|
cls.Game = game_class
|
|
return cls
|
|
|
|
|
|
def remove_from_list(list_, val, recursive=False):
|
|
if val in list_:
|
|
list_.remove(val)
|
|
if recursive:
|
|
while (val in list_):
|
|
list_.remove(val)
|
|
return list_
|
|
|
|
|
|
def rect_to_pygame_rect(rect):
|
|
if hasattr(rect, "bbox"):
|
|
rect = rect.bbox
|
|
return rect
|
|
|
|
|
|
# _register_event_ = register_event
|
|
# del register_event
|
|
# so that register event is actually delegated register
|
|
# register_event = run_dec_on_meta(_register_event_)
|
|
|
|
# Move to test
|
|
##import pygame
|
|
# pygame.init()
|
|
##evs = []
|
|
# evs.append(pygame.event.Event(KW_EVENTS_IB["KEY_DOWN"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_IB["JOY_AXIS_MOTION"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_IB["KEY_UP"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_IB["MOUSE_BUTTON_UP"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_USER["DRAW"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_USER["BEGIN_STEP"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_USER["END_STEP"]))
|
|
# evs.append(pygame.event.Event(KW_EVENTS_USER["STEP"]))
|
|
# evs.sort(sort_events)
|