def get_screen_dpi(): ''' Return screen DPI ''' try: xft_dpi = Gtk.settings_get_default().get_property('gtk-xft-dpi') dpi = float(xft_dpi / 1024) return dpi except BaseException: return 100
def __init__(self, event_manager): super().__init__(event_manager) self._event_handlers = [] self.gui_is_active = False self.gui = Gtk.Builder() self._mainloop_is_running = False self.mainloop = get_mainloop(use_gtk=True) gtk_build_file = get_ui_file_location(GTKBUILD_FILE) if gtk_build_file is None: raise InitializationError( "Failed to load GTK layout specification file: {}".format( gtk_build_file)) self.gui.add_from_file(gtk_build_file) if pycam.Utils.get_platform() == pycam.Utils.OSPlatform.WINDOWS: gtkrc_file = get_ui_file_location(GTKRC_FILE_WINDOWS) if gtkrc_file: Gtk.rc_add_default_file(gtkrc_file) Gtk.rc_reparse_all_for_settings(Gtk.settings_get_default(), True) action_group = Gio.SimpleActionGroup() self.settings.set("gtk_action_group_prefix", "pycam") self.settings.set("gtk_action_group", action_group) self.window = self.gui.get_object("ProjectWindow") self.window.insert_action_group( self.settings.get("gtk_action_group_prefix"), self.settings.get("gtk_action_group")) self.settings.set("main_window", self.window) # show stock items on buttons # increase the initial width of the window (due to hidden elements) self.window.set_default_size(400, -1) # initialize the RecentManager (TODO: check for Windows) if False and pycam.Utils.get_platform( ) == pycam.Utils.OSPlatform.WINDOWS: # The pyinstaller binary for Windows fails mysteriously when trying # to display the stock item. # Error message: Gtk:ERROR:gtkrecentmanager.c:1942:get_icon_fallback: # assertion failed: (retval != NULL) self.recent_manager = None else: try: self.recent_manager = Gtk.recent_manager_get_default() except AttributeError: # GTK 2.12.1 seems to have problems with "RecentManager" on # Windows. Sadly this is the version, that is shipped with the # "appunti" GTK packages for Windows (April 2010). # see http://www.daa.com.au/pipermail/pygtk/2009-May/017052.html self.recent_manager = None # file loading self.last_dirname = None self.last_model_uri = None # define callbacks and accelerator keys for the menu actions for objname, callback, data, accel_key in ( ("OpenModel", self.load_model_file, None, "<Control>o"), ("Quit", self.destroy, None, "<Control>q"), ("GeneralSettings", self.toggle_preferences_window, None, "<Control>p"), ("UndoButton", self.restore_undo_state, None, "<Control>z"), ("HelpIntroduction", self.show_help, "introduction", "F1"), ("HelpSupportedFormats", self.show_help, "supported-formats", None), ("HelpModelTransformations", self.show_help, "model-transformations", None), ("HelpProcessSettings", self.show_help, "process-settings", None), ("HelpBoundsSettings", self.show_help, "bounding-box", None), ("HelpTouchOff", self.show_help, "touch-off", None), ("Help3DView", self.show_help, "3d-view", None), ("HelpServerMode", self.show_help, "server-mode", None), ("HelpCommandLine", self.show_help, "cli-examples", None), ("HelpHotkeys", self.show_help, "keyboard-shortcuts", None), ("ProjectWebsite", self.show_help, "http://pycam.sourceforge.net", None), ("DevelopmentBlog", self.show_help, "http://fab.senselab.org/pycam", None), ("Forum", self.show_help, "http://sourceforge.net/projects/pycam/forums", None), ("BugTracker", self.show_help, "https://github.com/SebKuzminsky/pycam/issues/", None), ("FeatureRequest", self.show_help, "https://github.com/SebKuzminsky/pycam/issues/", None)): item = self.gui.get_object(objname) action = "activate" if data is None: item.connect(action, callback) else: item.connect(action, callback, data) if accel_key: key, mod = Gtk.accelerator_parse(accel_key) accel_path = "<pycam>/%s" % objname item.set_accel_path(accel_path) # Gtk.accel_map_change_entry(accel_path, key, mod, True) FIXME # LinkButton does not work on Windows: https://bugzilla.gnome.org/show_bug.cgi?id=617874 if pycam.Utils.get_platform() == pycam.Utils.OSPlatform.WINDOWS: def open_url(widget, data=None): webbrowser.open(widget.get_uri()) Gtk.link_button_set_uri_hook(open_url) # configure drag-n-drop for config files and models self.settings.set("configure-drag-drop-func", self.configure_drag_and_drop) self.settings.get("configure-drag-drop-func")(self.window) # other events self.window.connect("destroy", self.destroy) self.window.connect("delete-event", self.destroy) # the settings window self.gui.get_object("CloseSettingsWindow").connect( "clicked", self.toggle_preferences_window, False) self.gui.get_object("ResetPreferencesButton").connect( "clicked", self.reset_preferences) self.preferences_window = self.gui.get_object("GeneralSettingsWindow") self.preferences_window.connect("delete-event", self.toggle_preferences_window, False) self.preferences_window.insert_action_group( self.settings.get("gtk_action_group_prefix"), self.settings.get("gtk_action_group")) self._preferences_window_position = None self._preferences_window_visible = False # "about" window self.about_window = self.gui.get_object("AboutWindow") self.about_window.set_version(VERSION) self.about_window.insert_action_group( self.settings.get("gtk_action_group_prefix"), self.settings.get("gtk_action_group")) self.gui.get_object("About").connect("activate", self.toggle_about_window, True) # we assume, that the last child of the window is the "close" button # TODO: fix this ugly hack! about_window_children = self.gui.get_object( "AboutWindowButtons").get_children() if about_window_children: # it seems to be possible that there are no children - weird :( # see https://github.com/SebKuzminsky/pycam/issues/59 about_window_children[-1].connect("clicked", self.toggle_about_window, False) self.about_window.connect("delete-event", self.toggle_about_window, False) # menu bar uimanager = Gtk.UIManager() self.settings.set("gtk-uimanager", uimanager) self._accel_group = uimanager.get_accel_group() # send a "delete" event on "CTRL-w" for every window self._accel_group.connect( ord('w'), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.LOCKED, lambda accel_group, window, *args: window.emit( "delete-event", Gdk.Event())) self._accel_group.connect(ord('q'), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.LOCKED, lambda *args: self.destroy()) self.settings.add_item("gtk-accel-group", lambda: self._accel_group) for obj in self.gui.get_objects(): if isinstance(obj, Gtk.Window): obj.add_accel_group(self._accel_group) # preferences tab preferences_book = self.gui.get_object("PreferencesNotebook") def clear_preferences(): for child in preferences_book.get_children(): preferences_book.remove(child) def add_preferences_item(item, name): preferences_book.append_page(item, Gtk.Label(name)) self.settings.register_ui_section("preferences", add_preferences_item, clear_preferences) for obj_name, label, priority in (("GeneralSettingsPrefTab", "General", -50), ("ProgramsPrefTab", "Programs", 50)): obj = self.gui.get_object(obj_name) obj.unparent() self.settings.register_ui("preferences", label, obj, priority) # general preferences general_prefs = self.gui.get_object("GeneralPreferencesBox") def clear_general_prefs(): for item in general_prefs.get_children(): general_prefs.remove(item) def add_general_prefs_item(item, name): general_prefs.pack_start(item, expand=False, fill=False, padding=3) self.settings.register_ui_section("preferences_general", add_general_prefs_item, clear_general_prefs) # set defaults main_tab = self.gui.get_object("MainTabs") def clear_main_tab(): while main_tab.get_n_pages() > 0: main_tab.remove_page(0) def add_main_tab_item(item, name): main_tab.append_page(item, Gtk.Label(name)) # TODO: move these to plugins, as well self.settings.register_ui_section("main", add_main_tab_item, clear_main_tab) main_window = self.gui.get_object("WindowBox") def clear_main_window(): main_window.foreach(main_window.remove) def add_main_window_item(item, name, **extra_args): # some widgets may want to override the defaults args = {"expand": False, "fill": False, "padding": 3} args.update(extra_args) main_window.pack_start(item, **args) main_tab.unparent() self.settings.register_ui_section("main_window", add_main_window_item, clear_main_window) self.settings.register_ui("main_window", "Tabs", main_tab, -20, args_dict={ "expand": True, "fill": True }) def disable_gui(): self.menubar.set_sensitive(False) main_tab.set_sensitive(False) def enable_gui(): self.menubar.set_sensitive(True) main_tab.set_sensitive(True) # configure locations of external programs for auto_control_name, location_control_name, browse_button, key in ( ("ExternalProgramInkscapeAuto", "ExternalProgramInkscapeControl", "ExternalProgramInkscapeBrowse", "inkscape"), ("ExternalProgramPstoeditAuto", "ExternalProgramPstoeditControl", "ExternalProgramPstoeditBrowse", "pstoedit")): self.gui.get_object(auto_control_name).connect( "clicked", self._locate_external_program, key) location_control = self.gui.get_object(location_control_name) self.settings.add_item("external_program_%s" % key, location_control.get_text, location_control.set_text) self.gui.get_object(browse_button).connect( "clicked", self._browse_external_program_location, key) for objname, callback in ( ("ResetWorkspace", lambda widget: self.reset_workspace()), ("LoadWorkspace", lambda widget: self.load_workspace_dialog()), ("SaveWorkspace", lambda widget: self.save_workspace_dialog(self.last_workspace_uri) ), ("SaveAsWorkspace", lambda widget: self.save_workspace_dialog())): self.gui.get_object(objname).connect("activate", callback) # set the icons (in different sizes) for all windows # Gtk.window_set_default_icon_list(*get_icons_pixbuffers()) FIXME # load menu data gtk_menu_file = get_ui_file_location(GTKMENU_FILE) if gtk_menu_file is None: raise InitializationError( "Failed to load GTK menu specification file: {}".format( gtk_menu_file)) uimanager.add_ui_from_file(gtk_menu_file) # make the actions defined in the GTKBUILD file available in the menu actiongroup = Gtk.ActionGroup("menubar") for action in [ aobj for aobj in self.gui.get_objects() if isinstance(aobj, Gtk.Action) ]: actiongroup.add_action(action) # the "pos" parameter is optional since 2.12 - we can remove it later uimanager.insert_action_group(actiongroup) # the "recent files" sub-menu if self.recent_manager is not None: recent_files_menu = Gtk.RecentChooserMenu(self.recent_manager) recent_files_menu.set_name("RecentFilesMenu") recent_menu_filter = Gtk.RecentFilter() case_converter = pycam.Utils.get_case_insensitive_file_pattern for filter_name, patterns in FILTER_MODEL: if not isinstance(patterns, (list, set, tuple)): patterns = [patterns] # convert it into a mutable list (instead of set/tuple) patterns = list(patterns) for index in range(len(patterns)): patterns[index] = case_converter(patterns[index]) for pattern in patterns: recent_menu_filter.add_pattern(pattern) recent_files_menu.add_filter(recent_menu_filter) recent_files_menu.set_show_numbers(True) # non-local files (without "file://") are not supported. yet recent_files_menu.set_local_only(False) # most recent files to the top recent_files_menu.set_sort_type(Gtk.RECENT_SORT_MRU) # show only ten files recent_files_menu.set_limit(10) uimanager.get_widget("/MenuBar/FileMenu/OpenRecentModelMenu" ).set_submenu(recent_files_menu) recent_files_menu.connect("item-activated", self.load_recent_model_file) else: self.gui.get_object("OpenRecentModel").set_visible(False) # load the menubar and connect functions to its items self.menubar = uimanager.get_widget("/MenuBar") # dict of all merge-ids menu_merges = {} def clear_menu(menu_key): for merge in menu_merges.get(menu_key, []): uimanager.remove_ui(merge) def append_menu_item(menu_key, base_path, widget, name): merge_id = uimanager.new_merge_id() if widget: action_group = widget.props.action_group if action_group not in uimanager.get_action_groups(): uimanager.insert_action_group(action_group, -1) widget_name = widget.get_name() item_type = Gtk.UIManagerItemType.MENU else: widget_name = name item_type = Gtk.UIManagerItemType.SEPARATOR uimanager.add_ui(merge_id, base_path, name, widget_name, item_type, False) if menu_key not in menu_merges: menu_merges[menu_key] = [] menu_merges[menu_key].append(merge_id) def get_menu_funcs(menu_key, base_path): return (lambda widget, name: append_menu_item( menu_key, base_path, widget, name), lambda: clear_menu(menu_key)) for ui_name, base_path in (("view_menu", "/MenuBar/ViewMenu"), ("file_menu", "/MenuBar/FileMenu"), ("edit_menu", "/MenuBar/EditMenu"), ("export_menu", "/MenuBar/FileMenu/ExportMenu")): append_func, clear_func = get_menu_funcs(ui_name, base_path) self.settings.register_ui_section(ui_name, append_func, clear_func) self.settings.register_ui("file_menu", "Quit", self.gui.get_object("Quit"), 100) self.settings.register_ui("file_menu", "QuitSeparator", None, 95) self.settings.register_ui("main_window", "Main", self.menubar, -100) self.settings.set("set_last_filename", self.add_to_recent_file_list) self._event_handlers.extend(( ("history-changed", self._update_undo_button), ("model-change-after", "visual-item-updated"), ("gui-disable", disable_gui), ("gui-enable", enable_gui), ("notify-file-saved", self.add_to_recent_file_list), ("notify-file-opened", self.add_to_recent_file_list), )) for name, target in self._event_handlers: self.settings.register_event(name, target) # allow the task settings control to be updated self.mainloop.update() # register a logging handler for displaying error messages pycam.Utils.log.add_gtk_gui(self.window, logging.ERROR) self.window.show() self.mainloop.update()
GTK_RESPONSE_CANCEL = gtk.ResponseType.CANCEL GTK_DIALOG_MESSAGE_INFO = gtk.MessageType.INFO GTK_DIALOG_MESSAGE_ERROR = gtk.MessageType.ERROR GTK_RESPONSE_OK = gtk.ResponseType.OK settings = gtk.Settings.get_default() gtk.Settings.set_long_property(settings, "gtk-button-images", 1, "main") else: import gtk GTK_BUTTON_CANCEL = gtk.BUTTONS_CANCEL GTK_DIALOG_MODAL = gtk.DIALOG_MODAL GTK_DIALOG_DESTROY_WITH_PARENT = gtk.DIALOG_DESTROY_WITH_PARENT GTK_BUTTON_OK = gtk.BUTTONS_OK GTK_DIALOG_MESSAGE_INFO = gtk.MESSAGE_INFO GTK_DIALOG_MESSAGE_ERROR = gtk.MESSAGE_ERROR GTK_RESPONSE_OK = gtk.RESPONSE_OK settings = gtk.settings_get_default() gtk.Settings.set_long_property(settings, "gtk-button-images", 1, "main") import os import sys import shutil import decimal try: import psycopg2 psycopg2.extensions.register_adapter(decimal.Decimal, psycopg2._psycopg.Decimal) except: pass import sqlalchemy if "0.7.4" > sqlalchemy.__version__: dialoggg = gtk.MessageDialog(None, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
def foobnix(): if "--debug" in sys.argv: LOG.with_print = True for param in sys.argv: if param.startswith("--log"): if "=" in param: filepath = param[param.index("=") + 1:] if filepath.startswith('~'): filepath = os.path.expanduser("~") + filepath[1:] else: filepath = os.path.join(CONFIG_DIR, "foobnix.log") LOG.setup("debug", filename=filepath) else: LOG.setup("debug") LOG.print_platform_info() else: LOG.setup("error") from foobnix.gui.foobnix_core import FoobnixCore if "--test" in sys.argv: from test.all import run_all_tests print("""TEST MODE""") result = run_all_tests(ignore="test_core") if not result: raise SystemExit("Test failures are listed above.") exit() init_time = time.time() if "--nt" in sys.argv or os.name == 'nt': GLib.threads_init() #@UndefinedVariable core = FoobnixCore(False) core.run() analytics.begin_session() print("******Foobnix run in", time.time() - init_time, " seconds******") Gtk.main() else: init_time = time.time() from foobnix.gui.controls.dbus_manager import foobnix_dbus_interface iface = foobnix_dbus_interface() if "--debug" in sys.argv or not iface: print("start program") GLib.threads_init() #@UndefinedVariable core = FoobnixCore(True) core.run() settings = Gtk.settings_get_default() settings.props.gtk_button_images = True settings.props.gtk_menu_images = True analytics.begin_session() analytics.begin_session() #core.dbus.parse_arguments(sys.argv) analytics.begin_session() print("******Foobnix run in", time.time() - init_time, " seconds******") if sys.argv: Timer(1, GLib.idle_add, [core.check_for_media, sys.argv]).start() Gtk.main() else: print(iface.parse_arguments(sys.argv))
def foobnix(): if "--debug" in sys.argv: LOG.with_print = True for param in sys.argv: if param.startswith("--log"): if "=" in param: filepath = param[param.index("=")+1 : ] if filepath.startswith('~'): filepath = os.path.expanduser("~") + filepath[1 : ] else: filepath = os.path.join(CONFIG_DIR, "foobnix.log") LOG.setup("debug", filename=filepath) else: LOG.setup("debug") LOG.print_platform_info() else: LOG.setup("error") from foobnix.gui.foobnix_core import FoobnixCore if "--test" in sys.argv: from test.all import run_all_tests print("""TEST MODE""") result = run_all_tests(ignore="test_core") if not result: raise SystemExit("Test failures are listed above.") exit() init_time = time.time() if "--nt" in sys.argv or os.name == 'nt': GLib.threads_init() #@UndefinedVariable core = FoobnixCore(False) core.run() analytics.begin_session() print("******Foobnix run in", time.time() - init_time, " seconds******") Gtk.main() else: init_time = time.time() from foobnix.gui.controls.dbus_manager import foobnix_dbus_interface iface = foobnix_dbus_interface() if "--debug" in sys.argv or not iface: print("start program") GLib.threads_init() #@UndefinedVariable core = FoobnixCore(True) core.run() settings = Gtk.settings_get_default() settings.props.gtk_button_images = True settings.props.gtk_menu_images = True analytics.begin_session() analytics.begin_session() #core.dbus.parse_arguments(sys.argv) analytics.begin_session() print("******Foobnix run in", time.time() - init_time, " seconds******") if sys.argv: Timer(1, GLib.idle_add, [core.check_for_media, sys.argv]).start() Gtk.main() else: print(iface.parse_arguments(sys.argv))