def __init__(self, master, style_def): super().__init__(master, style_def) self.set_def(style_def) self.config(width=150, height=110) self.n = ToggleButton(self, text="N", width=20, height=20) self.n.grid(row=0, column=0, columnspan=3, sticky='ns') self.w = ToggleButton(self, text='W', width=20, height=20) self.w.grid(row=1, column=0, sticky='ew') self.pad = Frame(self, width=60, height=60, **self.style.dark, **self.style.dark_highlight_active) self.pad.grid(row=1, column=1, padx=1, pady=1) self.pad.grid_propagate(0) self.pad.grid_columnconfigure(0, minsize=60) self.pad.grid_rowconfigure(0, minsize=60) self.floating = Frame(self.pad, **self.style.dark_on_hover, width=20, height=20) self.floating.grid(row=0, column=0, pady=1, padx=1) self.e = ToggleButton(self, text="E", width=20, height=20) self.e.grid(row=1, column=2, sticky='ew') self.s = ToggleButton(self, text='S', width=20, height=20) self.s.grid(row=2, column=0, columnspan=3, sticky='ns') self.anchors = {"n": self.n, "w": self.w, "e": self.e, "s": self.s} self._order = ("n", "s", "e", "w") self._selected = [] self._exclusive_pairs = ({"n", "s"}, {"e", "w"}) self._is_multiple = re.compile(r'(.*[ns].*[ns])|(.*[ew].*[ew])') for anchor in self.anchors: self.anchors[anchor].on_change(self._change, anchor)
def render(self): self.config(height=40) seq_frame = Frame(self, **self.style.highlight) seq_frame.grid(row=0, column=0, sticky="nsew") seq_frame.pack_propagate(False) self.sequence = Entry(seq_frame, **self.style.input) self.sequence.place(x=0, y=0, relwidth=1, relheight=1, width=-40) self.sequence.set(self.value.sequence) self.sequence.configure(**self.style.no_highlight) self.sequence.focus_set() self.handler = Entry(self, **self.style.input) self.handler.grid(row=0, column=1, sticky="ew") self.handler.set(self.value.handler) self.handler.config(**self.style.highlight) self.add_arg = Checkbutton(self, **self.style.checkbutton) self.add_arg.grid(row=0, column=2, sticky="ew") self.add_arg.set(self.value.add) del_btn = Label(self, **self.style.button, image=get_icon_image("delete", 14, 14)) del_btn.grid(row=0, column=3, sticky='nswe') del_btn.bind("<Button-1>", self._delete_entry) # set the first two columns to expand evenly for column in range(2): self.grid_columnconfigure(column, weight=1, uniform=1) for widget in (self.sequence, self.handler): widget.on_change(self._on_value_change) self.add_arg._var.trace("w", lambda *_: self._on_value_change())
def __init__(self, master, studio, **cnf): super().__init__(master, studio, **cnf) self.body = ScrolledFrame(self, **self.style.dark) self.body.pack(side="top", fill="both", expand=True) self._toggle_btn = Button(self._header, image=get_icon_image("chevron_down", 15, 15), **self.style.dark_button, width=25, height=25) self._toggle_btn.pack(side="right") self._toggle_btn.on_click(self._toggle) self._search_btn = Button(self._header, image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.dark_button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self.groups = [] self._identity_group = self.add_group(IdentityGroup) self._layout_group = self.add_group(LayoutGroup) self._attribute_group = self.add_group(AttributeGroup) self._empty_frame = Frame(self.body) self.show_empty() self._current = None self._expanded = False
def render(self, _): self.detail = Label(self, **self.style.text, text=self.message) self.detail.pack(fill="x") warn_frame = Frame(self, **self.style.surface) self._warning = Label( warn_frame, **self.style.text_passive, padx=5, anchor='w', compound="left", image=get_tk_image("dialog_warning", 15, 15), ) self.event_pad = Label( self, **self.style.text_accent) self._add_button(text="Cancel", value=None) self._add_button(text="Okay", command=self.exit_with_key, focus=True) warn_frame.pack(side="bottom", fill="x") self.event_pad.config( **self.style.bright, takefocus=True, text="Tap here to begin capturing shortcuts." ) self.event_pad.bind("<Any-KeyPress>", self.on_key_change) # for some reason alt needs to be bound separately self.event_pad.bind("<Alt-KeyPress>", self.on_key_change) self.event_pad.bind("<Button-1>", lambda e: self.event_pad.focus_set()) self.event_pad.pack(fill="both", expand=True)
def setup_style_pane(self): self.body = ScrolledFrame(self, **self.style.surface) self.body.pack(side="top", fill="both", expand=True) self._toggle_btn = Button(self.get_header(), image=get_icon_image("chevron_down", 15, 15), **self.style.button, width=25, height=25) self._toggle_btn.pack(side="right") self._toggle_btn.on_click(self._toggle) self._search_btn = Button(self.get_header(), image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self.groups = [] self._empty_frame = Frame(self.body) self.show_empty() self._current = None self._expanded = False self._is_loading = False self._search_query = None
def __init__(self, master, studio=None, **cnf): super().__init__(master, studio, **cnf) self._toggle_btn = Button(self._header, image=get_icon_image("chevron_down", 15, 15), **self.style.button, width=25, height=25) self._toggle_btn.pack(side="right") self._toggle_btn.on_click(self._toggle) self._search_btn = Button( self._header, **self.style.button, image=get_icon_image("search", 15, 15), width=25, height=25, ) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self.body = Frame(self, **self.style.surface) self.body.pack(side="top", fill="both", expand=True) self._empty_label = Label(self.body, **self.style.text_passive) self._selected = None self._expanded = False self._tree = None
def __init__(self, master, studio=None, **cnf): super().__init__(master, **cnf) self.update_defaults() self.__class__._instance = self if not self.__class__._view_mode: self.__class__._view_mode = StringVar(None, self.get_pref('mode')) self.__class__._transparency_flag = t = BooleanVar(None, self.get_pref('inactive_transparency')) self.__class__._side = side = StringVar(None, self.get_pref('side')) t.trace_add("write", lambda *_: self.set_pref('inactive_transparency', t.get())) self.studio = studio self._header = Frame(self, **self.style.dark, **self.style.dark_highlight_dim, height=30) self._header.pack(side="top", fill="x") self._header.pack_propagate(0) self._header.allow_drag = True Label(self._header, **self.style.dark_text_passive, text=self.name).pack(side="left") self._min = Button(self._header, image=get_icon_image("close", 15, 15), **self.style.dark_button, width=25, height=25) self._min.pack(side="right") self._min.on_click(self.minimize) self._pref = MenuButton(self._header, **self.style.dark_button) self._pref.configure(image=get_icon_image("settings", 15, 15)) self._pref.pack(side="right") self._pref.tooltip("Options") self._search_bar = SearchBar(self._header, height=20) self._search_bar.on_query_clear(self.on_search_clear) self._search_bar.on_query_change(self.on_search_query) menu = self.make_menu(( ("cascade", "View Mode", None, None, {"menu": ( ("radiobutton", "Docked", None, self.open_as_docked, {"variable": self._view_mode, "value": "docked"}), ("radiobutton", "Window", None, self.open_as_window, {"variable": self._view_mode, "value": "window"}), )}), ("cascade", "Position", None, None, {"menu": ( ("radiobutton", "Left", None, lambda: self.reposition("left"), {"variable": self._side, "value": "left"}), ("radiobutton", "Right", None, lambda: self.reposition("right"), {"variable": self._side, "value": "right"}), )}), EnableIf(lambda: self._view_mode.get() == 'window', ("cascade", "Window options", None, None, {"menu": ( ( "checkbutton", "Transparent when inactive", None, None, {"variable": self._transparency_flag}), )})), ("command", "Close", get_icon_image("close", 14, 14), self.minimize, {}), ("separator",), *self.create_menu() ), self._pref) self._pref.config(menu=menu) # self._pref.on_click(self.minimize) self.config(**self.style.dark) self.indicator = None self.window_handle = None self.on_focus(self._on_focus_get) self.on_focus_lost(self._on_focus_release) self.on_close(self.close_window) self._mode_map = { 'window': self.open_as_window, 'docked': self.open_as_docked }
def init_toolbar(self): for action in self.actions: if len(action) == 1: Frame(self._toolbar, width=1, bg=self.style.colors.get("primarydarkaccent")).pack( side='left', fill='y', pady=3, padx=5) continue btn = Button(self._toolbar, image=action[1], **self.style.button, width=25, height=25) btn.pack(side="left", padx=3) btn.tooltip(action[3]) ActionNotifier.bind_event("<Button-1>", btn, action[2], text=action[3])
def __init__(self, master, **cnf): super().__init__(master, **cnf) self.config(**self.style.dark) self._label_frame = Frame(self, **self.style.bright, height=20) self._label_frame.pack(side="top", fill="x", padx=2) self._label_frame.pack_propagate(0) self._label = Label(self._label_frame, **self.style.bright, **self.style.text_bright) self._label.pack(side="left") self._collapse_btn = Button(self._label_frame, width=20, **self.style.bright, **self.style.text_bright) self._collapse_btn.config(text=get_icon("triangle_up")) self._collapse_btn.pack(side="right", fill="y") self._collapse_btn.on_click(self.toggle) self.body = Frame(self, **self.style.dark) self.body.pack(side="top", fill="both", pady=2) self.__ref = Frame(self.body, height=0, width=0, **self.style.dark) self.__ref.pack(side="top") self._collapsed = False
def __init__(self, master, **cnf): super(Pane, self).__init__(master, **cnf) self.config(**self.style.surface) self._header = Frame(self, **self.style.surface, **self.style.highlight_dim, height=30) self._header.pack(side="top", fill="x") self._header.pack_propagate(0) self._search_bar = SearchBar(self._header, height=20) self._search_bar.on_query_clear(self.on_search_clear) self._search_bar.on_query_change(self.on_search_query)
def __init__(self, master, pane, **cnf): super().__init__(master) self.style_pane = pane self.configure(**{**self.style.surface, **cnf}) self._empty_message = "Select an item to see styles" self._empty = Frame(self.body, **self.style.surface) self._empty_label = Label( self._empty, **self.style.text_passive, ) self._empty_label.pack(fill="both", expand=True, pady=15) self._widget = None self._prev_widget = None self._has_initialized = False # Flag to mark whether Style Items have been created self.items = {}
def __init__(self, master, studio=None, **cnf): super().__init__(master, studio, **cnf) f = Frame(self, **self.style.dark) f.pack(side="top", fill="both", expand=True, pady=4) f.pack_propagate(0) self._variable_pane = ScrolledFrame(f, width=150) self._variable_pane.place(x=0, y=0, relwidth=0.4, relheight=1) self._detail_pane = ScrolledFrame(f, width=150) self._detail_pane.place(relx=0.4, y=0, relwidth=0.6, relheight=1, x=15, width=-20) self._search_btn = Button(self._header, image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.dark_button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self._add = MenuButton(self._header, **self.style.dark_button) self._add.configure(image=get_icon_image("add", 15, 15)) self._add.pack(side="right") self._delete_btn = Button(self._header, image=get_icon_image("delete", 15, 15), width=25, height=25, **self.style.dark_button) self._delete_btn.pack(side="right") self._delete_btn.on_click(self._delete) self._var_types_menu = self.make_menu(self._get_add_menu(), self._add) self._add.config(menu=self._var_types_menu) self._selected = None self._links = {} self._overlay = Label(f, **self.style.dark_text_passive, text="Add variables", compound="top") self._overlay.configure(image=get_icon_image("add", 25, 25)) self._show_overlay(True) self._editors = []
def __init__(self, master, studio, **cnf): super().__init__(master, studio, **cnf) self.header = Frame(self, **self.style.surface) self.header.pack(side="top", fill="x") for i, title in enumerate(("Sequence", "Handler", "Add", " " * 3)): Label( self.header, **self.style.text_passive, text=title, anchor="w", ).grid(row=0, column=i, sticky='ew') # set the first two columns to expand evenly for column in range(2): self.header.grid_columnconfigure(column, weight=1, uniform=1) self.bindings = BindingsTable(self) self.bindings.on_value_change(self.modify_item) self.bindings.on_item_delete(self.delete_item) self.bindings.pack(fill="both", expand=True) self._add = Button(self._header, **self.style.button, width=25, height=25, image=get_icon_image("add", 15, 15)) self._add.pack(side="right") self._add.tooltip("Add event binding") self._add.on_click(self.add_new) self._search_btn = Button( self._header, **self.style.button, image=get_icon_image("search", 15, 15), width=25, height=25, ) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self._empty_frame = Label(self.bindings, **self.style.text_passive) self._show_empty(self.NO_SELECTION_MSG)
def __init__(self, master, studio=None, **cnf): if not self._var_init: self._init_var(studio) super().__init__(master, studio, **cnf) f = Frame(self, **self.style.surface) f.pack(side="top", fill="both", expand=True, pady=4) f.pack_propagate(0) self._widget_set = Spinner(self._header, width=150) self._widget_set.config(**self.style.no_highlight) self._widget_set.set_values(list(self.CLASSES.keys())) self._widget_set.pack(side="left") self._widget_set.on_change(self.collect_groups) self._select_pane = ScrolledFrame(f, width=150) self._select_pane.place(x=0, y=0, relwidth=0.4, relheight=1) self._search_btn = Button(self._header, image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self._search_selector = Label(self._select_pane.body, **self.style.text, text="search", anchor="w") self._search_selector.configure(**self.style.hover) self._widget_pane = ScrolledFrame(f, width=150) self._select_pane.body.config(**self.style.surface) self._widget_pane.place(relx=0.4, y=0, relwidth=0.6, relheight=1) self._pool = {} self._selectors = [] self._selected = None self._component_cache = None self._extern_groups = [] self._widget = None self.collect_groups(self.get_pref("widget_set")) # add custom widgets config to settings templates.update(_widget_pref_template) self._custom_group = None self._custom_widgets = [] Preferences.acquire().add_listener(self._custom_pref_path, self._init_custom) self._reload_custom()
def __init__(self, master, studio=None, **cnf): if not self._var_init: self._init_var(studio) super().__init__(master, studio, **cnf) f = Frame(self, **self.style.dark) f.pack(side="top", fill="both", expand=True, pady=4) f.pack_propagate(0) self._widget_set = Spinner(self._header, width=150) self._widget_set.config(**self.style.no_highlight) self._widget_set.set_values(list(self.CLASSES.keys())) self._widget_set.pack(side="left") self._widget_set.on_change(self.collect_groups) self._select_pane = ScrolledFrame(f, width=150) self._select_pane.place(x=0, y=0, relwidth=0.4, relheight=1) self._search_btn = Button(self._header, image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.dark_button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self._search_selector = Label(self._select_pane.body, **self.style.dark_text, text="search", anchor="w") self._search_selector.configure(**self.style.dark_on_hover) self._widget_pane = ScrolledFrame(f, width=150, bg="orange") self._select_pane.body.config(**self.style.dark) self._widget_pane.place(relx=0.4, y=0, relwidth=0.6, relheight=1) self._pool = {} self._selectors = [] self._selected = None self._component_cache = None self.collect_groups(self.get_pref("widget_set"))
def __init__(self, master, studio=None, **cnf): super().__init__(master, studio, **cnf) f = Frame(self, **self.style.surface) f.pack(side="top", fill="both", expand=True, pady=4) f.pack_propagate(0) self._variable_pane = ScrolledFrame(f, width=150) self._variable_pane.place(x=0, y=0, relwidth=0.4, relheight=1) self._detail_pane = ScrolledFrame(f, width=150) self._detail_pane.place(relx=0.4, y=0, relwidth=0.6, relheight=1, x=15, width=-20) Label(self._detail_pane.body, **self.style.text_passive, text="Type", anchor="w").pack(side="top", fill="x") self.var_type_lbl = Label(self._detail_pane.body, **self.style.text, anchor="w") self.var_type_lbl.pack(side="top", fill="x") Label(self._detail_pane.body, **self.style.text_passive, text="Name", anchor="w").pack(side="top", fill="x") self.var_name = editors.get_editor(self._detail_pane.body, self._definitions["name"]) self.var_name.pack(side="top", fill="x") Label(self._detail_pane.body, **self.style.text_passive, text="Value", anchor="w").pack(fill="x", side="top") self._editors = {} self._editor = None self._search_btn = Button(self._header, image=get_icon_image("search", 15, 15), width=25, height=25, **self.style.button) self._search_btn.pack(side="right") self._search_btn.on_click(self.start_search) self._search_query = None self._add = MenuButton(self._header, **self.style.button) self._add.configure(image=get_icon_image("add", 15, 15)) self._add.pack(side="right") self._delete_btn = Button(self._header, image=get_icon_image("delete", 15, 15), width=25, height=25, **self.style.button) self._delete_btn.pack(side="right") self._delete_btn.on_click(self._delete) self._var_types_menu = self.make_menu(self._get_add_menu(), self._add, title="Add variable") self._var_types_menu.configure(tearoff=True) self._add.config(menu=self._var_types_menu) self._selected = None self._links = {} self._overlay = Label(f, **self.style.text_passive, text=self._empty_message, compound="top") self._overlay.configure(image=get_icon_image("add", 25, 25)) self._show_overlay(True)
def _make_button_bar(self): self.bar = Frame(self, **self.style.dark, **self.style.dark_highlight_dim) self.bar.pack(side="bottom", fill="x")
def __init__(self, master=None, **cnf): super().__init__(master, **cnf) # Load icon asynchronously to prevent issues which have been known to occur when loading it synchronously icon_image = load_tk_image(self.ICON_PATH) self.iconphoto(True, icon_image) self.pref = pref self._restore_position() self.title('Formation Studio') self.protocol('WM_DELETE_WINDOW', self._on_close) self.shortcuts = ShortcutManager(self, pref) self.shortcuts.bind_all() self._register_actions() self._toolbar = Frame(self, **self.style.dark, height=30) self._toolbar.pack(side="top", fill="x") self._toolbar.pack_propagate(0) self._statusbar = Frame(self, **self.style.dark, height=20) self._statusbar.pack(side="bottom", fill="x") self._statusbar.pack_propagate(0) body = Frame(self, **self.style.dark) body.pack(fill="both", expand=True, side="top") self._right_bar = SideBar(body) self._right_bar.pack(side="right", fill="y") self._left_bar = SideBar(body) self._left_bar.pack(side="left", fill="y") self._pane = PanedWindow(body, **self.style.dark_pane_horizontal) self._pane.pack(side="left", fill="both", expand=True) self._left = PanedWindow(self._pane, **self.style.dark_pane_vertical) self._center = PanedWindow(self._pane, **self.style.dark_pane_vertical) self._right = PanedWindow(self._pane, **self.style.dark_pane_vertical) self._bin = [] self._clipboard = None self._undo_stack = [] self._redo_stack = [] self.current_preview = None self._pane.add(self._left, minsize=320, sticky='nswe', width=320) self._pane.add(self._center, minsize=400, width=16000, sticky='nswe') self._pane.add(self._right, minsize=320, sticky='nswe', width=320) self._panes = { "left": (self._left, self._left_bar), "right": (self._right, self._right_bar), "center": (self._center, None) } icon = get_icon_image self.actions = ( ("Delete", icon("delete", 20, 20), lambda e: self.delete(), "Delete selected widget"), ("Undo", icon("undo", 20, 20), lambda e: self.undo(), "Undo action"), ("Redo", icon("redo", 20, 20), lambda e: self.redo(), "Redo action"), ("Cut", icon("cut", 20, 20), lambda e: self.cut(), "Cut selected widget"), ("separator", ), ("Fullscreen", icon("image_editor", 20, 20), lambda e: self.close_all(), "Design mode"), ("Separate", icon("separate", 20, 20), lambda e: self.features_as_windows(), "Open features in window mode"), ("Dock", icon("flip_horizontal", 15, 15), lambda e: self.features_as_docked(), "Dock all features"), ("separator", ), ("New", icon("add", 20, 20), lambda e: self.open_new(), "New design"), ("Save", icon("save", 20, 20), lambda e: self.save(), "Save design"), ("Preview", icon("play", 20, 20), lambda e: self.preview(), "Preview design"), ) self.init_toolbar() self.selected = None # set the image option to blank if there is no image for the menu option self.blank_img = blank_img = icon("blank", 14, 14) # -------------------------------------------- menu definition ------------------------------------------------ self.menu_template = (EnableIf( lambda: self.selected, ("separator", ), ("command", "copy", icon("copy", 14, 14), actions.get('STUDIO_COPY'), {}), ("command", "paste", icon("clipboard", 14, 14), actions.get('STUDIO_PASTE'), {}), ("command", "cut", icon("cut", 14, 14), actions.get('STUDIO_CUT'), {}), ("separator", ), ("command", "delete", icon("delete", 14, 14), actions.get('STUDIO_DELETE'), {}), ), ) self.menu_bar = MenuUtils.make_dynamic( (("cascade", "File", None, None, { "menu": ( ("command", "New", icon( "add", 14, 14), actions.get('STUDIO_NEW'), {}), ("command", "Open", icon( "folder", 14, 14), actions.get('STUDIO_OPEN'), {}), ("cascade", "Recent", icon("clock", 14, 14), None, { "menu": self._create_recent_menu() }), ("separator", ), ("command", "Save", icon( "save", 14, 14), actions.get('STUDIO_SAVE'), {}), ("command", "Save As", icon( "save", 14, 14), actions.get('STUDIO_SAVE_AS'), {}), ("separator", ), ("command", "Settings", icon("settings", 14, 14), actions.get('STUDIO_SETTINGS'), {}), ("command", "Exit", icon( "exit", 14, 14), actions.get('STUDIO_EXIT'), {}), ) }), ("cascade", "Edit", None, None, { "menu": ( EnableIf(lambda: len(self._undo_stack), ("command", "undo", icon("undo", 14, 14), actions.get('STUDIO_UNDO'), {})), EnableIf(lambda: len(self._redo_stack), ("command", "redo", icon("redo", 14, 14), actions.get('STUDIO_REDO'), {})), *self.menu_template, ) }), ("cascade", "Code", None, None, { "menu": (EnableIf(lambda: self.designer and self.designer.root_obj, ("command", "Preview design", icon("play", 14, 14), actions.get('STUDIO_PREVIEW'), {}), ("command", "close preview", icon("close", 14, 14), actions.get('STUDIO_PREVIEW_CLOSE'), {}))) }), ("cascade", "Window", None, None, { "menu": (("command", "show all", blank_img, actions.get('FEATURE_SHOW_ALL'), {}), ("command", "close all", icon( "close", 14, 14), actions.get('FEATURE_CLOSE_ALL'), {}), ("command", "close all on the right", blank_img, actions.get('FEATURE_CLOSE_RIGHT'), {}), ("command", "close all on the left", blank_img, actions.get('FEATURE_CLOSE_LEFT'), {}), ("separator", ), ("command", "Undock all windows", blank_img, actions.get('FEATURE_UNDOCK_ALL'), {}), ("command", "Dock all windows", blank_img, actions.get('FEATURE_DOCK_ALL'), {}), ("separator", ), LoadLater(self.get_features_as_menu), ("separator", ), ("command", "Save window positions", blank_img, actions.get('FEATURE_SAVE_POS'), {})) }), ("cascade", "Tools", None, None, { "menu": ToolManager.get_tools_as_menu(self) }), ("cascade", "Help", None, None, { "menu": ( ("command", "Help", icon('dialog_info', 14, 14), actions.get('STUDIO_HELP'), {}), ("command", "Check for updates", icon("cloud", 14, 14), None, {}), ("separator", ), ("command", "About Studio", blank_img, lambda: about_window(self), {}), ) })), self, self.style, False) self.config(menu=self.menu_bar) self.features = [] self.designer = Designer(self._center, self) self._center.add(self.designer, sticky='nswe') self.install(ComponentPane) self.install(ComponentTree) self.install(StylePane) self.install(VariablePane) self._startup() self._restore_position()
def __init__(self, master, widget, menu=None): super().__init__(master, widget) self.title(f'Edit menu for {widget.id}') if not isinstance(menu, tk.Menu): menu = tk.Menu(widget, tearoff=False) widget.configure(menu=menu) self._base_menu = menu self._tool_bar = Frame(self, **self.style.dark, **self.style.dark_highlight_dim, height=30) self._tool_bar.pack(side="top", fill="x") self._tool_bar.pack_propagate(False) self._pane = PanedWindow(self, **self.style.dark_pane_horizontal) self._tree = MenuTree(self._pane, widget, menu) self._tree.allow_multi_select(True) self._tree.on_select(self._refresh_styles) self._tree.on_structure_change(self._refresh_styles) self._editor_pane = ScrolledFrame(self._pane) self._editor_pane_cover = Label(self._editor_pane, **self.style.dark_text_passive) self._editor_pane.pack(side="top", fill="both", expand=True) self._menu_item_styles = CollapseFrame(self._editor_pane.body) self._menu_item_styles.pack(side="top", fill="x", pady=4) self._menu_item_styles.label = "Menu Item attributes" self._menu_styles = CollapseFrame(self._editor_pane.body) self._menu_styles.pack(side="top", fill="x", pady=4) self._menu_styles.label = "Menu attributes" self._style_item_ref = {} self._menu_style_ref = {} self._prev_selection = None self._add = MenuButton(self._tool_bar, **self.style.dark_button) self._add.pack(side="left") self._add.configure(image=get_icon_image("add", 15, 15)) _types = MenuTree.Node._type_def menu_types = self._tool_bar.make_menu( [( tk.COMMAND, i.title(), get_icon_image(_types[i][0], 14, 14), functools.partial(self.add_item, i), {} ) for i in _types], self._add) menu_types.configure(tearoff=True) self._add.config(menu=menu_types) self._delete_btn = Button(self._tool_bar, image=get_icon_image("delete", 15, 15), **self.style.dark_button, width=25, height=25) self._delete_btn.pack(side="left") self._delete_btn.on_click(self._delete) self._preview_btn = Button(self._tool_bar, image=get_icon_image("play", 15, 15), **self.style.dark_button, width=25, height=25) self._preview_btn.pack(side="left") self._preview_btn.on_click(self._preview) self._pane.pack(side="top", fill="both", expand=True) self._pane.add(self._tree, minsize=350, sticky='nswe', width=350, height=500) self._pane.add(self._editor_pane, minsize=320, sticky='nswe', width=320, height=500) self.load_menu(menu, self._tree) self._show_editor_message(self._MESSAGE_EDITOR_EMPTY) self.enable_centering() self.focus_set() self._load_all_properties()
def __init__(self, master=None, **cnf): super().__init__(master, **cnf) # Load icon asynchronously to prevent issues which have been known to occur when loading it synchronously icon_image = load_tk_image(self.ICON_PATH) self.load_styles(self.THEME_PATH) self.iconphoto(True, icon_image) self.pref = pref self._restore_position() self.title('Formation Studio') self.protocol('WM_DELETE_WINDOW', self._on_close) self.shortcuts = ShortcutManager(self, pref) self.shortcuts.bind_all() self._register_actions() self._toolbar = Frame(self, **self.style.surface, height=30) self._toolbar.pack(side="top", fill="x") self._toolbar.pack_propagate(0) self._statusbar = Frame(self, **self.style.surface, height=20) self._statusbar.pack(side="bottom", fill="x") self._statusbar.pack_propagate(0) body = Frame(self, **self.style.surface) body.pack(fill="both", expand=True, side="top") self._right_bar = SideBar(body) self._right_bar.pack(side="right", fill="y") self._left_bar = SideBar(body) self._left_bar.pack(side="left", fill="y") self._pane = PanedWindow(body, **self.style.pane_horizontal) self._pane.pack(side="left", fill="both", expand=True) self._left = FeaturePane(self._pane, **self.style.pane_vertical) self._center = PanedWindow(self._pane, **self.style.pane_vertical) self._right = FeaturePane(self._pane, **self.style.pane_vertical) self._bin = [] self._clipboard = None self.current_preview = None self._pane.add(self._left, minsize=320, sticky='nswe', width=320) self._pane.add(self._center, minsize=400, width=16000, sticky='nswe') self._pane.add(self._right, minsize=320, sticky='nswe', width=320) self._panes = { "left": (self._left, self._left_bar), "right": (self._right, self._right_bar), "center": (self._center, None) } icon = get_icon_image self.actions = ( ("Delete", icon("delete", 20, 20), lambda e: self.delete(), "Delete selected widget"), ("Undo", icon("undo", 20, 20), lambda e: self.undo(), "Undo action"), ("Redo", icon("redo", 20, 20), lambda e: self.redo(), "Redo action"), ("Cut", icon("cut", 20, 20), lambda e: self.cut(), "Cut selected widget"), ("separator",), ("Fullscreen", icon("image_editor", 20, 20), lambda e: self.close_all(), "Design mode"), ("Separate", icon("separate", 20, 20), lambda e: self.features_as_windows(), "Open features in window mode"), ("Dock", icon("flip_horizontal", 15, 15), lambda e: self.features_as_docked(), "Dock all features"), ("separator",), ("New", icon("add", 20, 20), lambda e: self.open_new(), "New design"), ("Save", icon("save", 20, 20), lambda e: self.save(), "Save design"), ("Preview", icon("play", 20, 20), lambda e: self.preview(), "Preview design"), ) self.init_toolbar() self.selected = None # set the image option to blank if there is no image for the menu option self.blank_img = blank_img = icon("blank", 14, 14) self.tool_manager = ToolManager(self) # -------------------------------------------- menu definition ------------------------------------------------ self.menu_template = (EnableIf( lambda: self.selected, ("separator",), ("command", "copy", icon("copy", 14, 14), actions.get('STUDIO_COPY'), {}), ("command", "duplicate", icon("copy", 14, 14), actions.get('STUDIO_DUPLICATE'), {}), EnableIf( lambda: self._clipboard is not None, ("command", "paste", icon("clipboard", 14, 14), actions.get('STUDIO_PASTE'), {}) ), ("command", "cut", icon("cut", 14, 14), actions.get('STUDIO_CUT'), {}), ("separator",), ("command", "delete", icon("delete", 14, 14), actions.get('STUDIO_DELETE'), {}), ),) self.menu_bar = MenuUtils.make_dynamic( (( ("cascade", "formation", None, None, {"menu": ( ("command", "Restart", None, actions.get('STUDIO_RESTART'), {}), ("separator", ), ("command", "About Formation", icon("formation", 14, 14), lambda: about_window(self), {}), ), "name": "apple"}), ) if platform_is(MAC) else ()) + ( ("cascade", "File", None, None, {"menu": ( ("command", "New", icon("add", 14, 14), actions.get('STUDIO_NEW'), {}), ("command", "Open", icon("folder", 14, 14), actions.get('STUDIO_OPEN'), {}), ("cascade", "Recent", icon("clock", 14, 14), None, {"menu": self._create_recent_menu()}), ("separator",), EnableIf( lambda: self.designer, ("command", "Save", icon("save", 14, 14), actions.get('STUDIO_SAVE'), {}), ("command", "Save As", icon("blank", 14, 14), actions.get('STUDIO_SAVE_AS'), {}) ), EnableIf( # more than one design contexts open lambda: len([i for i in self.contexts if isinstance(i, DesignContext)]) > 1, ("command", "Save All", icon("blank", 14, 14), actions.get('STUDIO_SAVE_ALL'), {}) ), ("separator",), ("command", "Settings", icon("settings", 14, 14), actions.get('STUDIO_SETTINGS'), {}), ("command", "Restart", icon("blank", 14, 14), actions.get('STUDIO_RESTART'), {}), ("command", "Exit", icon("close", 14, 14), actions.get('STUDIO_EXIT'), {}), )}), ("cascade", "Edit", None, None, {"menu": ( EnableIf(lambda: self.context and self.context.has_undo(), ("command", "undo", icon("undo", 14, 14), actions.get('STUDIO_UNDO'), {})), EnableIf(lambda: self.context and self.context.has_redo(), ("command", "redo", icon("redo", 14, 14), actions.get('STUDIO_REDO'), {})), *self.menu_template, )}), ("cascade", "Code", None, None, {"menu": ( EnableIf( lambda: self.designer and self.designer.root_obj, ("command", "Preview design", icon("play", 14, 14), actions.get('STUDIO_PREVIEW'), {}), ("command", "close preview", icon("close", 14, 14), actions.get('STUDIO_PREVIEW_CLOSE'), {}), ("separator", ), EnableIf( lambda: self.designer and self.designer.design_path, ("command", "Reload design file", icon("rotate_clockwise", 14, 14), actions.get('STUDIO_RELOAD'), {}), ), ) )}), ("cascade", "View", None, None, {"menu": ( ("command", "show all panes", blank_img, actions.get('FEATURE_SHOW_ALL'), {}), ("command", "close all panes", icon("close", 14, 14), actions.get('FEATURE_CLOSE_ALL'), {}), ("command", "close all panes on the right", blank_img, actions.get('FEATURE_CLOSE_RIGHT'), {}), ("command", "close all panes on the left", blank_img, actions.get('FEATURE_CLOSE_LEFT'), {}), ("separator",), ("command", "Undock all windows", blank_img, actions.get('FEATURE_UNDOCK_ALL'), {}), ("command", "Dock all windows", blank_img, actions.get('FEATURE_DOCK_ALL'), {}), ("separator",), LoadLater(self.get_features_as_menu), ("separator",), EnableIf( lambda: self.context, ("command", "close tab", icon("close", 14, 14), actions.get('CONTEXT_CLOSE'), {}), ("command", "close all tabs", blank_img, actions.get('CONTEXT_CLOSE_ALL'), {}), EnableIf( lambda: self.context and len(self.tab_view.tabs()) > 1, ("command", "close other tabs", blank_img, actions.get('CONTEXT_CLOSE_OTHER'), {}) ), EnableIf( lambda: self.context and self.context._contexts_right(), ("command", "close all tabs on the right", blank_img, actions.get('CONTEXT_CLOSE_OTHER_RIGHT'), {}) ) ), ("separator",), ("command", "Save window positions", blank_img, actions.get('FEATURE_SAVE_POS'), {}) )}), ("cascade", "Tools", None, None, {"menu": (LoadLater(self.tool_manager.get_tools_as_menu), )}), ("cascade", "Help", None, None, {"menu": ( ("command", "Help", icon('dialog_info', 14, 14), actions.get('STUDIO_HELP'), {}), ("command", "Check for updates", icon("cloud", 14, 14), self._check_updates, {}), ("separator",), ("command", "About Formation", icon("formation", 14, 14), lambda: about_window(self), {}), )}) ), self, self.style, False) self.config(menu=self.menu_bar) if platform_is(MAC): self.createcommand("tk::mac::ShowPreferences", lambda: actions.get('STUDIO_SETTINGS').invoke()) self.createcommand("tk::mac::ShowHelp", lambda: actions.get('STUDIO_HELP').invoke()) self.createcommand("tk::mac::Quit", lambda: actions.get('STUDIO_EXIT').invoke()) self.features = [] self.context = None self.contexts = [] self.tab_view = TabView(self._center) self.tab_view.malleable(True) self.tab_view.bind("<<TabSelectionChanged>>", self.on_context_switch) self.tab_view.bind("<<TabClosed>>", self.on_context_close) self.tab_view.bind("<<TabAdded>>", self.on_context_add) self.tab_view.bind("<<TabOrderChanged>>", lambda _: self.save_tab_status()) self._center.add(self.tab_view, sticky='nswe') self._tab_view_empty = Label( self.tab_view, **self.style.text_passive, compound='top', image=get_icon_image("paint", 60, 60) ) self._tab_view_empty.config(**self.style.bright) # install features for feature in FEATURES: self.install(feature) # common feature references self.style_pane = self.get_feature(StylePane) # initialize tools with everything ready self.tool_manager.initialize() self._ignore_tab_status = False self._startup() self._exit_failures = 0 self._is_shutting_down = False
def initialize_tree(self): super(ComponentTreeView, self).initialize_tree() self._empty = Frame(self, **self.style.surface) self._empty_text = Label(self._empty, **self.style.text_passive) self._empty_text.pack(fill="both", expand=True, pady=30) self._show_empty("No items created yet")