Ejemplo n.º 1
0
def image_grab(bbox=None, childprocess=None, backend=None):
    if platform_is(WINDOWS) or platform_is(MAC):
        return ImageGrab.grab(bbox)
    else:
        # only import pyscreenshot if not on windows
        import pyscreenshot  # noqa
        return pyscreenshot.grab(bbox, childprocess, backend)
Ejemplo n.º 2
0
def all_supported_cursors() -> tuple:
    """
    Get all cursors from the database that are supported in the current operating system
    :return: Tuple of strings
    """
    if platform_is(MAC):
        return BUILTIN_CURSORS + BUILTIN_CURSORS_MAC
    elif platform_is(WINDOWS):
        return BUILTIN_CURSORS + BUILTIN_CURSORS_WINDOWS
Ejemplo n.º 3
0
def resize_cursor() -> tuple:
    r"""
    Returns a tuple of the cursors to be used based on platform
    :return: tuple ("nw_se", "ne_sw") cursors roughly equal to \ and / respectively
    """
    if platform_is(WINDOWS):
        # Windows provides corner resize cursors so use those
        return "size_nw_se", "size_ne_sw"
    if platform_is(LINUX):
        return "bottom_right_corner", "bottom_left_corner"
    # Use circles for other platforms
    return ("circle", ) * 2
Ejemplo n.º 4
0
class Symbol(Key):
    if platform_is(LINUX):
        _keycodes = {
            '\'': 48, '[': 34,
            '-': 20, '\\': 51,
            ',': 59, ']': 35,
            '.': 60, '`': 49,
            '/': 61, '=': 21,
            ';': 47,
        }
    else:
        _keycodes = {
            '\'': 222, '[': 219,
            '-': 189, '\\': 220,
            ',': 188, ']': 221,
            '.': 190, '`': 192,
            '/': 192, '=': 187,
            ';': 186,
        }

    def __init__(self, symbol: str):
        if symbol:
            symbol = symbol[:1]
            if symbol in self._keycodes:
                super().__init__(symbol, self._keycodes[symbol])
            else:
                raise ValueError('symbol {} not found'.format(symbol))
        else:
            raise ValueError('symbol must not be empty')
Ejemplo n.º 5
0
 def __init__(self, alphanumeric: str):
     alphanumeric = alphanumeric.upper()
     if platform_is(LINUX):
         super().__init__(alphanumeric,
                          10 + self.qwerty.index(alphanumeric))
     else:
         super().__init__(alphanumeric, ord(alphanumeric))
Ejemplo n.º 6
0
def is_admin():
    """
    Returns ``True`` if current process is running in elevated mode otherwise
    ``False`` is returned
    """
    if platform_is(WINDOWS):
        return windll.shell32.IsUserAnAdmin()
    return os.getuid() == 0
Ejemplo n.º 7
0
def upgrade(args):
    # elevate process to run in admin mode
    command = f"\"{sys.executable}\" -m pip install --upgrade formation-studio"
    if platform_is(WINDOWS):
        # run command directly in elevated mode
        elevate(command)
    else:
        elevate()
        sys.exit(os.system(command))
Ejemplo n.º 8
0
 def _restore_position(self):
     pos = pref.get("studio::pos")
     if pos.get("state") == 'zoomed':
         if platform_is(WINDOWS):
             self.state('zoomed')
         else:
             self.wm_attributes('-zoomed', True)
         return
     self.state('normal')
     self.geometry('{width}x{height}+{x}+{y}'.format(**pos))
Ejemplo n.º 9
0
 def __init__(self, master, **cnf):
     super().__init__(master, **cnf)
     if master:
         self.style = master.window.style
     self.window = self
     self.pos = (0, 0)
     self.overrideredirect(True)
     self.attributes("-alpha", 0.6)  # Default transparency
     if platform_is(MAC):
         # needed for macos to make window visible
         self.lift()
Ejemplo n.º 10
0
 def show_loading(self):
     if platform_is(LINUX) or self._is_loading:
         # render transitions in linux are very fast and glitch free
         # for other platforms or at least for windows we need to hide the glitching
         return
     self.remove_empty()
     self._empty_frame.place(x=0, y=0, relheight=1, relwidth=1)
     Label(self._empty_frame, text="Loading...",
           **self.style.text_passive).place(x=0,
                                            y=0,
                                            relheight=1,
                                            relwidth=1)
     self._is_loading = True
