Skip to content

Commit eec2e6a

Browse files
upgrade selecting
Clicking will now have a small radius around it, so that small things (like path points) are easier to click. I also added the ability to right click a path point, and delete it (as well as using the delete key). Currently it does not automatically decrease the other path point numbers, but that may come later. I also made sure that using the arrow keys does not move the selection in the object selector (by just shifting focus to the level canvas after clicking).
1 parent 9ab9a8b commit eec2e6a

File tree

1 file changed

+132
-74
lines changed

1 file changed

+132
-74
lines changed

src/main.py

+132-74
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,15 @@ def updateObject(self, obj : wmwpy.classes.Object | None):
852852
image = obj.foreground_PhotoImage,
853853
tags = ('object', 'foreground', id)
854854
)
855+
856+
if len(obj._foreground) == 0 and len(obj._background) == 0:
857+
self.level_canvas.create_image(
858+
canvas_pos[0],
859+
canvas_pos[1],
860+
anchor = 'c',
861+
image = ImageTk.PhotoImage(Image.new('RGBA', (1, 1), 'black')),
862+
tags = ('object', 'foreground', id),
863+
)
855864

856865
if (obj == self.selectedObject or self.settings.get('view.radius', True)) and obj.Type is not None:
857866
properties = filter(lambda name : obj.Type.PROPERTIES[name].get('type', 'string') == 'radius', obj.Type.PROPERTIES)
@@ -924,21 +933,22 @@ def updateObject(self, obj : wmwpy.classes.Object | None):
924933
tags = ('part', 'path', property, 'pathPoint', id),
925934
)
926935

927-
if is_closed:
928-
line = self.level_canvas.create_polygon(
929-
path_canvas_points,
930-
fill = '',
931-
outline = 'black',
932-
width = 2,
933-
tags = ('passthrough', 'part', 'path', property, 'pathLine', id),
934-
)
935-
else:
936-
line = self.level_canvas.create_line(
937-
path_canvas_points,
938-
fill = 'black',
939-
width = 2,
940-
tags = ('passthrough', 'part', 'path', property, 'pathLine', id),
941-
)
936+
if len(path_canvas_points) > 1:
937+
if is_closed:
938+
line = self.level_canvas.create_polygon(
939+
path_canvas_points,
940+
fill = '',
941+
outline = 'black',
942+
width = 2,
943+
tags = ('passthrough', 'part', 'path', property, 'pathLine', id),
944+
)
945+
else:
946+
line = self.level_canvas.create_line(
947+
path_canvas_points,
948+
fill = 'black',
949+
width = 2,
950+
tags = ('passthrough', 'part', 'path', property, 'pathLine', id),
951+
)
942952

943953
# self.level_canvas.tag_bind(line, '<Button-1>', self.onLevelClick)
944954

@@ -952,27 +962,34 @@ def updateObject(self, obj : wmwpy.classes.Object | None):
952962

953963
self.updateSelectionRectangle()
954964
self.updateLevelScroll()
955-
956965

957-
def onLevelClick(self, event : tk.Event):
958-
logging.debug('level')
959-
960-
if self.level == None:
961-
return
962-
963-
mouse = (self.level_canvas.canvasx(event.x), self.level_canvas.canvasy(event.y))
966+
967+
def selectObjectAt(
968+
self,
969+
pos: tuple[float, float] | list[float] | tk.Event,
970+
halo: int | float = 5,
971+
):
972+
event = None
973+
if isinstance(pos, tk.Event):
974+
event = pos
975+
logging.debug(f'select obj event: {event.__dict__}')
976+
pos = (pos.x, pos.y)
977+
978+
pos = (
979+
self.level_canvas.canvasx(pos[0]),
980+
self.level_canvas.canvasy(pos[1])
981+
)
964982

965983
# objects = self.level_canvas.find_overlapping(*mouse, *mouse)
966984
objects = self.level_canvas.find_overlapping(
967-
mouse[0] - 5, mouse[1] - 5,
968-
mouse[0] + 5, mouse[1] + 5,
985+
pos[0] - halo, pos[1] - halo,
986+
pos[0] + halo, pos[1] + halo,
969987
)
970988
logging.debug(f'under mouse: {objects}')
971-
# logging.debug(f'close: {close}')
972-
length = len(objects)
973989

974990
for id in reversed(objects):
975991
tags = self.level_canvas.gettags(id)
992+
logging.debug(f'tags: {tags}')
976993
if tags[0] in ['selection', 'level']:
977994
continue
978995

@@ -983,6 +1000,7 @@ def onLevelClick(self, event : tk.Event):
9831000

