def add_group(self, name, group_dir=None, file_type=None, select_list=True): """ Add data file group :name: group name :group_dir: directory holding files default: self.data_dir/name :file_type: file type default: "image" """ if group_dir is None: group_dir = os.path.join(self.data_dir, name) self.group_dir = group_dir if file_type is None: file_type = self.file_type self.file_type = file_type image_hash = None image_files = None select_image_hash = None select_image_files = None if file_type == "image": """ Setup image hash for selection possibility via SelectList """ SlTrace.lg(f"image_dir:{group_dir}") image_hash = ImageHash(image_dir=group_dir) image_files = image_hash.get_image_files() if select_list: select_image_hash = ImageHash(image_dir=self.group_dir) select_image_files = select_image_hash.get_image_files() data_file_group = DataFileGroup(name, data_dir=group_dir, file_type=file_type, image_hash=image_hash, image_files=image_files, select_image_hash=select_image_hash, select_image_files=select_image_files) self.data_file_groups[name] = data_file_group
class KeyboardDraw(SelectWindow): IT_FILE = "it_file" # image from file IT_TEXT = "it_text" # image generated def __init__(self, master, title=None, kbd_master=None, canvas=None, draw_x=20, draw_y=20, draw_width=1500, draw_height=1000, kbd_win_x=0, kbd_win_y=0, kbd_win_width=350, kbd_win_height=200, side=100, width=20, hello_drawing_str=None, with_screen_kbd=True, show_help=True, **kwargs): """ Keyboard Drawing tool :master: master :kbd_master: screen keyboard master, if present must be grid managed default: create Toplevel :draw_width: drawing window width default: 1500 pixels :draw_height: drawing window height default: 1000 :kbd_win_x: screen keyboard initial x :kbd_win_y: screen keyboard initial y :kbd_win_width: screen keyboard width :kbd_win_height: screen keyboard height :canvas: base canvas default: create 500x500 :side: starting line side length default: 100 :width: starting line width default: 20 :hello_drawing_str: Beginning display command string default: HI... :with_screen_kbd: Has screen keyboard control default: True :show_help: Show help text at beginning default: True """ control_prefix = "KbdDraw" self.x_cor = 0 self.y_cor = 0 self.heading = 0 self.color_current = "red" self.color_changing = True self.color_index = 0 super().__init__(master, title=title, control_prefix=control_prefix, **kwargs) self.cmd_pointer = None # marker pointer if canvas is None: canvas = tk.Canvas(master=master, width=draw_width, height=draw_height, bd=2, bg="white", relief="ridge") canvas.pack(expand=True, fill=tk.BOTH) self.draw_width = draw_width self.draw_height = draw_height self.canv = canvas self.canvas_width = draw_width # Fudge self.canvas_height = draw_height # Fudge self.canv.bind("<ButtonPress>", self.mouse_down) self.cmd_proc = KbdCmdProc(self) """ Setup our own, outside turtle, key processing """ self.bound_keys = {} # functions, bound to keys self.master = master self.side = side self.current_width = width self.do_trace = False # Set True to do debugging trace self.do_trace = True self.set_key_mapping() canvas_width = self.canv.winfo_width() canvas_height = self.canv.winfo_height() x_start = int(-canvas_width / 2 + side) y_start = int(canvas_height / 2 - side) side = self.side width = self.current_width ostuff_x = x_start + side ostuff_y = y_start - 6 * side hi_stuff_x = ostuff_x + 5 * side hi_stuff_y = ostuff_y + 1 * side hi_side = side / 5 if hello_drawing_str == "BUILTIN": hello_drawing_str = f""" # Beginning screen pattern # Add in Family minus line({side},{width}) # Set side, width moveto({x_start},{y_start}) plus setnewline();F;a;m;i;l;y;END newline();a;l;e;x;END;image_file(family,alex);q newline();d;e;c;l;a;n;END;image_file(family,declan);q newline();a;v;e;r;y;END;image_file(family,avery);q newline();c;h;a;r;l;i;e;END;image_file(family,charlie);q ### # Add in animals ### k ### plus ### k;Right;a;a ### k;Right;a:a ### k;Right;a;a ### k;Right;a;a ### k;Right;a;a # A bit of other stuff check shorten();shorten();shorten() newline();END;image_file(princesses,princess);q image_file(other_stuff,batman) image_file(other_stuff,baseball) """ hello_drawing_str += f""" minus # HI in middle of screen shape(line) marker(line) shape(line) line({hi_side},{width}) # Set side, width moveto({hi_stuff_x},{hi_stuff_y}) w plus check Down;Down;Down;Down;Down;Down;Down;Down Up;Up;Up;Up; Right;Right; Up;Up;Up;Up Down;Down;Down;Down;Down;Down;Down;Down minus;Right;Right plus Up;Up;Up;Up;Up;Up;Up;Up minus line({side},{width}) # Set side, width Down;Down;Right;plus """ """ # Line under minus line({side},{4}) moveto({int(self.canvas_width/2-side)},{int(-self.canvas_height/2+side)}) plus Left t;=#ff0000;shape(rotate) t;=#0ff000;shape() t;=#00ff00;shape() t;=#000ff0;shape() t;=#0000ff;shape() t;=#f0f0f0;shape() t;=#af0f0f;shape(line) t;=#0ff000;shape() t;=#00ff00;shape() t;=#000ff0;shape() t;=#0000ff;shape() line({side},{width}) # Set side,width to starting w check """ self.hello_drawing_str = hello_drawing_str SlTrace.lg(f"hello_drawing_str evaluated:" f"\n{hello_drawing_str}") # Rotating pattern of custom colors self.custom_colors = [] self.setup_image_access() self.moves_canvas_tags = [] # Init for canvas part of draw_undo self.clear_all() # Setup initial settings self.enlarge_fraction = .2 # Enlargement fraction if with_screen_kbd: if kbd_master is None: kbd_master = tk.Toplevel() self.kbd_master = kbd_master self.screen_keyboard = ScreenKbdFlex(kbd_master, on_kbd=self.do_key, win_x=kbd_win_x, win_y=kbd_win_y, win_width=kbd_win_width, win_height=kbd_win_height, title="Let's Make a Drawing!") self.screen_keyboard.to_top() # Just earlier to see problems self.do_keys(self.hello_drawing_str) self.screen_keyboard.to_top() if show_help: self.help() def clear_all(self): """ Clear screen """ self.cmd_proc.clear_all() self.is_pendown_orig = True self.is_pendown = self.is_pendown_orig # Drawing pen state self.heading_orig = 0 self.heading = self.heading_orig # Current heading self.side_orig = 100 self.side = self.side_orig # Default distance self.current_width_orig = 2 self.current_width = self.current_width_orig # Current line width self.photo_images = {} # Keeping references """ Reset image group access to first file """ for name in self.image_group_names: ifg = self.get_image_file_group(name) ifg.set_file_index(-1) self.x_cor = 0 self.y_cor = 0 def last_command(self): if hasattr(self, "cmd_proc"): return self.cmd_proc.last_command() return None def enable_image_update(self, enable=True): """ Enable/Disable kbd image update :enable: enable update default: True """ self.screen_keyboard.enable_image_update(enable) def help(self): """ Help message """ if hasattr(self, "cmd_proc"): self.cmd_proc.help() else: SlTrace.lg("help is on the way") def trace(self, tstring): """ trace info (debugging) when we can't use select_trace Place info on next line as a comment line :tstring: trace string """ if self.do_trace: SlTrace.lg(f"\n#{tstring}", "tracing") def setup_image_access(self, image_dir=None): """ Setup image access for markers :image_dir: image file directory """ if image_dir is None: image_dir = "./images" # Distribution choice SlTrace.lg(f"Trying distibution image dir: {image_dir}") if not os.path.exists(image_dir): image_dir = "../../resource_lib/images" SlTrace.lg(f"Using development image dir: {image_dir}") self.image_type = KeyboardDraw.IT_FILE self.image_group_names = [ "animals", "family", "princesses", "other_stuff" ] self.image_group_index = len(self.image_group_names) if self.image_group_index >= len(self.image_group_names): self.image_group_index = 0 group_name = self.image_group_names[self.image_group_index] self.ifh = DataFiles(data_dir=image_dir) for name in self.image_group_names: group_dir = os.path.join(image_dir, name) self.ifh.add_group(name, group_dir=group_dir) SlTrace.lg("Image Files") data_files_dir = "../../resource_lib/images/animals" image_files_dir = os.path.abspath(data_files_dir) if not os.path.exists(image_files_dir): SlTrace.lg(f'__file__:{__file__}') src_dir = os.path.dirname(os.path.abspath(__file__)) SlTrace.lg(f"Assuming images are in src_dir") SlTrace.lg(f'src_dir:{src_dir}') prj_dir = os.path.dirname(src_dir) SlTrace.lg(f'prj_dir:{prj_dir}') image_dir = prj_dir self.image_dir = os.path.abspath(image_dir) SlTrace.lg(f"image_dir:{image_dir}") self.select_image_hash = ImageHash(image_dir=self.image_dir) self.select_image_files = self.select_image_hash.get_image_files() """ Marker images stored at twice size to facilitate rotation without loss of picture NOTE: needs work to support side size changes """ self.marker_image_hash = ImageHash(image_dir=self.image_dir) self.marker_image_files = self.select_image_hash.get_image_files() self.image_index = len(self.marker_image_files) # will wrap to 0 self.photo_images = {} # Keeping references self.marker_image_tags = [] self.image_chosen = None def ignore_key(self): """ ignore key """ self.trace("ignore key") def add_canvas_tag(self, tag): """ Add tag to this move :tag: tag to add """ move = self.get_move() if move is None: SlTrace.lg(f"add_canvas_tag: No move for tag") return move.canvas_tags.append(tag) def xset_color(self, colr=None, changing=None): """ set color, with no move :colr: new color default: use current color(w,2, or color string based on: self.color_current: w : rotate through colors[], using self.color_index 2 : rotate though self.custom_colors[], using self.color_index other : use self.color_current self.color_index: index within w : colors[] 2 : self.custom_colors :colr: color w : set current color to w standard 2 : set current color to 2 custom other : set self.color_current to colr :changing: True - color change False - color remains constant default: use self.color_changing """ if changing is None: changing = self.color_changing if colr is None: if self.color_current is None: return else: colr = self.color_current self.trace(f"xset_color:{colr}") if colr == "w": self.color_current = "w" self.color_changing = True elif colr == "2" or colr == "=": self.color_current = "2" self.color_changing = True else: self.color_current = colr self.color_changing = changing new_color = self.next_color() if not self.use_command: self.tu.color(new_color) def next_color(self, colr=None, changing=None): """ Get next color based on color_current, color_changing :colr: color default: use self.color_current :changing: is color changing default: use self.color_changing """ if colr is None: colr = self.color_current self.color_current = colr if changing is None: changing = self.color_changing self.color_changing = changing if self.color_current == 'w': if self.color_changing: self.color_index += 1 if self.color_index >= len(self.colors): self.color_index = 0 # wrap around new_color = self.colors[self.color_index] elif self.color_current == '2': if changing: self.color_index += 1 if self.color_index >= len(self.custom_colors): self.color_index = 0 new_color = self.custom_colors[self.color_index] else: new_color = self.color_current if type(new_color) != str: SlTrace.report(f"new_color:{new_color} not str") return SlTrace.lg( f"new_color:{new_color}" f" color_current:{self.color_current}" f" color_index:{self.color_index}" f" color_changing:{self.color_changing}", "color") return new_color def set_visible_color(self, colr): """ Set visible color based on colr :colr: color to be - set invisible (white) + set visible current color """ if colr == "-": self.move_minus() elif colr == "+": self.move_plus() else: self.xset_color(colr) def marker_set(self, marker=None, changing=None, choose=None): """ Event marker setting :marker: marker to set :changing: auto changing markers :choose: True: prompt user for marker """ if choose: """ Prompt user for marker """ x0 = 300 y0 = 400 width = 200 height = 400 SlTrace.lg(f"x0={x0}, y0={y0}, width={width}, height={height}", "choose") select_image_files = self.get_image_files() select_image_hash = self.get_select_image_hash() app = SelectList(items=select_image_files, image_hash=select_image_hash, default_to_files=True, title="Marker Images", position=(x0, y0), size=(width, height)) selected_field = app.get_selected(return_text=True) SlTrace.lg(f"image_image: selected_field:{selected_field}", "choose") if selected_field is None: return self.image_chosen = self.image_file_to_info(selected_field) if self.image_chosen is None: SlTrace.report(f"Sorry, can't load image {selected_field}") return self.marker_chosen = selected_field SlTrace.lg(f"self.image_chosen={self.image_chosen}") self.set_marker(marker="image", changing=False) self.do_marker() else: self.set_marker(marker=marker, changing=changing) def pick_next_image(self): """ Get next from current image group :returns: imageinfo (key, image) """ display_file = self.get_image_file() return self.image_file_to_info(display_file) def image_file_to_image(self, file): """ Get base image from file """ image = self.marker_image_hash.get_image(key=file, photoimage=False) return image def image_file_to_info(self, display_file): """ Convert file name(key) to image_info(key, image) :display_file: display file name/key :returns: image_info (key, image) None if can't get it """ image = self.image_file_to_image(display_file) if image is None: SlTrace.report(f"Can't load image:{display_file}") return None return (display_file, image) def line_setting(self): self.line_set(choose=True) def moveto_setting(self): self.moveto_set(choose=True) def set_pen_state(self, pendwn=None): """ Set pen to or back to drawing state self.is_pendown :pendown: target pen state default: current drawing state """ if self.use_command: self.set_pen_state(pendwn=pendwn) return pen_target = self.is_pendown if pendwn is not None: pen_target = pendwn if pen_target: if not self.tu.isdown(): self.tu.pendown() else: if self.tu.isdown(): self.tu.penup() self.is_pendown = pen_target def jump_to(self, heading=None, distance=0, pendwn=False): """ Move pen from current (immediate) location :heading: move direction default: current heading :distance: distance in direction of heading :pendwn: True lower pen, False Raise pen Leave pen in original state after default: raise pen """ if self.use_command: self.cmd_jump_to(heading=heading, distance=distance, pendwn=pendwn) return if pendwn: if not self.tu.isdown(): self.tu.pendown() else: if self.tu.isdown(): self.tu.penup() if heading is None: heading = self.heading self.xset_heading(heading, change=False) self.tu.forward(distance) self.xset_heading(self.heading) # Restore heading self.set_pen_state() # Restore pen state def jump_to_next(self): """ Move to next position, invisibly """ if self.use_command: self.cmd_jump_to_next() return if self.tu.isdown(): self.tu.penup() self.xset_heading(self.heading) theta = math.radians(self.heading) x_chg = self.side * math.cos(theta) y_chg = self.side * math.sin(theta) new_x = self.x_cor + x_chg new_y = self.y_cor + y_chg self.move_to(new_x, new_y) self.set_pen_state() def jump_to_next_line(self): """ Move to beginning of next line, invisibly """ if not self.use_command: if self.tu.isdown(): self.tu.penup() self.xset_heading(self.heading) down_heading = self.heading - 90 # Down to next line theta = math.radians(down_heading) x_chg = self.side * math.cos(theta) y_chg = self.side * math.sin(theta) new_x = self.text_line_begin_x + x_chg new_y = self.text_line_begin_y + y_chg self.move_to(new_x, new_y, pen_down=False) # Beginning of next line self.set_new_line() self.set_pen_state() def pick_next_shape(self): """ Get next from shape list :returns: return next shape """ if self.nth_shape > 0: self.shape_index += 1 self.nth_shape += 1 nshape = len(self.shape_order) if self.shape_index >= nshape: self.shape_index = 0 display_shape = self.shape_order[self.shape_index] return display_shape def set_shape(self, shape=None, choose=None, changing=None): """ Set shape - not much - initially to be in line with set_marker """ self.shape_next(shape=shape, choose=choose) """ Select special marker images """ def marker_animals(self): """ Setup to rotate through animal images """ self.set_image_type(KeyboardDraw.IT_FILE) self.set_image_group("animals") self.image_next('rotateinplace') def marker_text(self): """ Setup to add text character images """ self.set_image_type(KeyboardDraw.IT_FILE) self.image_next('rotateinplace') def do_shift(self, shift_on=True): """ Shift letters :shift_on: Put shift on, adjust letters default: True """ self.screen_keyboard.do_shift(shift_on=shift_on) def letter_next(self): """ Set letter "shape" """ if self.marker_current == "letter": return self.marker_before_letter = self.marker_current self.set_marker("letter") self.set_new_line() if self.marker_before_letter != "letter": self.jump_to(distance=self.side / 2) self.do_shift() # Default to uppercase self.do_pendown() # Default to visible self.set_key_images(show=False) exit_infos = self.get_btn_infos(key="END") self.set_btn_image(exit_infos, image="drawing_abc_end.png") self.track_keys_text() self.master.focus() # So keyboard is active def on_text_end(self): ###self.text_entry_funcid = self.master.unbind('<KeyPress>', self.text_entry_funcid) self.track_keys() # Reset keys to drawing cmds self.do_shift(False) exit_infos = self.get_btn_infos(key="BKSP") self.set_btn_image(exit_infos, image=None) self.set_key_images(show=True) self.set_marker(self.marker_before_letter) def get_move(self): """ Get most recent move (MoveInfo) :returns: move, None if none """ if len(self.move_stack) > 0: return self.move_stack[-1] return None def check(self, key): print(f"\n#{key}") # Force even if self.trace is False print("check") def checking(self): """ Debugging catch """ self.check("check") def dotrace(self, key=None): """ Flip tracing setting """ self.do_trace = not self.do_trace def tracing(self): """ Debugging catch """ self.dotrace("trace") def get_image_files(self): """ get current image group's files """ ifg = self.get_image_file_group() return ifg.image_files def get_image_file(self, group=None, file=None, next=True): """ get current image group's file :group: group name default: current group :file: file name default: current or next :next: if true get next """ ifg = self.get_image_file_group(name=group) if file is not None: im_file = ifg.get_file(file=file) return im_file if next: inc = 1 else: inc = 0 im_file = ifg.get_file(inc=inc) SlTrace.lg(f"get_image_file: {im_file}", "image_display") return im_file def get_image_hash(self): """ get current image group's files """ ifg = self.get_image_file_group() return ifg.image_hash def get_select_image_hash(self): """ get current image group's SelectList hash Note that these may be images whose sizes are for the SelectList and not for marker images """ ifg = self.get_image_file_group() return ifg.select_image_hash def get_image_file_group(self, name=None): """ Get current marker image file group (DataFileGroup) :name: group name default: return current self.image_group """ if name is None: name = self.image_group_names[0] ifg = self.ifh.get_group(name) return ifg def get_image_file_groups(self): """ Get all image file groups (DataFileGroup) :returns: data groups (list of DataFileGroup) """ names = self.image_group_names groups = [] for name in names: groups.append(self.ifh.get_group(name)) return groups def get_canvas(self): """ Get our working canvas """ return self.canv def select_print(self, tag, trace=None): """ Print select select state """ """TBD""" def expand_key(self, key): """ Expand key to functional form: name(arg,arg,...) """ if re.match(r'^\w+\(.*\)', key): return key # Already in function form for short_name in self.key_fun_name: if key.startswith(short_name): fun_name = self.key_fun_name[short_name] arg_str = key[len(short_name):] name = f"{fun_name}({arg_str})" return name return key # Unchanged nk = 0 # length key spaces so far def print_key(self, key): """ Print key :key: key string """ if self.nk > 0: if self.nk > 40: print() self.nk = 0 else: print(";", end="") exp_key = self.expand_key(key) self.nk += len(exp_key) print(exp_key, end="") def do_key(self, key, **kwargs): """ Process key by calling keyfun, echoing key :key: key (descriptive string) pressed or special "key" e.g. funname(args) :kwargs: function specific parameters often to "redo" adjusted undone operations """ return self.cmd_proc.do_key(key, **kwargs) def do_keys(self, keystr): """ Do action based on keystr semicolon or newline used as separators Empty areas between separators are ignored lines starting with # are printed but removed text starting with "\s+.*" are removed :keystr: string of key(values) must match track_key interpretations e.g. Up for up-arrow, minus for "-" """ rawkeylines = keystr.split('\n') code_keylines = [] for rawkeyline in rawkeylines: if re.match(r'^\s*#', rawkeyline): code_keylines.append(rawkeyline) # Pass comment line continue eol_com_match = re.match(r'^(.*\S)(\s+#.+)$', rawkeyline) if eol_com_match: code_keylines.append(eol_com_match.group(1)) code_keylines.append( eol_com_match.group(2)) # remove trailing comment continue code_keylines.append(rawkeyline) for code_keyline in code_keylines: if re.match(r'\s*#', code_keyline): print(f"\n{code_keyline}") continue keys = re.split(r'\s*;\s*|\s+', code_keyline) for key in keys: if key != "": self.do_key(key) def set_key_mapping(self): """ Setup key to function mapping TBD """ # key, function [, *parameters], key_mapping = [ ['h', self.help], ] def on_text_entry(self, event): """ Text entry from keyboard :event" key press event """ inchar = event.char keysym = event.keysym keycode = event.keycode SlTrace.lg(f"on_text_entry: keysym: {keysym} keycode: {keycode}") if keysym == 'End': key = "END" self.text_enter_key(key) if keysym == "Return": self.text_enter_key("ENTER") elif keysym == 'BackSpace': self.draw_undo() elif keysym == 'Shift_L' or keysym == 'Shift_R': pass # Just adjust physical keyboard elif keysym == 'Caps_Lock': pass # Just adjust physical keyboard elif keysym == 'Up' or keysym == 'Down' or keysym == 'Left' or keysym == 'Right': self.move(direct=keysym, just_move=True) else: key = event.char self.text_enter_key(key) def on_text_entry_screen(self, key): """ Text entry from screen keyboard :key" key click """ SlTrace.lg(f"on_text_entry_screen: key: {key}") if key == "END": self.on_text_end() return if key == "BKSP": self.draw_undo() return self.text_enter_key(key=key) def track_keys_text(self): """ Setup keys for text input """ """ bind screen keyboard keys """ def set_key_images(self, show=False): self.screen_keyboard.set_images(show=show) def get_btn_infos(self, key=None, row=None, col=None): """ Get buttons :key: if not None, must match :row: if not None, must match :col: if not None, must match """ return self.screen_keyboard.get_btn_infos(key=key, row=row, col=col) def set_btn_image(self, btn_infos=None, image=None): """ Set button (btn_infos) image displayed :btn_infos: ButtonInfo, or list of ButtonInfos :image" text - image file Image - image """ self.screen_keyboard.set_btn_image(btn_infos=btn_infos, image=image) def draw_undo(self): """ Undo most recent operation As the only handle we have on turtle objects is undobufferentries(), we save a stack of this count at the beginning of each opperation. Undo consists of calling undo while undobufferentries() returns a number greater than the stack entry count """ self.trace_move_stack("draw_undo", flag="draw_undo") """ Undo move (limits undo) Might consider combining with canvas undo """ """ Undo canvas (e.g. image) actions if any Have to do check before move because we keep the stacks diferently because move_stack[0] remains """ move = self.get_move() if move is None: SlTrace.lg("draw_undo: Empty Stack - can't undo") return if len(move.canvas_tags) > 0: canvas_tags = move.canvas_tags for canvas_tag in canvas_tags: self.canv.delete(canvas_tag) if len(self.move_stack) > 0: # current is on top of stack self.move_undo = self.move_stack.pop() else: self.trace_move_stack("draw_undo AFTER - no more undos", flag="draw_undo") return """ Undo turtle actions, if any. """ if len(self.draw_undo_counts) > 0: while (tu_undo_count := self.tu.undobufferentries()) > move.undo_count_base: SlTrace.lg(f"tu_undo_count: {tu_undo_count}") self.tu.undo() SlTrace.lg(f"undo_count: {tu_undo_count}") self.master.update_idletasks() self.trace_move_stack("draw_undo AFTER")
if __name__ == '__main__': def report_change(item, val, cklist=None): SlTrace.lg("changed: %s = %d" % (item, val)) new_val = SlTrace.getLevel(item) SlTrace.lg("New val: %s = %d" % (item, new_val)) if cklist is not None: cklist.list_ckbuttons() root = Tk() SlTrace.set_mw(root) ###frame = Frame(root) ###frame.pack() SlTrace.setProps() image_hash = ImageHash(image_dir="../../crs_dots/images") image_files = image_hash.get_image_files() text_items = ["ONE", "TWO", "3", "FOUR"] x0 = 300 y0 = 400 width = 200 height = 400 SlTrace.lg(f"x0={x0}, y0={y0}, width={width}, height={height}", "select_list") SlTrace.lg("Text Buttons") app = SelectList(items=text_items, position=(x0, y0), size=(width, height), title="Text Buttons") selected_field = app.get_selected() SlTrace.lg(f"text_items: selected_field:{selected_field}")
class DmDrawerImage(DmDrawer): IT_FILE = "it_file" # image from file IT_TEXT = "it_text" # image generated def __init__(self, master, **kwargs): """ DmDrawer, extended to support images """ super().__init__(master, **kwargs) self.setup_image_access() def get_image_file(self, group=None, file=None, next=True): """ get current image group's file :group: group name default: current group :file: file name default: current or next :next: if true get next """ ifg = self.get_image_file_group(name=group) if file is not None: im_file = ifg.get_file(file=file) return im_file if next: inc = 1 else: inc = 0 im_file = ifg.get_file(inc=inc) SlTrace.lg(f"get_image_file: {im_file}", "image_display") return im_file def get_image_file_group(self, name=None): """ Get current marker image file group (DataFileGroup) :name: group name default: return current self.image_group """ if name is None: name = "animals" ifg = self.ifh.get_group(name) return ifg def get_next_image(self): """ Get next from current image group :returns: imageinfo (key, image) """ display_file = self.get_image_file() return self.image_file_to_image(display_file) def setup_image_access(self, image_dir=None): """ Setup image access for markers :image_dir: image file directory """ if image_dir is None: image_dir = "./images" # Distribution choice SlTrace.lg(f"Trying distibution image dir: {image_dir}") if not os.path.exists(image_dir): image_dir = "../../resource_lib/images" SlTrace.lg(f"Using development image dir: {image_dir}") self.image_type = "it_file" self.image_group_names = [ "animals", "family", "princesses", "other_stuff" ] self.image_group_index = len(self.image_group_names) if self.image_group_index >= len(self.image_group_names): self.image_group_index = 0 group_name = self.image_group_names[self.image_group_index] self.ifh = DataFiles(data_dir=image_dir) for name in self.image_group_names: group_dir = os.path.join(image_dir, name) self.ifh.add_group(name, group_dir=group_dir) SlTrace.lg("Image Files") data_files_dir = "../../resource_lib/images/animals" image_files_dir = os.path.abspath(data_files_dir) if not os.path.exists(image_files_dir): SlTrace.lg(f'__file__:{__file__}') src_dir = os.path.dirname(os.path.abspath(__file__)) SlTrace.lg(f"Assuming images are in src_dir") SlTrace.lg(f'src_dir:{src_dir}') prj_dir = os.path.dirname(src_dir) SlTrace.lg(f'prj_dir:{prj_dir}') image_dir = prj_dir self.image_dir = os.path.abspath(image_dir) SlTrace.lg(f"image_dir:{image_dir}") self.select_image_hash = ImageHash(image_dir=self.image_dir) self.select_image_files = self.select_image_hash.get_image_files() """ Marker images stored at twice size to facilitate rotation without loss of picture NOTE: needs work to support side size changes """ self.marker_image_hash = ImageHash(image_dir=self.image_dir) self.marker_image_files = self.select_image_hash.get_image_files() self.image_index = len(self.marker_image_files) # will wrap to 0 self.photo_images = {} # Keeping references self.marker_image_tags = [] self.image_chosen = None def image_file_to_image(self, file): """ Get base image from file """ image = self.marker_image_hash.get_image(key=file, photoimage=False) return image