Ejemplo n.º 11
0
class KeyPad(Key):
    if platform_is(LINUX):
        _offset = 79
        _keys = '789-456+1230.'
    else:
        _offset = 96
        _keys = '0123456789*+ -./'

    def __init__(self, key):
        key = str(key)[:1]
        key = key.replace(' ', '')
        if key != '' and key in self._keys:
            super().__init__(key, self._offset + self._keys.index(key))
        else:
            raise ValueError('Invalid keypad key')
Ejemplo n.º 12
0
 def __init__(self, master, render_routine=None, **kw):
     super().__init__(master)
     self.configure(**self.style.surface)
     # ensure the dialog is above the parent window at all times
     self.transient(master)
     # prevent resizing by default
     self.resizable(False, False)
     self.bar = None
     # Common dialogs
     routines = {
         "OKAY_CANCEL": self._ask_okay_cancel,
         "YES_NO": self._ask_yes_no,
         "RETRY_CANCEL": self._ask_retry_cancel,
         "SHOW_ERROR": self._show_error,
         "SHOW_WARNING": self._show_warning,
         "SHOW_INFO": self._show_info,
         "SHOW_PROGRESS": self._show_progress,
         "BUILDER": self._builder  # Allows building custom dialogs
     }
     if render_routine in routines:
         # Completely custom dialogs
         routines[render_routine](**kw)  # noqa
     elif render_routine is not None:
         render_routine(self)
     self.enable_centering()
     self.value = None
     # quirk that prevents explicit window centering on linux for best results
     add = "+" if platform_is(WINDOWS, MAC) else None
     self.bind('<Visibility>', lambda _: self._get_focus(), add=add)
     if platform_is(WINDOWS):
         # This special case fixes a windows specific issue which blocks
         # application from retuning from a withdrawn state
         self.bind('<FocusOut>', lambda _: self.grab_release())
     self.bind('<FocusIn>', lambda _: self._get_focus())
     self._reaction = -1
     self.bind('<Button>', self._on_event)
Ejemplo n.º 13
0
def _elevate_posix():
    if os.getuid() == 0:
        return

    working_dir = os.getcwd()
    args = [sys.executable] + sys.argv
    commands = []

    def quote_shell(a):
        return " ".join(quote(arg) for arg in a)

    def quote_applescript(string):
        charmap = {
            "\n": "\\n",
            "\r": "\\r",
            "\t": "\\t",
            "\"": "\\\"",
            "\\": "\\\\",
        }
        return '"%s"' % "".join(charmap.get(char, char) for char in string)

    if platform_is(MAC):
        commands.append([
            "osascript", "-e",
            "do shell script %s "
            "with administrator privileges "
            "without altering line endings" %
            quote_applescript(quote_shell(args))
        ])

    elif os.environ.get("DISPLAY"):
        commands.append(["pkexec"] + args)
        commands.append(["gksudo"] + args)
        commands.append(["kdesudo"] + args)

    commands.append(["sudo"] + args)

    for args in commands:
        try:
            os.execlp(args[0], *args)
            # restore working directory which may be changed in certain systems
            if working_dir != os.getcwd():
                os.chdir(working_dir)
            # we are confident process has been elevated
            break
        except OSError as e:
            if e.errno != errno.ENOENT or args[0] == "sudo":
                sys.exit(1)
Ejemplo n.º 14
0
def elevate(args=None):
    """
    Runs the current process with root privileges. In posix systems, the current
    process is swapped while in Windows UAC creates a new process and the return
    code of the spawned process is chained back to the process that initiated
    the elevation. In case of elevation failures the process will terminate
    with a non zero exit code

    :param args: A list of commandline arguments to be used in creating the
        command to be run directly in elevated mode. If not provided current
        process is elevated instead. Only available in windows.
    """
    if platform_is(WINDOWS):
        _elevate_win(args)
    else:
        _elevate_posix()