9841001
if tags[obj_tag].startswith('object-'):
9851002
obj = self.level.getObjectById(tags[obj_tag][7::])
1003+
logging.debug(f'obj: {obj}')
9861004
if obj == None:
9871005
continue
9881006
else:
@@ -994,24 +1012,36 @@ def onLevelClick(self, event : tk.Event):
9941012
continue
9951013
elif tags[0] == 'object':
9961014
logging.debug(f'selecting obj: {obj.name}')
997-
self.selectObject(obj)
998-
return
1015+
self.selectObject(obj, event)
1016+
return 'object', obj
9991017
elif tags[0] == 'part':
10001018
self.selectPart(
10011019
obj,
10021020
tags[1],
10031021
id,
10041022
tags[2],
10051023
)
1006-
return
1024+
return 'part', obj, self.selectedPart
10071025

10081026
self.selectObject(None)
1027+
1028+
return None, None
1029+
1030+
def onLevelClick(self, event : tk.Event):
1031+
logging.debug('level')
1032+
1033+
if self.level == None:
1034+
return
1035+
1036+
self.selectObjectAt(event)
10091037

10101038

10111039

10121040
def onLevelMove(self, event: tk.Event):
1013-
if self.selectedPart:
1041+
if self.selectedPart['type'] != None:
10141042
self.dragPart(event)
1043+
elif self.selectedObject:
1044+
self.dragObject(self.selectedObject, event)
10151045

10161046

10171047
def createLevelContextMenu(self):
@@ -1022,19 +1052,15 @@ def createLevelContextMenu(self):
10221052
def onLevelRightClick(self, event):
10231053
logging.debug('level context menu')
10241054

1025-
mouse = (self.level_canvas.canvasx(event.x), self.level_canvas.canvasy(event.y))
1055+
selected_type, selected_obj, *extra = self.selectObjectAt(event)
10261056

1027-
objects = self.level_canvas.find_overlapping(*mouse, *mouse)
1028-
logging.debug(objects)
1029-
length = len(objects)
1030-
1031-
if length <= 1:
1032-
if length == 1:
1033-
if objects[0] != self.level_images['background']:
1034-
return
1035-
1036-
self.selectObject(None)
1057+
if selected_type == None:
10371058
self.showPopup(self.levelContextMenu, event)
1059+
elif selected_type == 'object':
1060+
self.showPopup(self.createObjectContextMenu(selected_obj), event)
1061+
elif selected_type == 'part':
1062+
self.showPopup(self.createPartContextMenu(selected_obj, extra[0]), event)
1063+
10381064

10391065
def bindObject(self, id, obj : wmwpy.classes.Object | None = None):
10401066
if obj == None:
@@ -1043,26 +1069,26 @@ def bindObject(self, id, obj : wmwpy.classes.Object | None = None):
10431069
else:
10441070
return
10451071

1046-
self.level_canvas.tag_bind(
1047-
id,
1048-
'<Button1-Motion>',
1049-
lambda e, object = obj: self.dragObject(object, e)
1050-
)
1072+
# self.level_canvas.tag_bind(
1073+
# id,
1074+
# '<Button1-Motion>',
1075+
# lambda e, object = obj: self.dragObject(object, e)
1076+
# )
10511077

10521078
context_menu = self.createObjectContextMenu(obj)
10531079

1054-
if platform.system() == 'Darwin':
1055-
self.level_canvas.tag_bind(
1056-
id,
1057-
'<Button-2>',
1058-
lambda e, object = obj, menu = context_menu: self.showPopup(menu, e, callback = lambda : self.selectObject(object))
1059-
)
1060-
else:
1061-
self.level_canvas.tag_bind(
1062-
id,
1063-
'<Button-3>',
1064-
lambda e, object = obj, menu = context_menu: self.showPopup(menu, e, callback = lambda : self.selectObject(object))
1065-
)
1080+
# if platform.system() == 'Darwin':
1081+
# self.level_canvas.tag_bind(
1082+
# id,
1083+
# '<Button-2>',
1084+
# lambda e, object = obj, menu = context_menu: self.showPopup(menu, e, callback = lambda : self.selectObject(object))
1085+
# )
1086+
# else:
1087+
# self.level_canvas.tag_bind(
1088+
# id,
1089+
# '<Button-3>',
1090+
# lambda e, object = obj, menu = context_menu: self.showPopup(menu, e, callback = lambda : self.selectObject(object))
1091+
# )
10661092

