diff --git a/apps/icon/layer.png b/apps/icon/layer.png deleted file mode 100644 index 2ccd413..0000000 --- a/apps/icon/layer.png +++ /dev/null Binary files differ diff --git a/apps/icon/locked_button.png b/apps/icon/locked_button.png new file mode 100644 index 0000000..c23e36d --- /dev/null +++ b/apps/icon/locked_button.png Binary files differ diff --git a/apps/icon/maps.png b/apps/icon/maps.png new file mode 100644 index 0000000..aeb9c3e --- /dev/null +++ b/apps/icon/maps.png Binary files differ diff --git a/apps/icon/unlocked_button.png b/apps/icon/unlocked_button.png new file mode 100644 index 0000000..dd62ba5 --- /dev/null +++ b/apps/icon/unlocked_button.png Binary files differ diff --git a/apps/mylib/application.py b/apps/mylib/application.py index 2659310..9eab68f 100644 --- a/apps/mylib/application.py +++ b/apps/mylib/application.py @@ -54,12 +54,13 @@ ++++++++++ File menu functions ++++++++++ """ def menu_open_base(self, event=None): - map_path = self.menu_open(title="Select base map yaml file") + map_path = self.open_yaml(title="Select base map yaml file") if not map_path: return - waypoints_path = self.menu_open(title="Select waypoints file for the map") + waypoints_path = self.open_yaml(title="Select waypoints file for the map") if not waypoints_path: return - self.tools.set_base_map(Path(map_path).resolve(), Path(waypoints_path).resolve()) + suc = self.tools.set_base_map(Path(map_path).resolve(), Path(waypoints_path).resolve()) + if not suc: return self.open_menu.entryconfigure("Base map", state="disabled") self.open_menu.entryconfigure("Multimaps dir", state="disabled") self.open_menu.entryconfigure("Additional map", state="normal") @@ -67,9 +68,9 @@ def menu_open_addtion(self, event=None): - map_path = self.menu_open(title="Select additional map yaml file") + map_path = self.open_yaml(title="Select additional map yaml file") if not map_path: return - waypoints_path = self.menu_open(title="Select waypoints file for the map") + waypoints_path = self.open_yaml(title="Select waypoints file for the map") if not waypoints_path: return self.tools.add_map(Path(map_path).resolve(), Path(waypoints_path).resolve()) return @@ -84,16 +85,17 @@ if not dirpath: return dirpath = Path(dirpath) if not (dirpath / Path("map0.yaml")).exists(): return - waypoints_path = self.menu_open(title="Select waypoints file for the map") + waypoints_path = self.open_yaml(title="Select waypoints file for the map") if not waypoints_path: return - self.tools.set_multimaps(dirpath, Path(waypoints_path).resolve()) + suc = self.tools.set_multimaps(dirpath, Path(waypoints_path).resolve()) + if not suc: return self.open_menu.entryconfigure("Base map", state="disabled") self.open_menu.entryconfigure("Multimaps dir", state="disabled") self.open_menu.entryconfigure("Additional map", state="normal") return - def menu_open(self, title): + def open_yaml(self, title): filepath = tkinter.filedialog.askopenfilename( parent=self.master, title=title, @@ -107,7 +109,7 @@ if (len(self.tools.label_list) < 2): return ## サブウィンドウを作成 win = tk.Toplevel() - win.geometry("500x200+50+50") + win.geometry("700x200+50+50") win.minsize(width=500, height=200) win.attributes('-topmost', True) win.title("Export") diff --git a/apps/mylib/mapdisp.py b/apps/mylib/mapdisp.py index 37e1cce..d04627a 100644 --- a/apps/mylib/mapdisp.py +++ b/apps/mylib/mapdisp.py @@ -154,7 +154,6 @@ self.rotate_center = None self.old_map_rot = None self.selected_map_key = None - self.selected_map_center = None self.mode = 0 self.base_map_key = "" self.point_rad = 5 @@ -228,7 +227,7 @@ def plot_waypoints(self): for key, wp_list in self.waypoints_dict.items(): if key[-2:] == "fp": - finish_pose = self.waypoints_dict[key] + finish_pose: FinishPose = self.waypoints_dict[key] img_x, img_y = self.map_dict[key[:-2]].real2image(finish_pose.x, finish_pose.y) cx, cy = self.map_dict[key[:-2]].transform(img_x, img_y) th = finish_pose.yaw - self.map_dict[key[:-2]].get_rotate_angle() @@ -246,7 +245,7 @@ if len(wp_list.get_id_list()) == 0: # 初めて描画する for n, wp in enumerate(wp_list.get_waypoint()): - id = self.create_waypoint(wp, self.map_dict[key]) + id = self.create_waypoint(key, wp, self.map_dict[key]) self.waypoints_dict[key].set_id(n+1, id) else: for id in wp_list.get_id_list(): @@ -259,7 +258,7 @@ return - def create_waypoint(self, waypoint: dict, mymap: MyMap): + def create_waypoint(self, key, waypoint: dict, mymap: MyMap): img_x, img_y = mymap.real2image(float(waypoint["x"]), float(waypoint["y"])) cx, cy = mymap.transform(img_x, img_y) r = self.point_rad-1 @@ -267,7 +266,7 @@ y0 = round(cy - r) x1 = round(cx + r + 1) y1 = round(cy + r + 1) - id = self.canvas.create_oval(x0, y0, x1, y1, fill='#F88', outline='#F88') + id = self.canvas.create_oval(x0, y0, x1, y1, fill='#F88', outline='#F88', tags=key+"wp") return id @@ -287,8 +286,10 @@ self.canvas.create_polygon(polygon, tags="selection_frame", fill="", outline="#FF0", dash=(5,3), width=5) self.canvas.lift(self.selected_map_key) self.canvas.lift("selection_frame") - self.canvas.lift("origin", self.selected_map_key) - self.plot_waypoints() + self.canvas.lift(self.selected_map_key+"wp") + self.canvas.lift(self.selected_map_key+"fp") + self.canvas.lift("origin") + # self.plot_waypoints() return @@ -296,8 +297,12 @@ key = self.path2key(path) if vision: self.canvas.itemconfigure(key, state=tk.NORMAL) + self.canvas.itemconfigure(key+"wp", state=tk.NORMAL) + self.canvas.itemconfigure(key+"fp", state=tk.NORMAL) else: self.canvas.itemconfigure(key, state=tk.HIDDEN) + self.canvas.itemconfigure(key+"wp", state=tk.HIDDEN) + self.canvas.itemconfigure(key+"fp", state=tk.HIDDEN) diff --git a/apps/mylib/tools.py b/apps/mylib/tools.py index 15109d5..90736c3 100644 --- a/apps/mylib/tools.py +++ b/apps/mylib/tools.py @@ -2,6 +2,7 @@ import numpy as np import ruamel.yaml import math +from tkinter import messagebox from PIL import Image, ImageTk from pathlib import Path from .mapdisp import MapDisplay, MyMap @@ -23,6 +24,7 @@ self.map_path = Path() self.map_transparency = tk.IntVar() self.map_transparency.set(100) + self.state = "unlocked" def set_map_path(self, path: Path): @@ -58,17 +60,29 @@ self.rot_btn.bind("", lambda event, btn=self.rot_btn: self.btn_leave(event, btn)) self.rot_btn.bind("", lambda event, btn=self.rot_btn, mode="rotate": self.btn_clicked(event, btn, mode)) self.rot_btn.grid(column=1, row=0) + ## lock, unlock ボタン + icon = Image.open(Path(__file__).parent.parent / Path("icon","locked_button.png")) + icon = icon.resize((30,30)) + self.locked_icon = ImageTk.PhotoImage(image=icon) + icon = Image.open(Path(__file__).parent.parent / Path("icon","unlocked_button.png")) + icon = icon.resize((30,30)) + self.unlocked_icon = ImageTk.PhotoImage(image=icon) + self.lock_btn = tk.Label(self.btn_frame, image=self.unlocked_icon, bg=theme["main"]) + self.lock_btn.bind("", lambda event, btn=self.lock_btn: self.btn_entry(event, btn)) + self.lock_btn.bind("", lambda event, btn=self.lock_btn: self.btn_leave(event, btn)) + self.lock_btn.bind("", self.lock_btn_clicked) + self.lock_btn.grid(column=0, row=1) ## 余白 space = tk.Frame(self, height=100, bg=theme["main"]) space.pack(expand=False, fill=tk.X) - #### レイヤーリストを表示 #### + #### マップリストを表示 #### ## アイコン - icon = Image.open(Path(__file__).parent.parent / Path("icon","layer.png")) - icon = icon.resize((20, 17)) + icon = Image.open(Path(__file__).parent.parent / Path("icon","maps.png")) + icon = icon.resize((20, 20)) self.layer_icon = ImageTk.PhotoImage(image=icon) layer_label = tk.Label(self, bg=theme["bg1"], - text=" Layers", fg="white", font=("Arial",11,"bold"), + text=" Maps", fg="white", font=("Arial",11,"bold"), image=self.layer_icon, compound=tk.LEFT ) layer_label.pack(expand=False, anchor=tk.W, ipadx=3, ipady=2, padx=5) @@ -118,6 +132,7 @@ def btn_clicked(self, event, btn: tk.Label, mode): if (len(self.label_list) == 0) or (self.selected_layer == self.base_map_layer): return + if self.selected_layer.state == "locked": return if btn.cget("bg") == "black": self.map_disp.mode = self.map_disp.Normal btn.configure(bg="#333") @@ -130,39 +145,75 @@ elif mode == "rotate": self.map_disp.mode = self.map_disp.RotateSelected btn.configure(bg="black") return + + + def lock_btn_clicked(self, event): + if (len(self.label_list) == 0) or (self.selected_layer == self.base_map_layer): return + if self.lock_btn.cget("bg") == "black": + self.lock_btn.configure(image=self.unlocked_icon, bg=self.theme["main"]) + self.selected_layer.state = "unlocked" + else: + self.lock_btn.configure(image=self.locked_icon, bg="black") + self.selected_layer.state = "locked" + return def set_base_map(self, map_path: Path, wp_path: Path): map_yaml = read_file(map_path) - if not ("image" in map_yaml): return + if not ("image" in map_yaml): + messagebox.showerror(title="Format error", message="Selected map file is unexpected format.") + return False wp_yaml = read_file(wp_path) - if not ("waypoints" in wp_yaml): return - self.map_disp.add_map(map_path, map_yaml, wp_yaml, base=True) + if (not "waypoints" in wp_yaml) or (not "finish_pose" in wp_yaml): + messagebox.showerror(title="Format error", message="Selected waypoints file is unexpected format.") + return False + try: + self.map_disp.add_map(map_path, map_yaml, wp_yaml, base=True) + except (FileNotFoundError, FileExistsError): + messagebox.showerror(title="Image file is not found", message="\""+map_yaml["image"]+"\" is not found.") + return False self.append_layer(map_path, base=True) + self.base_map_layer.state = "locked" + self.lock_btn.configure(image=self.locked_icon, bg="black") self.base_waypoints_path = wp_path - return + return True def add_map(self, path: Path, wp_path: Path): map_yaml = read_file(path) - if not ("image" in map_yaml): return + if not ("image" in map_yaml): + messagebox.showerror(title="Format error", message="Selected map file is unexpected format.") + return False wp_yaml = read_file(wp_path) - if not ("waypoints" in wp_yaml): return - if self.map_disp.add_map(path, map_yaml, wp_yaml): - self.append_layer(path) - else: - i = 2 - path2 = path.with_name(path.with_suffix("").name + "-" + str(i)) - while(not self.map_disp.add_map(path2, map_yaml, wp_yaml)): - i += 1 + if (not "waypoints" in wp_yaml) or (not "finish_pose" in wp_yaml): + messagebox.showerror(title="Format error", message="Selected waypoints file is unexpected format.") + return False + try: + if self.map_disp.add_map(path, map_yaml, wp_yaml): + self.append_layer(path) + else: + i = 2 path2 = path.with_name(path.with_suffix("").name + "-" + str(i)) - self.append_layer(path2) - return + while(not self.map_disp.add_map(path2, map_yaml, wp_yaml)): + i += 1 + path2 = path.with_name(path.with_suffix("").name + "-" + str(i)) + self.append_layer(path2) + path = path2 + except (FileNotFoundError, FileExistsError): + messagebox.showerror(title="Image file is not found", message="\""+map_yaml["image"]+"\" is not found.") + return False + self.selected_layer.map_transparency.set(70) + self.map_disp.set_transparency(path, 70) + self.tra_bar.configure(variable=self.selected_layer.map_transparency) + return True def set_multimaps(self, dirpath: Path, wp_path: Path): all_wp_yaml = read_file(wp_path) + if (not "waypoints" in wp_yaml) or (not "finish_pose" in wp_yaml): + messagebox.showerror(title="Format error", message="Selected waypoints file is unexpected format.") + return False map_idx = 0 wp_idx = 0 while(True): @@ -188,14 +239,22 @@ } } break - base = (map_idx==0) - self.map_disp.add_map(map_path, map_yaml, wp_yaml, base=base) - self.append_layer(map_path, base=base) - if base: self.base_waypoints_path = wp_path + if map_idx==0: + self.map_disp.add_map(map_path, map_yaml, wp_yaml, base=True) + self.append_layer(map_path, base=True) + self.base_map_layer.state = "locked" + self.lock_btn.configure(image=self.locked_icon, bg="black") + self.base_waypoints_path = wp_path + else: + self.map_disp.add_map(map_path, map_yaml, wp_yaml) + self.append_layer(map_path) + self.selected_layer.map_transparency.set(70) + self.map_disp.set_transparency(map_path, 70) + self.tra_bar.configure(variable=self.selected_layer.map_transparency) map_idx += 1 wp_idx += 1 - return + return True def append_layer(self, path: Path, base=None): @@ -219,6 +278,7 @@ self.selected_layer.configure(bg=self.theme["bg1"]) self.selected_layer = label self.tra_bar.configure(variable=self.selected_layer.map_transparency, state=tk.NORMAL) + self.lock_btn.configure(image=self.unlocked_icon, bg=self.theme["main"]) self.label_list.append(label) if base: self.base_map_layer = label return @@ -236,7 +296,6 @@ else: label.configure(image=self.visible_icon, fg="white") self.map_disp.set_vision_state(label.map_path, vision=True) - return if label != self.selected_layer: self.selected_layer.configure(bg=self.theme["bg1"]) @@ -244,6 +303,15 @@ self.selected_layer = label self.tra_bar.configure(variable=self.selected_layer.map_transparency) self.map_disp.select_map(self.selected_layer.map_path) + for btn in [self.move_btn, self.rot_btn]: + if btn.cget("bg") == "black": + self.map_disp.mode = self.map_disp.Normal + btn.configure(bg=self.theme["main"]) + break + if self.selected_layer.state == "locked": + self.lock_btn.configure(image=self.locked_icon, bg="black") + else: + self.lock_btn.configure(image=self.unlocked_icon, bg=self.theme["main"]) return