Ejemplo n.º 15
0
    def popup(cls, event, menu):
        """
        Display context menu based on a right click event

        :param event: tk event object
        :param menu: tk menu to be displayed
        :return: None
        """
        try:
            menu.post(event.x_root, event.y_root)
            if platform_is(LINUX):
                menu.focus_set()
                menu.bind("<FocusOut>", lambda e: menu.unpost())
        except tk.TclError:
            pass
        finally:
            menu.grab_release()
Ejemplo n.º 16
0
    def make_dynamic(cls, templates, parent=None, style: StyleDelegator = None, dynamic=True, **cnf):
        """
        Create a dynamic menu object under a tkinter widget parent

        :param dynamic: suppress dynamic behaviour, useful for toplevel
          menubar. Default is set to true
        :param style: hoverset StyleDelegator object to allow retrieval of
          necessary menu theme styles
        :param templates: a tuple that may contain the following

          1. a tuples of the format
             (type, label, icon, command, additional_config)
             where type is either ``command, cascade, radiobutton, checkbutton``
             and additional_config is a dict containing menu item configuration
          2. a tuple of he format ('separator', additional_config) to
             declare a separator. The additional_config is optional
          3. a :class:`Hoverset.ui.menu.Manipulator` object.

        :param parent: The parent of the menu. You will never need to set
          this attribute directly as it only exists for the purposes of
          recursion
        :param cnf: configuration for created menu
        :return: dynamic menu

        """
        if style and not platform_is(MAC):
            # styles are not applied consistently on macOS so just suppress them
            cnf.update(style.context_menu)
        menu = tk.Menu(parent, **cnf)

        def on_post():
            # clear former contents of menu to allow _make_menu to populate it afresh
            cls.clear_menu(menu)
            cls._make_menu(templates, menu, style)

        if dynamic:
            # set postcommand only if dynamic behaviour is not suppressed
            menu.config(postcommand=on_post)
        else:
            # otherwise just populate menu on creation
            cls._make_menu(templates, menu, style)
        return menu
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
    'gray50',
    'gray25',
    'gray12',
    'hourglass',
    'info',
    'questhead',
    'question',
    'warning',
)

BUILTIN_BITMAPS_MAC = ('document', 'stationery', 'edition', 'application',
                       'accessory', 'forder', 'pfolder', 'trash', 'floppy',
                       'ramdisk', 'cdrom', 'preferences', 'querydoc', 'stop',
                       'note', 'caution')

if platform_is(MAC):
    BUILTIN_BITMAPS = BUILTIN_BITMAPS + BUILTIN_BITMAPS_MAC


def all_cursors() -> tuple:
    """
    Get all cursors in the cursor database regardless of the platform they belong to
    :return: Tuple of strings
    """
    return BUILTIN_CURSORS + BUILTIN_CURSORS_WINDOWS + BUILTIN_CURSORS_MAC


def all_supported_cursors() -> tuple:
    """
    Get all cursors from the database that are supported in the current operating system
    :return: Tuple of strings
Ejemplo n.º 19
0
# ======================================================================= #
# Copyright (C) 2020 Hoverset Group.                                      #
# ======================================================================= #

import threading
import time
import functools
import errno
import os
import sys
import importlib.util
import pathlib
from hoverset.platform import platform_is, WINDOWS, MAC

if platform_is(WINDOWS):
    import ctypes
    from ctypes import POINTER, c_ulong, c_char_p, c_int, c_void_p
    from ctypes.wintypes import HANDLE, BOOL, DWORD, HWND, HINSTANCE, HKEY
    from ctypes import windll
    import subprocess
else:
    try:
        from shlex import quote
    except ImportError:
        from pipes import quote


def timed(func):
    """
    Time the execution of a wrapped function and print the output
Ejemplo n.º 20
0
def function_key(number):
    if number > 12 or number < 1:
        raise ValueError("Function keys should be between 1 and 12 inclusive")
    if platform_is(LINUX):
        return Key('F{}'.format(number), 66 + number)
    return Key('F{}'.format(number), 111 + number)
Ejemplo n.º 21
0
 def platform(cls, label, windows, linux):
     if platform_is(LINUX):
         return Key(label, linux)
     return Key(label, windows)