10671093
def unbindObject(self, id):
10681094
self.level_canvas.tag_unbind(
@@ -1092,6 +1118,23 @@ def createObjectContextMenu(self, obj : wmwpy.classes.Object):
10921118
self.objectContextMenu.add_command(label = 'delete', command = lambda *args : self.deleteObject(obj), accelerator = 'Del')
10931119

10941120
return self.objectContextMenu
1121+
1122+
def createPartContextMenu(
1123+
self,
1124+
obj: wmwpy.classes.Object,
1125+
part: dict[
1126+
typing.Literal[
1127+
'type',
1128+
'id',
1129+
'property'
1130+
], str | None,
1131+
],
1132+
):
1133+
1134+
self.objectContextMenu.delete(0, 3)
1135+
self.objectContextMenu.add_command(label = 'delete', command = lambda *args : self.deleteProperty(obj, part['property']), accelerator = 'Del')
1136+
1137+
return self.objectContextMenu
10951138

10961139
def showPopup(self, menu : tk.Menu, event : tk.Event = None, callback : typing.Callable = None):
10971140
try:
@@ -1140,16 +1183,27 @@ def deleteObject(self, obj : wmwpy.classes.Object = None):
11401183
if obj == None:
11411184
return
11421185

1143-
self.level_canvas.delete(f'object-{str(obj.id)}')
1144-
1145-
if obj in self.level.objects:
1146-
index = self.level.objects.index(obj)
1147-
del self.level.objects[index]
1148-
1149-
if obj == self.selectedObject:
1150-
self.selectObject(None)
1151-
1152-
self.updateObjectSelector()
1186+
if self.selectedPart['type']:
1187+
self.deleteProperty(obj, self.selectedPart['property'])
1188+
else:
1189+
self.level_canvas.delete(f'object-{str(obj.id)}')
1190+
1191+
if obj in self.level.objects:
1192+
index = self.level.objects.index(obj)
1193+
del self.level.objects[index]
1194+
1195+
if obj == self.selectedObject:
1196+
self.selectObject(None)
1197+
1198+
self.updateObjectSelector()
1199+
1200+
def deleteProperty(self, obj: wmwpy.classes.Object, property: str):
1201+
if property in obj.properties:
1202+
del obj.properties[property]
1203+
1204+
self.updateObject(obj)
1205+
if self.selectedObject == obj:
1206+
self.updateProperties()
11531207

11541208
def checkLevelFocus(
11551209
self,
@@ -1729,6 +1783,7 @@ def selectObject(event: tk.Event):
17291783
item = self.object_selector['treeview'].selection()
17301784
# logging.debug(f"selection: {self.object_selector['treeview'].selection()}")
17311785
item = self.object_selector['treeview'].item(item)
1786+
self.level_canvas.focus_set()
17321787

17331788
if 'object' in item['tags']:
17341789
id = item['values'][2]
@@ -1799,7 +1854,6 @@ def rightClick(event):
17991854
self.showPopup(self.object_selector['menu'], event)
18001855

18011856
self.object_selector['treeview'].bind('<ButtonRelease-1>', selectObject)
1802-
self.object_selector['treeview'].bind('<Return>', selectObject)
18031857

18041858
if platform.system() == 'Darwin':
18051859
self.object_selector['treeview'].bind('<Button-2>', rightClick)
@@ -1918,7 +1972,7 @@ def getRelativeMousePos(self, pos : tuple, widget : tk.Widget):
19181972
def selectObject(
19191973
self,
19201974
obj : wmwpy.classes.Object = None,
1921-
event: tk.Event = None,
1975+
event: tk.Event | None = None,
19221976
partInfo: dict[str, str] = None,
19231977
):
19241978
self.selectedPart = {
@@ -1936,21 +1990,24 @@ def selectObject(
19361990
self.selectedPart['id'] = partInfo.get('id', None)
19371991
self.selectedPart['property'] = partInfo.get('property', None)
19381992

1939-
if event:
1940-
obj_pos = self.getObjectPosition(obj.pos, obj.offset)
1941-
self.dragInfo['offset'] = numpy.array((obj_pos[0], obj_pos[1])) - (self.level_canvas.canvasx(event.x), self.level_canvas.canvasy(event.y))
19421993

19431994
# logging.debug(obj.name)
19441995
logging.debug('object')
19451996

19461997
self.updateObject(obj)
19471998
self.updateProperties()
19481999
self.updateSelectionRectangle()
2000+
if event:
2001+
obj_pos = self.getObjectPosition(obj.pos, obj.offset)
2002+
self.dragInfo['offset'] = numpy.array((obj_pos[0], obj_pos[1])) - (self.level_canvas.canvasx(event.x), self.level_canvas.canvasy(event.y))
2003+
else:
2004+
self.dragInfo['offset'] = (0,0)
19492005

19502006
if self.selectedObject == None:
19512007
if len(self.object_selector['treeview'].selection()) > 0:
19522008
self.object_selector['treeview'].selection_remove(self.object_selector['treeview'].selection()[0])
19532009
else:
2010+
19542011
children = self.object_selector['treeview'].get_children('')
19552012

19562013
selected = None
@@ -1985,6 +2042,7 @@ def selectPart(
19852042
}
19862043
)
19872044
logging.debug(f'selected part: {self.selectedPart}')
2045+
return self.selectedPart
19882046

19892047
def dragPart(
19902048
self,

0 commit comments

Comments
 (0)