[
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.zip\n*.gif\npyc.py\n__pycache__/\n.vscode/\nbuild/\ndist/\n*egg-info"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 @mahartstudio\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "#### KivyStudio\n<!-- ![KivyStudio](https://raw.githubusercontent.com/MichaelStott/KivMob/master/demo/assets/kivmob-title.png) -->\n\n[![Build Status](https://travis-ci.com/MichaelStott/KivMob.svg?branch=master)](https://travis-ci.com/MichaelStott/KivMob)\n[![Python](https://img.shields.io/badge/python-2-green.svg)](https://www.python.org/downloads/release/python-270/)\n[![Python](https://img.shields.io/badge/python-3-green.svg)](https://www.python.org/downloads/release/python-270/)\n[![Downloads](https://pepy.tech/badge/kivmob)](https://pepy.tech/project/kivmob)\n[![Maintainability](https://api.codeclimate.com/v1/badges/add8cd9bd9600d898b79/maintainability)](https://codeclimate.com/github/MichaelStott/KivMob/maintainability)\n\nA kivy software development environment targeted towards fast testing and interactive development.\n* #### Features\n  - Emulation can be done in real time\n  - Supports multiple screen views for mobile devices\n  - Supports orientation changes for mobile devices\n  - Supports outer window emulation for desktop intended emulation and for full test on mobile devices\n\n* **Status**: under development...\n* **Release**: 0\n\n\n### Installation\n\nPackage file for various platform will be available on first release\n\n\n### Demo Screenshot\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/mahart-studio/kivystudio/master/showcase/Screenshot(1).png\">\n</p>\n\n### Quickstart\n\n* Create a new folder\n* Open **kivystudio**.\n* On the top menu bar go to **File** option\n* Click **Open Folder**,\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/mahart-studio/kivystudio/master/showcase/Screenshot(2).png\">\n</p>\n\n* Choose your folder\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/mahart-studio/kivystudio/master/showcase/Screenshot(3).png\">\n</p>\n\n* Press <kbd>Ctrl</kbd> + <kbd>N</kbd> : a new file will open-up\n\n\nCopy the following code into the editor provided.\n```python\nfrom kivy.app import App\nfrom kivy.uix.button import Button\n\nclass MyApp(App):\n\tdef build(self):\n\t\treturn Button(text='Welcome to KivyStudio!!')\n\nif __name__ == '__main__':\n\tMyApp().run()\n```\n\n* To save the code, press <kbd>Ctrl</kbd> + <kbd>S</kbd>.\n* Right click on **File** tab\n* Choose **Set for Emulation**, or press <kbd>Ctrl</kbd> + <kbd>E</kbd> to select the file for emulation\n* Then, press <kbd>Ctrl</kbd> + <kbd>R</kbd> to see the output, *OR* you can also set auto-emulation from **File** tab\n* To switch screens, use the <kbd>Ctrl</kbd> + <kbd>Tab</kbd> combination\n* To open and close terminal panel, press <kbd>Ctrl</kbd> + <kbd>`</kbd>\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/mahart-studio/kivystudio/master/showcase/Screenshot(4).png\">\n</p>\n\n### Contributions\nTo contribute to this project\n* Fork the repository\n* Clone it\n``` git clone https://github.com/mahart-studio/kivystudio.git``` \n* Start by solving an issue or fixing a known bug\n* Create a **Pull Request**\n* PR would be merged after review.\n"
  },
  {
    "path": "kivystudio/__init__.py",
    "content": "from kivy.config import Config\nConfig.set('graphics', 'width', '1000')\nConfig.set('graphics', 'height', '730')\nConfig.set('kivy', 'exit_on_escape', '0')\nConfig.set('input', 'mouse', 'mouse,disable_multitouch')\n\n__version__ = '0.2.0.dev'\n\n\ndef get_kivystudio_app():\n     from .main import studio_app\n     return studio_app\n\n"
  },
  {
    "path": "kivystudio/assembler.py",
    "content": "\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.core.window import Window\nfrom kivy.clock import mainthread\n\nfrom kivystudio.widgets.filemanager import filemanager\nfrom kivystudio.parser import emulate_file\n\nfrom kivystudio.components.topmenu import TopMenu\nfrom kivystudio.components.codeplace import code_place, code_container\nfrom kivystudio.components.sibebar import SideBar\nfrom kivystudio.components.terminal import TerminalSpace\nfrom kivystudio.components.emulator_area import get_emulator_area\nfrom kivystudio.settings import settings_obj\n\nclass Assembly(BoxLayout):\n    '''\n    Widget to assemble and structure \n    all widgets\n    '''\n\ndef add_new_tab(paths):\n    for path in paths:\n        code_place.add_code_tab(filename=path)\n\n@mainthread\ndef open_project(paths):\n    if paths:\n        side_bar.ids.explorer_btn='down'\n        side_bar.fileexplorer.load_directory(paths[0])\n\ndef main_key_handler(win, *args):\n    '''' main keyboard and shortcut lisener '''\n    # print(args)\n    if args[0] == 114 and  'ctrl' in args[3]:     # emulate file Ctrl+R\n        emulate_file(emulator_area.emulation_file)\n\n    elif args[0] == 107 and 'ctrl' in args[3]:    # Open folder Ctrl+K\n        filemanager.choose_dir(path='.',on_selection=open_project)\n\n    elif args[0] == 111 and 'ctrl' in args[3]:    # Open file Ctrl+O\n        filemanager.open_file(path='.',on_selection=add_new_tab)\n\n    elif args[0] == 110 and 'ctrl' in args[3]:    # New file Ctrl+N\n        code_place.add_code_tab(tab_type='new_file')\n\n    elif args[0] == 96 and 'ctrl' in args[3]:    # Toggle terminal  Ctrl+`\n        from kivystudio.components.codeplace import terminal\n        terminal.toggle_state()\n\n    elif args[0] == 45 and 'ctrl' in args[3]:    # Zoom out Ctrl -\n        if settings_obj.dpi_scale > 0.8:\n            settings_obj.dpi_scale -= 0.1\n\n    elif args[0] == 61 and 'ctrl' in args[3]:    # Zoom in Ctrl +\n        if settings_obj.dpi_scale < 1.4:\n            settings_obj.dpi_scale += 0.1\n\nWindow.bind(on_key_down=main_key_handler)\n\n\nemulator_area = get_emulator_area()\nside_bar = SideBar()\nAssembler = Assembly()\n\nbox = Assembler.ids.box\nbox.add_widget(side_bar)\nbox.add_widget(code_container)\nbox.add_widget(emulator_area)\n"
  },
  {
    "path": "kivystudio/behaviors/__init__.py",
    "content": "from .highlightbehavior import HighlightBehavior\nfrom .hoverbehavior import HoverBehavior\nfrom .hoverinfobehavior import HoverInfoBehavior"
  },
  {
    "path": "kivystudio/behaviors/highlightbehavior.py",
    "content": "\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.button import Button\nfrom kivy.properties import (BooleanProperty, ObjectProperty, \n                ListProperty, OptionProperty, NumericProperty)\nfrom kivy.base import runTouchApp\nfrom kivy.graphics import InstructionGroup, Color, Rectangle, RoundedRectangle, Callback\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\n\nfrom kivy.core.window import Window, Keyboard\n\n__all__ = ('HighlightBehavior', )\n\nclass HighlightBehavior(object):\n\n    current_highlighted_child = ObjectProperty(None, allownone=True)\n    ''' current highlighted child\n        on ObjectProperty and defualts to None '''\n\n    highlighted_color = ListProperty([.2,.5,1,.5])\n    ''' color that show highlighted widget\n        a ListProperty defualts to [.2,.5,1.5] make sure it transparent\n        because it's drawn over the widget '''\n\n    auto_scroll_to = BooleanProperty(False)\n    ''' automatically scroll to the widget when widget is out of focus \n    note* parent most be a scrollview to enable the property'''\n\n    highlighted_shape = OptionProperty('rectangle', options=['rounded_rectangle','rectangle'])\n\n\n    highlight_orientation = OptionProperty('vertical', options=['vertical',\n                                'horizontal', 'grid'])\n    ''' Orientation in which the highlighting will take place if\n    grid grid len must be set'''\n\n    instruction_canvas = ObjectProperty(InstructionGroup())\n    ''' internal instruction group used to draw the canvas on the\n        currently highlighted child '''\n\n    grid_len = NumericProperty(0)\n\n\n    def __init__(self, **kwargs):\n        super(HighlightBehavior, self).__init__(**kwargs)\n\n\n    def set_first_child(self, dt):\n        if len(self.children) >= 1:\n            self.set_highlighted(self.children[0])\n\n\n    def on_highlighted_color(self, *args):\n        self.redraw_canvas()\n\n    def redraw_canvas(self, *args):\n        if self.current_highlighted_child:\n            self.instruction_canvas.clear()\n            self.instruction_canvas.add(Color(*self.highlighted_color))\n\n            if self.highlighted_shape =='rectangle':\n                self.instruction_canvas.add(Rectangle(pos=self.current_highlighted_child.pos, size=self.current_highlighted_child.size))\n            elif self.highlighted_shape =='rounded_rectangle':\n                self.instruction_canvas.add(RoundedRectangle(pos=self.current_highlighted_child.pos, size=self.current_highlighted_child.size))\n            else:\n                raise Exception('Invalid highlighted shape {}'.format(self.highlighted_shape))\n\n    def on_focus(self, arg, focus):\n        if focus:\n            Window.bind(on_key_down=self.handle_key)\n            if self.current_highlighted_child is None:\n                Clock.schedule_once(self.set_first_child)\n        else:\n            Window.unbind(on_key_down=self.handle_key)\n\n\n    def on_children(self, *args):\n        if len(self.children) == 1:\n            self.set_highlighted(self.children[0])\n\n\n    def set_highlighted(self, child):\n        if not (child == self.current_highlighted_child):\n            if self.current_highlighted_child: # remove the canvas from the previosly highlighted child\n                self.current_highlighted_child.canvas.after.remove(self.instruction_canvas)\n\n            child.canvas.after.add(self.instruction_canvas)\n            self.current_highlighted_child = child\n            with child.canvas:\n                Callback(self.redraw_canvas)\n\n    def handle_key(self, keyboard, key, codepoint, text, modifier, *args):\n\n        key_str = Keyboard.keycode_to_string(Window._system_keyboard, key)\n        modifier.sort()\n        if modifier:\n            value = '_'.join(modifier) + '_' + key_str\n        else:\n            value = key_str\n        \n        callable_method = 'do_' + value\n\n        try:\n            func = getattr(self, callable_method)\n        except AttributeError:\n            pass\n        else:\n            func()\n\n    def _moving(self):\n        if self.auto_scroll_to:\n            self.parent.scroll_to(self.current_highlighted_child)\n\n\n    def do_up(self):\n        if self.highlight_orientation == 'vertical':\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index >= len(children)-1):\n                self.set_highlighted(children[(index)+1])\n                self._moving()\n        \n        elif self.highlight_orientation == 'horizontal':\n            pass\n        \n        elif self.highlight_orientation == 'grid':\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index+self.grid_len >= len(children)):\n                self.set_highlighted(children[(index)+self.grid_len])\n                self._moving()\n\n        else:\n            raise Exception('invalid highlight_orientation %s'%self.highlight_orientation)\n\n    def do_down(self):\n        if self.highlight_orientation == 'vertical':\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index < 1):\n                self.set_highlighted(children[(index)-1])\n                self._moving()\n\n        elif self.highlight_orientation == 'horizontal':\n            pass\n        \n        elif self.highlight_orientation == 'grid':\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index+self.grid_len < 1):\n                self.set_highlighted(children[(index)-self.grid_len])\n                self._moving()\n        else:\n            raise Exception('invalid highlight_orientation %s'%self.highlight_orientation)\n\n    def do_right(self):\n        if self.highlight_orientation == 'vertical':\n            pass\n\n        elif self.highlight_orientation == 'horizontal' or self.highlight_orientation == 'grid':\n\n            self._moving()\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index < 1):\n                self.set_highlighted(children[(index)-1])\n                self._moving()\n        else:\n            raise Exception('invalid highlight_orientation %s'%self.highlight_orientation)\n\n    def do_left(self):\n\n        if self.highlight_orientation == 'vertical':\n            pass\n\n        elif self.highlight_orientation == 'horizontal' or self.highlight_orientation == 'grid':\n\n            children = self.children[:]\n            index = children.index(self.current_highlighted_child)\n            if not(index >= len(children)-1):\n                self.set_highlighted(children[(index)+1])\n                self._moving()\n\n        else:\n            raise Exception('invalid highlight_orientation %s'%self.highlight_orientation)\n\n    def do_enter(self):\n        pass\n\n    def do_ctrl_up(self):\n        pass\n    def do_shift_up(self):\n        pass\n    def do_shift_down(self):\n        pass\n    def do_shift_left(self):\n        pass\n    def do_shift_up(self):\n        pass\n\n'''\n        if value :\n            self.map.get(value)[0]()\n            return True\n'''\nclass What(HighlightBehavior, FocusBehavior, GridLayout):\n    pass\n\nif __name__ == \"__main__\":\n    what = What(cols=3, grid_len=3, highlight_orientation='grid')\n\n    for btn in range(12):\n        what.add_widget(Button(text=str(btn)))\n\n    runTouchApp(what)\n"
  },
  {
    "path": "kivystudio/behaviors/hoverbehavior.py",
    "content": "\n''' A quick implementation of mouse hovering \n    just fires one event called 'on_hover'\n    when the mouse hover on a widget the inhenrites from this\n    behavior\n    Ex:\n    class HoverButton(HoverBehavior, Button):\n\n        def on_hover(self, *args):\n            if self.hover:\n                self.text = 'Yeah!!'\n            else:\n                self.text =''\n'''\n\nfrom kivy.core.window import Window\nfrom kivy.properties import ObjectProperty\n\nclass HoverBehavior(object):\n\n    hover = ObjectProperty(False)\n    ''' indicate is mouse if over the widget\n    defaults to False'''\n\n\n    def on_parent(self, *args):\n\n        if self.parent:\n            Window.bind(mouse_pos=self.on_mouse_move)\n        else:\n            Window.unbind(mouse_pos=self.on_mouse_move)\n\n\n    def on_mouse_move(self, win, pos):\n\n        if self.collide_point(*self.to_widget(*pos)):\n            self.hover = True\n        else:\n            self.hover = False\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp as app\n    from kivy.uix.button import Button\n    from kivy.uix.boxlayout import BoxLayout\n\n    class HoverButton(HoverBehavior, Button):\n\n        def on_hover(self, *args):\n            if self.is_hover:\n                self.text = 'Yeah!!'\n            else:\n                self.text =''\n    box=BoxLayout()\n    box.add_widget(HoverButton())\n    box.add_widget(Button(text='Hello'))\n    app(box)"
  },
  {
    "path": "kivystudio/behaviors/hoverinfobehavior.py",
    "content": "'''\nMixin behavior widget that inherits from kivystudio.behavior.HoverBehavior\nused on a widget, to show extra infomation on what the widgets does\nby hovering on it\n\nSimple usages:\n\nclass MyButton(HoverInfoBehavior, Button):\n\n    def __init__(self, **kwargs):\n        super(MyButton, self).__init__(**kwargs)\n        self.info_text = 'Click me'\n\n        # or if the info text might change you, could bind it to an atrr\n        self.mytext = 'somthing'\n        self.info_text_attr = 'mytext'\n\n\n\n'''\nfrom kivy.clock import Clock\nfrom kivy.properties import StringProperty\nfrom kivystudio.tools import infolabel\n\nfrom .hoverbehavior import HoverBehavior\n\nclass HoverInfoBehavior(HoverBehavior):\n\n    info_text = StringProperty('')\n    \n    info_text_attr = StringProperty('')\n\n    def on_parent(self, *a):\n        if self.parent is None:\n            infolabel.remove_info_on_mouse()\n        return super(HoverInfoBehavior, self).on_parent(*a)\n\n    def on_hover(self, *a):\n        if self.hover:\n            Clock.schedule_once(self.show_label_info,1)\n        else:\n            Clock.unschedule(self.show_label_info)\n            infolabel.remove_info_on_mouse()\n\n    def show_label_info(self,dt):\n        info_text = self.info_text\n        if self.info_text_attr:\n            info_text = getattr(self, self.info_text_attr)\n\n        # if info_text:\n        infolabel.show_info_on_mouse(info_text)\n"
  },
  {
    "path": "kivystudio/components/__init__.py",
    "content": ""
  },
  {
    "path": "kivystudio/components/codeplace/__init__.py",
    "content": "\nfrom .codeplace import CodePlace\n\nfrom kivystudio.widgets.splitter import StudioSplitter\nfrom kivystudio.components.terminal import TerminalSpace\n\nclass CodeContainer(StudioSplitter):\n    pass\ncode_container = CodeContainer()\ncontainer = code_container.ids.container\n\n\ncode_place = CodePlace()\ncode_place.add_code_tab(tab_type='welcome')  # add welcoming tab\n\nterminal = TerminalSpace()\n\ncontainer.add_widget(code_place)\ncontainer.add_widget(terminal)\n"
  },
  {
    "path": "kivystudio/components/codeplace/code.kv",
    "content": "\n<CodeContainer>:\n    sizable_from: 'right'\n    max_size: root.parent.width-self.parent.children[2].width if self.parent and len(self.parent.children)>2 else 0\n    min_size: '700dp'\n    FloatLayout:\n        id: container\n\n\n<CodePlace>:\n    orientation: 'vertical'\n    tab_manager: tab_manager\n    pos_hint: {'center_y': .5, 'center_x': .5}\n    CodeTabsContainer:\n        size_hint_y: None\n        height: '36dp'\n        canvas.before:\n            Color:\n                rgba: (0.12, 0.12, 0.12, 1)\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\n        # canvas to show shadow division\n        canvas.after:\n            Color:\n                rgba: (0, 0, 0, .4)\n            Line:\n                points: [self.x,self.y, self.right,self.y]\n            Color:\n                rgba: (0, 0, 0, .3)\n            Line:\n                points: [self.x,self.y-1, self.x-1,self.y-1]\n            Color:\n                rgba: (0, 0, 0, .2)\n            Line:\n                points: [self.x,self.y-2, self.x,self.y-2]\n            Color:\n                rgba: (0, 0, 0, .1)\n            Line:\n                points: [self.x,self.y-3, self.x,self.y-3]\n                width: 2\n\n        GridLayout:\n            rows: 1\n            id: tab_manager\n            size_hint_x: None\n            width: self.minimum_width\n\n\n\n<TabToggleButton>:\n    size_hint_x: None\n    width: self.minimum_width\n    padding: '6dp'\n    spacing: '3dp'\n    canvas_color: (0.12, 0.12, 0.12, 1)\n    allow_no_selection: False\n    group: '__tabed_btn__'\n    on_state:\n        if self.state == 'down': self.canvas_color= (.2,.2,.2,1)\n        else: self.canvas_color= (0.12, 0.12, 0.12, 1)\n    canvas.before:\n        Color:\n            rgba: self.canvas_color\n        Rectangle:\n            size: self.size\n            pos: self.pos\n    IconLabel:\n        size_hint_x: None\n        width: '10dp'\n        text: '%s'%(icon('fa-file-code-o'))\n        color: .2,.5,1,.8\n    Label:\n        font_size: '13.5dp'\n        text: root.text\n        text_size: None, None\n        padding: '3dp', 0\n        shorten: True\n        shorten_from: 'right'\n        size_hint_x: None\n        width: max(self.texture_size[0]+10, 110)\n    TabPannelIndicator:\n        id: indicator\n        on_release: root.close_tab()\n\n<TabPannelIndicator>:\n    size_hint_x: None\n    width: '12dp'\n\n\n<CodeTabDropDown>:\n    MenuButton:\n        on_release: root.close_tab()\n        MenuLabel:\n            text: 'Close'\n        MenuLabel:\n            text: 'Ctrl+W'\n            type: 'shortcut'\n    ToggleMenuButton:\n        text: 'Set file for emulation'\n        on_state:\n            if self.state=='down': root.set_for_emulation()\n            else: root.set_for_emulation(remove=True)\n    MenuButton:\n        MenuLabel:\n            text: 'Copy path'\n        MenuLabel:\n            text: 'Alt-Ctrl+C'\n            type: 'shortcut'\n    MenuButton:\n        MenuLabel:\n            text: 'Copy relative path'\n        MenuLabel:\n            text: 'Alt-Ctrl+Shift+C'\n            type: 'shortcut'\n        MenuLabel:\n            text: 'Split Up'\n    MenuButton:\n        MenuLabel:\n            text: 'Split Down'\n    MenuButton:\n        MenuLabel:\n            text: 'Split Left'\n    MenuButton:\n        MenuLabel:\n            text: 'Split Right'\n\n\n<FileErrorTab>:\n    text: \"This file is not displayed because it is either binary or uses an unsupported text encoding.\"\n    canvas.before:\n        Color:\n            rgba: (0.12, 0.12, 0.12, 1)\n        Rectangle:\n            size: self.size\n            pos: self.pos\n"
  },
  {
    "path": "kivystudio/components/codeplace/codeplace.py",
    "content": "\nfrom kivy.uix.screenmanager import ScreenManager, Screen, NoTransition, ScreenManagerException\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.behaviors import ToggleButtonBehavior, FocusBehavior\nfrom kivy.uix.boxlayout import BoxLayout\n\nfrom kivy import properties as prop\nfrom kivy.clock import Clock\nfrom kivy.core.window import Window\nfrom kivy.lang import Builder\nfrom kivy.extras.highlight import KivyLexer\n\n\nfrom kivystudio.widgets.codeinput import FullCodeInput\nfrom kivystudio.widgets.filemanager import filemanager\nfrom kivystudio.components.emulator_area import get_emulator_area\nfrom kivystudio.tools import quicktools, load_kv\nfrom kivystudio.tools.logger import Logger\n\nfrom .tabs.welcometab import WelcomeTab\nfrom .tabs.codetab import TabToggleButton\nfrom .tabs.errortab import FileErrorTab\n\nfrom pygments import lexers\nimport os\n\n# file_formats = ['.py', '.kv', '.spec', '.txt']\n\ndef get_tab_from_group(filename):\n    all_tabs = ToggleButtonBehavior.get_widgets('__tabed_btn__')\n    if not all_tabs: return\n    for tab in all_tabs:\n        if tab.filename == filename:\n            return tab\n\n\ndef get_lexer_for_file(filename):\n    ext = os.path.splitext(filename)[1]\n    try:\n        lexer = lexers.get_lexer_for_filename(filename)\n    except lexers.ClassNotFound:\n        if ext == '.kv':\n            lexer = KivyLexer()\n        else:\n            lexer = lexers.TextLexer()\n    # print('found {} for {}'.format(lexer, filename))\n    return lexer\n\n\nclass CodeScreenManager(ScreenManager):\n\n    def __init__(self, **kwargs):\n        super(CodeScreenManager, self).__init__(**kwargs)\n        self.transition = NoTransition()\n\n    def add_widget(self, widget, name, tab_type='code'):\n        if tab_type=='code':\n            Clock.schedule_once(lambda dt: self.open_file(widget),1)     # open the file\n\n        try:\n            widget.code_input.lexer = get_lexer_for_file(widget.filename)\n        except:\n            pass\n\n        screen = CodeScreen(name=name)\n        screen.add_widget(widget,tab_type=tab_type)\n        super(CodeScreenManager, self).add_widget(screen)\n\n    def open_file(self, code_input):\n        if os.path.exists(code_input.filename):\n            with open(code_input.filename, 'r') as f:\n                code_input.code_input.focus = False\n                code_input.code_input.text = f.read()\n\n    def save_current_tab(self):\n        self.get_screen(self.current).save_file()\n\n    def save_all_tabs(self):\n        for name in self.screen_names:\n            self.get_screen(name).save_file()\n\n    def get_children_with_filename(self, filename):\n        try:\n            child = list(filter(lambda child: child.name==filename, self.screens))[0]\n            return child\n        except IndexError:\n            raise Exception('code manager as no child with such filename {}'.format(filename))\n\n\nclass CodeScreen(Screen):\n    \n    code_field = prop.ObjectProperty(None)\n\n    def on_pre_enter(self):\n        if self.code_field:\n            self.code_field.code_input.focus = True\n            Window.bind(on_key_down=self.keyboard_down)\n\n        tab = get_tab_from_group(self.name)\n        if tab:\n            Clock.schedule_once(lambda dt: setattr(tab, 'state', 'down'))\n\n\n    def on_pre_leave(self):\n        if self.code_field:\n            Window.unbind(on_key_down=self.keyboard_down)\n\n    def on_enter(self):\n        if self.code_field:\n            self.code_field.code_input.focus = True\n\n    def save_file(self, new_file=False, auto_save=False):\n        if self.code_field.tab_type=='code':\n            if not self.code_field.saved or new_file:\n                with open(self.name, 'w') as fn:\n                    fn.write(self.code_field.code_input.text)\n    \n            self.code_field.saved = True\n        if new_file:\n            self.code_field.code_input.lexer = get_lexer_for_file(self.name)\n                \n        if self.code_field.tab_type=='new_file' and not auto_save:\n            filemanager.save_file(path='/root', on_selection=self.save_new_file)\n\n\n    def save_new_file(self, paths):\n        if paths:\n            path=paths[0]\n            self.code_field.tab.filename=path\n            self.code_field.tab.text = os.path.split(path)[1]\n            self.code_field.tab_type='code'\n            self.name=path\n            self.save_file(new_file=True)\n\n    def add_widget(self, widget, tab_type='code'):\n        super(CodeScreen, self).add_widget(widget)\n        if tab_type=='code' or tab_type=='new_file':\n            self.code_field = widget\n            self.code_field.tab_type=tab_type\n            self.code_field.bind(saved=self.saving_file)\n\n    def saving_file(self, ins, saved):\n        tab = get_tab_from_group(self.name)\n        tab.saved = saved       \n\n    def keyboard_down(self, window, *args):\n        # print(args)\n        if args[0] == 115 and 'ctrl' in args[3]:  # save file Ctrl+S\n            self.save_file()\n            return False\n\n        if args[0] == 101 and 'ctrl' in args[3]:  # select file for emulation file Ctrl+E\n            if os.path.exists(self.name):\n                get_emulator_area().emulation_file=self.name\n                Logger.info(\"Emulator: File '{}' selected\".format(self.name))\n            else:\n                Logger.info(\"Emulator: invalid file selected\".format(self.name))\n\n\nclass CodePlace(BoxLayout):\n    \n    code_manager = prop.ObjectProperty(None)\n\n    tab_manager = prop.ObjectProperty(None)\n\n    new_empty_tab = prop.NumericProperty(0)\n    '''count of empty tabs that has been opened\n    '''\n\n    def __init__(self, **kwargs):\n        super(CodePlace, self).__init__(**kwargs)\n        self.code_manager = CodeScreenManager()\n        self.add_widget(self.code_manager)\n\n        Window.bind(on_key_down=self.keyboard_down)\n        Window.bind(on_dropfile=self.file_droped)\n\n    def file_droped(self, window, filename, *args):\n        if self.collide_point(*window.mouse_pos):\n            print('File droped on code input {} '.format(filename))\n            if filename:\n                self.add_code_tab(filename=filename.decode('utf-8'))\n\n    def add_widget(self, widget, tab_type=''):\n        if len(self.children) > 1:\n            if tab_type =='code' or tab_type =='new_file' or tab_type=='unsupported':\n                tab = TabToggleButton(text=os.path.split(widget.filename)[1],\n                                    filename=widget.filename)\n                widget.tab = tab\n                widget.tab_type = tab_type\n                self.code_manager.add_widget(widget, widget.filename, tab_type=tab_type)\n\n            elif tab_type=='welcome':\n                self.code_manager.add_widget(widget, 'kivystudiowelcome', tab_type=tab_type)\n                tab = TabToggleButton(text='Welcome',filename='kivystudiowelcome')\n\n            tab.bind(state=self.change_screen)\n            self.tab_manager.add_widget(tab)\n            Clock.schedule_once(lambda dt: setattr(tab, 'state', 'down'))\n\n        else:\n            super(CodePlace, self).add_widget(widget)\n\n    def change_screen(self, tab, state):\n        if state == 'down':\n            self.code_manager.current = tab.filename\n            checked_list = list(filter(lambda child: child != tab, ToggleButtonBehavior.get_widgets(tab.group)))\n            for child in checked_list:\n                if child != tab:\n                    child.state='normal'\n\n    def keyboard_down(self, window, *args):\n\n        if args[0] == 9 and args[3] == ['ctrl']:   # switching screen with ctrl tab\n            self.code_manager.current = self.code_manager.next()\n            return True\n\n        if args[0] == 119 and args[3] == ['ctrl']:   # close tab\n            try:\n                name = self.code_manager.get_screen(self.code_manager.current).name\n                tab = get_tab_from_group(name)\n                self.remove_code_tab(tab)\n            except ScreenManagerException:\n                pass\n\n    def remove_code_tab(self, tab):\n        self.tab_manager.remove_widget(tab)\n        codeinput=self.code_manager.get_children_with_filename(tab.filename)\n        self.code_manager.remove_widget(codeinput)\n\n        if tab.filename.startswith('Untitled-') and not os.path.exists(tab.filename):\n            self.new_empty_tab -= 1\n\n    def add_code_tab(self, filename='', tab_type='code'):\n        if filename and os.path.exists(filename):\n            if not quicktools.is_binary(filename):\n                widget=FullCodeInput(filename=filename)\n            else:\n                widget=FileErrorTab(filename=filename)\n                tab_type='unsupported'\n            try:\n                self.code_manager.get_screen(filename)\n                self.code_manager.current=filename\n            except ScreenManagerException:   # then it is not added\n                self.add_widget(widget, tab_type=tab_type)\n\n        elif tab_type=='new_file':   # a new tab\n            self.new_empty_tab += 1\n            while True:\n                try:\n                    self.code_manager.get_screen(filename)\n                    self.code_manager.current=filename\n                except ScreenManagerException:   # then it is not added\n                    filename = 'Untitled-{}'.format(self.new_empty_tab)\n                    self.add_widget(FullCodeInput(filename=filename), tab_type=tab_type)\n                    return\n                self.new_empty_tab += 1\n\n        elif tab_type == 'welcome':\n            try:\n                self.code_manager.get_screen('kivystudiowelcome')\n                self.code_manager.current=filename\n            except ScreenManagerException:   # then it is not added\n                self.add_widget(WelcomeTab(), tab_type=tab_type)\n\n\n\nclass CodeTabsContainer(ScrollView):\n    '''horizontal scrollview where the small tab \n        buttons lay'''\n\n    def on_touch_down(self, touch):\n        FocusBehavior.ignored_touch.append(touch)\n        return super(CodeTabsContainer, self).on_touch_down(touch)\n\nload_kv(__file__, 'code.kv')\n"
  },
  {
    "path": "kivystudio/components/codeplace/tabs/__init__.py",
    "content": ""
  },
  {
    "path": "kivystudio/components/codeplace/tabs/codetab.py",
    "content": "from kivy.uix.behaviors import ToggleButtonBehavior,ButtonBehavior\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.uix.image import Image\nfrom kivy.core.window import Window\nfrom kivy.clock import Clock, mainthread\nfrom kivy.properties import (StringProperty,\n                            ObjectProperty,\n                            BooleanProperty)\nfrom kivystudio.behaviors import HoverInfoBehavior\nfrom kivystudio.behaviors import HighlightBehavior\nfrom kivystudio.widgets.iconlabel import IconLabelButton\nfrom kivystudio.widgets.rightclick_drop import RightClickDrop\nfrom kivystudio.tools import set_auto_mouse_position\nfrom kivystudio.tools.iconfonts import icon\nfrom kivystudio.components.emulator_area import get_emulator_area\n\nrightclick_dropdown = [None]\n\nclass TabToggleButton(HoverInfoBehavior, ToggleButtonBehavior, BoxLayout):\n\n    filename = StringProperty('')\n\n    saved = BooleanProperty(True)\n\n    text = StringProperty('')\n\n    def __init__(self, **kwargs):\n        super(TabToggleButton, self).__init__(**kwargs)\n        # set the info attr because filename could change\n        self.info_text_attr = 'filename'\n\n        if rightclick_dropdown[0] is None:\n            self.rightclick_dropdown = CodeTabDropDown()\n            rightclick_dropdown[0] = self.rightclick_dropdown\n        else:\n            self.rightclick_dropdown=rightclick_dropdown[0]\n\n    def on_saved(self, *args):\n        if self.saved:\n            self.ids.indicator.text =''\n        elif not self.saved:\n            self.ids.indicator.text = '%s' % (icon('fa-circle'))\n            self.ids.indicator.font_size = '12dp'\n\n    def on_state(self, *args):\n        if self.state=='down' and not self.saved:\n            self.ids.indicator.text = '%s' % (icon('fa-circle'))\n            self.ids.indicator.font_size = '12dp'\n        elif self.state=='down' and self.saved:\n            self.ids.indicator.text = '%s' % (icon('fa-close'))\n            self.ids.indicator.font_size = '16dp'\n        elif self.state=='normal':\n            self.ids.indicator.source =''\n \n\n    def on_touch_down(self,touch):\n        if self.collide_point(*touch.pos):\n            if touch.button == 'right':\n                self.rightclick_dropdown.open(self)\n                FocusBehavior.ignored_touch.append(touch)\n                return True\n\n        if touch.button == 'left':\n            return super(TabToggleButton, self).on_touch_down(touch)\n\n    def close_tab(self):\n        from kivystudio.assembler import code_place\n        code_place.remove_code_tab(self)\n\n\n    def __str__(self):\n        return self.filename\n\n\nclass CodeTabDropDown(RightClickDrop):\n\n    def __init__(self, **kwargs):\n        super(CodeTabDropDown, self).__init__(**kwargs)\n        self.tab = None\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):  # touch should not unfocus input\n            FocusBehavior.ignored_touch.append(touch)\n        return super(CodeTabDropDown,self).on_touch_down(touch)\n\n    def open(self, tab):\n        self.tab=tab\n        super(CodeTabDropDown, self).open()\n\n    def set_for_emulation(self, remove=False):\n        if not remove:\n            get_emulator_area().emulation_file=self.tab.filename\n        else:\n            get_emulator_area().emulation_file=''\n\n    def close_tab(self):\n        self.dismiss()\n        self.tab.close_tab()\n\n\nclass TabPannelIndicator(IconLabelButton):\n        \n    def on_hover(self, *a):\n        if self.hover:\n            self.text = '%s' % (icon('fa-close'))\n            self.font_size = '16dp'\n        if not self.hover and not self.parent.saved:\n            self.text = '%s' % (icon('fa-circle'))\n            self.font_size = '12dp'\n        if not self.hover and self.parent.saved and self.parent.state=='normal':\n            self.text = ''\n        if not self.hover and self.parent.saved and self.parent.state=='down':\n            self.text = '%s' % (icon('fa-close'))\n            self.font_size = '16dp'\n\n        return super(TabPannelIndicator, self).on_hover(*a)\n"
  },
  {
    "path": "kivystudio/components/codeplace/tabs/errortab.py",
    "content": "from kivy.uix.label import Label\nfrom kivy.properties import StringProperty\n\nclass FileErrorTab(Label):\n    filename = StringProperty('')\n"
  },
  {
    "path": "kivystudio/components/codeplace/tabs/welcome.kv",
    "content": "#: import icon kivystudio.tools.iconfonts.icon\n#: import quicktools kivystudio.tools.quicktools\n            # IconLabel:\n            #     text: '%s'%(icon('fa-bug'))\n            # IconLabel:\n            #     text: '%s'%(icon('fa-code-fork'))\n\n<WelcomeTab>:\n    BoxLayout:\n        orientation: 'vertical'\n        BoxLayout:\n            size_hint_y: None\n            height:'80dp'\n            orientation: 'vertical'\n            Label:\n                haling:'center'\n                text: 'Kivy Studio' \n                bold: True\n                font_size: '40dp'\n        BoxLayout:\n            size_hint_y: None\n            height:'150dp'\n            GridLayout:\n                cols: 4\n                IconLabel:\n                    text: '%s'%(icon('fa-android'))\n                    color: .2,1,.2\n                    font_size: '64dp'\n                IconLabel:\n                    text: '%s'%(icon('fa-apple'))\n                    color: .9,.9,.95\n                    font_size: '64dp'\n                IconLabel:\n                    text: '%s'%(icon('fa-linux'))\n                    font_size: '64dp'\n                IconLabel:\n                    text: '%s'%(icon('fa-windows'))\n                    font_size: '64dp'\n        BoxLayout:\n            padding: '30dp'\n            GridLayout:\n                cols: 1\n                Label:\n                    size_hint_y: None\n                    height: '32dp'\n                    text: 'Start'\n                    bold: True\n                    font_size: '18dp'\n                BoxLayout:\n                    orientation: 'vertical'\n                    size_hint_y: None\n                    height: self.minimum_height\n                    Label:\n                        on_ref_press: quicktools.open_new_file()\n                        text: '[u][color=2255FF][ref=\"d\"]Open new file[/ref][/color][/u] - [ctrl N]'\n                        markup: True\n                        size_hint_y: None\n                        height: '32dp'\n                    Label:\n                        on_ref_press: quicktools.open_file()\n                        text: '[u][color=2255FF][ref=\"d\"]Open file[/ref][/color][/u] - [ctrl O]'\n                        markup: True\n                        size_hint_y: None\n                        height: '32dp'\n                    Label:\n                        on_ref_press: quicktools.open_folder()\n                        text: '[u][color=2255FF][ref=\"d\"]Open folder[/ref][/color][/u] - [ctrl K]'\n                        markup: True\n                        size_hint_y: None\n                        height: '32dp'\n            GridLayout:\n                cols: 1\n                Label:\n                    size_hint_y: None\n                    height: '32dp'\n                    text: 'Recent'\n                    bold: True\n                    font_size: '18dp'\n                BoxLayout:\n                    orientation: 'vertical'\n"
  },
  {
    "path": "kivystudio/components/codeplace/tabs/welcometab.py",
    "content": "from kivystudio.widgets.iconlabel import IconLabel\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.lang import Builder\n\nfrom os.path import join, dirname\nBuilder.load_file(join(dirname(__file__), 'welcome.kv'))\n\nclass WelcomeTab(BoxLayout):\n    pass\n"
  },
  {
    "path": "kivystudio/components/emulator_area/__init__.py",
    "content": "from kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.behaviors import ToggleButtonBehavior\nfrom kivy.uix.screenmanager import ScreenManager, Screen\n\nfrom kivy.lang import Builder\nfrom kivy.properties import ObjectProperty, StringProperty\nfrom kivy.clock import Clock\n\nfrom kivystudio.behaviors import HoverBehavior\nfrom kivystudio.components import screens\nfrom kivystudio.widgets.iconlabel import IconLabelButton\n\nfrom .screen_drop import ScreenDrop\n\nimport os\n__all__ = ('get_emulator',)\nfilepath = os.path.dirname(__file__)\nBuilder.load_file(os.path.join(filepath,'emulator.kv'))\n\nclass EmulatorArea(BoxLayout):\n\n    screen_display = ObjectProperty(None)\n\n    emulation_file = StringProperty('')\n\n    def __init__(self, **kwargs):\n        super(EmulatorArea, self).__init__(**kwargs)\n        self.screen_manager = EmulatorScreens()\n        self.add_widget(self.screen_manager)\n        self.screen_display = ScreenDisplay()\n        self.screen_manager.add_widget(self.screen_display)\n    \n    def add_widget(self, widget):\n        super(EmulatorArea, self).add_widget(widget)\n\n    def toggle_orientation(self):\n        if self.screen_display.screen.orientation =='portrait': \n            self.screen_display.screen.orientation ='landscape'\n        else:\n            self.screen_display.screen.orientation ='portrait'\n\n    def open_screen_drop(self,widget):\n        ScreenDrop().open(widget, self.screen_display)\n\n\nclass ScreenTopMenu(BoxLayout):\n    \n    screen = ObjectProperty(None)\n\n\n\nclass EmulatorScreens(ScreenManager):\n    \n    def add_widget(self, widget):\n        screen = Screen()\n        screen.add_widget(widget)\n        super(EmulatorScreens, self).add_widget(screen)\n\n\n\nclass ScreenDisplay(HoverBehavior, FloatLayout):\n    \n    screen = ObjectProperty(None)\n\n    topmenu = ObjectProperty(None)\n\n    screen_name = StringProperty('')\n\n    def __init__(self, **kwargs):\n        super(ScreenDisplay, self).__init__(**kwargs)\n        self.scaler = ScreenTopMenu()\n        self.screen_name = 'AndroidPhoneScreen'\n\n    def on_hover(self, *args):\n        pass\n\n    def on_screen_name(self, *a):\n        self.former_screen = self.screen\n        self.screen = getattr(screens, self.screen_name)()\n\n    def on_screen(self, obj, screen):\n        if self.former_screen:\n            root = self.former_screen.root_widget\n            if root:\n                self.former_screen.clear_widgets()\n                screen.add_widget(root)\n\n        # now add new screen \n        self.clear_widgets()\n        self.add_widget(screen)\n        self.bind(center=self.screen.setter('center'))\n        self.scaler.screen = screen\n\n\ninstance=[]\ndef get_emulator_area():\n    if instance:\n        return instance[0]\n    else:\n        emulator_area = EmulatorArea(size_hint_x=.45)\n        instance.append(emulator_area)\n        return emulator_area\n"
  },
  {
    "path": "kivystudio/components/emulator_area/emulator.kv",
    "content": "#: import split os.path.split\n\n<EmulatorArea>:\n    orientation: 'vertical'\n    GridLayout:\n        canvas.before:\n            Color:\n                rgba: (0.12, 0.12, 0.12, 1)\n            Rectangle:\n                size: self.size\n                pos: self.pos\n        rows: 1\n        id: tab_manager\n        size_hint_y: None\n        height: '36dp'\n\n        Label:\n            size_hint_x: None\n            width: min(self.texture_size[0]+dp(7), dp(108))\n            text: split(root.emulation_file)[1]\n            shorten: True\n            shorten_from: 'right'\n        IconLabelButton:\n            info_text: 'Zooom Out'\n            color: .8,.8,.8,1\n            size_hint_x: None\n            width: '36dp'\n            text: icon('fa-search-minus')\n            on_release:\n                if not root.screen_display.screen.scale < 0.10: root.screen_display.screen.scale -= 0.05\n        IconLabelButton:\n            info_text: 'Zooom In'\n            color: .8,.8,.8,1\n            text: icon('fa-search-plus')\n            size_hint_x: None\n            width: '36dp'\n            icon_source: 'images/scale2.png'\n            on_release:\n                if not root.screen_display.screen.scale > 1.0: root.screen_display.screen.scale += 0.05\n        IconToggleLabel:\n            info_text: 'Change Orientation'\n            color: .8,.8,.8,1\n            text: icon('fa-mobile', 24)\n            size_hint_x: None\n            width: '36dp'\n            angle:0\n            on_state:\n                root.toggle_orientation();\n                if self.state=='down': self.angle=90\n                else: self.angle=0\n            canvas:\n                Clear\n                PushMatrix\n                Rotate:\n                    angle: self.angle\n                    origin: self.center_x , self.center_y\n                Rectangle:\n                    size: self.texture_size\n                    pos: self.center_x - 12, self.center_y - 12\n                    texture: self.texture\n                PopMatrix\n\n        IconLabelButton:\n            info_text: 'Change Screen'\n            on_release: root.open_screen_drop(self)\n            size_hint_x: None\n            width: '36dp'\n            text: icon('fa-ellipsis-h')\n\n<ScreenDisplay>:\n    name: 'Emulator'\n    canvas.before:\n        Color:\n            rgba: .5,.5,.5,1\n        Rectangle:\n            size: self.size\n            pos: self.pos\n\n<ScreenDrop>:\n    auto_width: False\n    width: '260dp'\n    MenuButton:\n        on_release: root.screen_display.screen_name=self.children[0].text\n        MenuLabel:\n            text: 'IphoneScreen'\n    MenuButton:\n        on_release: root.screen_display.screen_name=self.children[0].text\n        MenuLabel:\n            text: 'IpadScreen'\n    MenuButton:\n        on_release: root.screen_display.screen_name=self.children[0].text\n        MenuLabel:\n            text: 'AndriodTabScreen'\n    MenuButton:\n        on_release: root.screen_display.screen_name=self.children[0].text\n        MenuLabel:\n            text: 'AndroidPhoneScreen'\n"
  },
  {
    "path": "kivystudio/components/emulator_area/screen_drop.py",
    "content": "from kivystudio.widgets.dropdown import DropDownBase\n\nclass ScreenDrop(DropDownBase):\n\n    def open(self, widget, screen_display):\n        self.screen_display = screen_display\n        super(ScreenDrop, self).open(widget)"
  },
  {
    "path": "kivystudio/components/screens/__init__.py",
    "content": "import os\n\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.screenmanager import ScreenManager, Screen\nfrom kivy.properties import ObjectProperty, NumericProperty, StringProperty, ListProperty\nfrom kivy.uix.scatter import Scatter\nfrom kivy.lang import Builder \nfrom kivy.metrics import dp\n\n# module resources\nfrom kivy.resources import resource_add_path\nresource_add_path(os.path.dirname(os.path.realpath(__file__)))\n\n__all__ = ('IphoneScreen', 'IpadScreen', 'AndroidPhoneScreen', 'AndriodTabScreen', )\n\nclass ScreenScatter(Scatter):\n    ''' base widget for screens'''\n\n    root_widget = ObjectProperty(None, allow_none=True)\n\n    angle = NumericProperty(0)\n\n    orientation = StringProperty('portrait')\n\t\n    container = ObjectProperty(None)\n\n    border_size =ListProperty([0,0])\n\n    border_pos =ListProperty([0,0])\n\n    source = StringProperty('')\n\n    def __init__(self, **k):\n        super(ScreenScatter, self).__init__(**k)\n        self.bind(pos=self.set_border)\n        self.bind(size=self.set_border)\n\n    def add_widget(self, widget):\n        if len(self.children) > 0:\n            self.root_widget = widget\n            if widget.parent:\n                widget.parent.remove_widget(widget)\n            self.container.add_widget(widget)\n        else:\n            super(ScreenScatter, self).add_widget(widget)\n\n    def clear_widgets(self):\n        self.container.clear_widgets()\n\n    def on_orientation(self, *a):\n        if self.orientation == 'portrait':\n            self.angle = 0\n            self.container.size = (self.height,self.width)\n        elif self.orientation == 'landscape':\n            self.angle = -90\n            self.container.size = (self.height,self.width)\n\n        self.set_border(from_orientation=True)\n\n    def set_border(self, *a, **k):\n        if self.orientation == 'portrait':\n            self.border_pos = self.get_pos \n            self.border_size = self.get_size\n        elif self.orientation == 'landscape':\n            self.border_pos = self.get_pos\n\n        try:\n            from_orientation = k.pop('from_orientation')\n        except KeyError:\n            from_orientation = False\n\n        if from_orientation:\n            self.center = self.parent.center\n\n    def on_parent(self,*a):\n        if self.parent:\n            self.set_border()\n            self.center = self.parent.center\n\n    @property\n    def get_pos(self):\n        pass\n\n    @property\n    def get_size(self):\n        pass\n\n\nclass IphoneScreen(ScreenScatter):\n    @property\n    def get_pos(self):\n        pos = (-25, -dp(133))\n        if self.orientation == 'landscape':\n            return (-self.container.height+pos[0], pos[1])\n        return pos\n\n    @property\n    def get_size(self):\n\n        return (self.width + dp(50), self.height + dp(270))\n\nclass IpadScreen(ScreenScatter):\n    @property\n    def get_pos(self):\n        pos = (-dp(95), -dp(77))\n        if self.orientation == 'landscape':\n            return (-self.container.height+pos[0], pos[1])\n        return pos\n\n    @property\n    def get_size(self):\n        return (self.width + dp(190), self.height + dp(154))\n\nclass AndriodTabScreen(ScreenScatter):\n    @property\n    def get_pos(self):\n        if self.orientation == 'landscape':\n            return (-self.container.height-35, -dp(51))\n        return (-dp(35), -dp(51))\n\n    @property\n    def get_size(self):\n        return (self.width + dp(70), self.height + dp(102))\n\nclass AndroidPhoneScreen(ScreenScatter):\n    @property\n    def get_pos(self):\n        if self.orientation == 'landscape':\n            return (-self.container.height-16.5, -dp(85.5))\n        return (-dp(16.5), -dp(85.5))\n\n    @property\n    def get_size(self):\n        return (self.container.width + dp(32), self.container.height + dp(152))\n\n\nclass ScreenContainer(FloatLayout):\n\n    # overide\n    def add_widget(self,widget):\n        if len(self.children) > 1:\n            screen = self.ids.inner_container.get_screen('container')\n            screen.add_widget(widget)\n            # self.ids.inner_container.add_widget(screen)\n        else:\n            super(ScreenContainer,self).add_widget(widget)\n\n    # overide\n    def clear_widgets(self):\n        screen = self.ids.inner_container.get_screen('container')\n        screen.clear_widgets()\n\nBuilder.load_file('screen.kv')\n\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp as app\n    app(build)\n"
  },
  {
    "path": "kivystudio/components/screens/screen.kv",
    "content": "#: import Window kivy.core.window.Window\n\n# 398 804\n<AndroidPhoneScreen>:\n    size: container.size\n    container: container\n    scale: 0.75\n    ScreenContainer:\n        id: container\n        size: '320dp', '610dp'\n        source: 'images/android_lolipop1.png'\n\n# 380 743\n<IphoneScreen>:\n    size: container.size\n    container: container\n    scale: 0.75\n    ScreenContainer:\n        id: container\n        size: ('300dp', '500dp')\n        source: 'images/iphone.png'\n\n#1271 992\n<IpadScreen>:\n    size: container.size\n    container: container\n    scale: 0.75\n    ScreenContainer:\n        id: container\n        size: ('800dp', '512dp')\n        source: 'images/ipad.png'\n\n# 953 612\n<AndriodTabScreen>:\n    size: container.size\n    container: container\n    ScreenContainer:\n        id: container\n        size: ('500dp', '280dp')\n        source: 'images/android_tab.png'\n        my_parent: self.parent\n\n<ScreenScatter>:\n    do_rotation: False\n    do_scale: False\n    do_translation: False\n    # scale_min: 1\n    size_hint: None, None\n    auto_bring_to_front: False\n\n<ScreenContainer>:\n    source: ''\n    FloatLayout:\n        source: root.source\n        size_hint: None, None\n        pos_hint: {'center_y': .5, 'center_x': .5}\n        canvas.before:\n            PushMatrix:\n            Rotate:\n                angle: root.parent.angle if self.parent else 0\n                origin: (0,0,1)\n            BorderImage:\n                source: root.source\n                size: root.parent.border_size if self.parent else (0,0)\n                pos: root.parent.border_pos if self.parent else (0,0)\n            PopMatrix:\n    ScreenManager:\n        id: inner_container\n        Screen:\n            name: 'container'\n"
  },
  {
    "path": "kivystudio/components/screens/screen_test.py",
    "content": "from kivy.lang import Builder\nfrom kivy.base import runTouchApp as app\nfrom __init__ import *\n\napp(\nBuilder.load_string('''\n\nBoxLayout:\n    Carousel:\n        canvas.before:\n            Color:\n                rgba: 1,1,1,1\n            Rectangle:\n                size: self.size\n                pos: self.pos\n        FloatLayout:\n            IphoneScreen:\n                on_scale: self.center=root.center\n                center: root.center\n                id: screen\n                Button:\n                    text: 'Hello'\n                    font_size: '17dp'\n\n            BoxLayout:\n                pos_hint: {'y': .01, 'center_x': .5}\n                size_hint: None,None\n                size: '120dp', '60dp'\n                Button:\n                    text: '-'\n                    bold: True\n                    on_release:\n                        if not(screen.scale < -100.0) : screen.scale -= 0.05\n                Button:\n                    text: '+'\n                    bold: True\n                    on_release:\n                        if not(screen.scale > 4.0): screen.scale += 0.05\n\n# Carousel:\n#     AndroidPhoneScreen:\n#         Button:\n#             text: 'Hello'\n#     IphoneScreen:\n#         Button:\n#             text: 'Hello'\n#     IpadScreen:\n#         Button:\n#             text: 'Hello'\n#     AndriodTabScreen:\n#         Button:\n#             text: 'Hello'\n\n''')\n)\n"
  },
  {
    "path": "kivystudio/components/sibebar/__init__.py",
    "content": "from kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.behaviors import ToggleButtonBehavior\nfrom kivy.uix.screenmanager import ScreenManager\n\nfrom kivy.lang import Builder\n\nfrom kivystudio.behaviors import HoverInfoBehavior\n\nfrom .fileexplorer import FileExplorer\nfrom .gitmanager import GitManager\nfrom .generalsearch import GeneralSearch\nfrom kivy import properties as prop\n\nimport os\nfilepath = os.path.dirname(__file__)\nBuilder.load_file(os.path.join(filepath,'sidebar.kv'))\n\n\n__all__ = ('SideBar',)\n\nclass SideBar(BoxLayout):\n\n    def __init__(self, **k):\n        super(SideBar, self).__init__(**k)\n        self.fileexplorer = FileExplorer()\n        self.gitmanager = GitManager()\n        self.generalsearch = GeneralSearch()\n\n    def toggle_bar(self, tab):\n        if tab.state=='down':\n            if len(self.children) > 1:\n                self.remove_widget(self.children[0])\n                self.width = '46dp'\n\n            tab_bar = getattr(self, tab.tab_type)\n            self.width += tab_bar.width\n            self.add_widget(tab_bar)\n        else:\n            self.width = '46dp'\n            if len(self.children) > 1:\n                    self.remove_widget(self.children[0])\n    \n\nclass SideButter(HoverInfoBehavior, ToggleButtonBehavior, Label):\n    '''\n    buttons on the sidebar\n    '''\n    def on_hover(self, *a):\n        if self.hover:\n            self.color = (1,1,1,1)\n        elif not self.hover and self.state == 'normal':\n            self.color = (.5,.5,.5,1)\n\n        return super(SideButter, self).on_hover(*a)\n\nclass SideToggleBar(ScreenManager):\n    '''ScreenManager of the sidebar\n    '''\n\n"
  },
  {
    "path": "kivystudio/components/sibebar/fileexplorer/__init__.py",
    "content": "from kivy.uix.treeview import TreeViewLabel, TreeView\nfrom kivy.uix.screenmanager import Screen\nfrom kivy.uix.button import Button\nfrom kivy.lang import Builder\nfrom kivy.properties import ObjectProperty\nfrom .filewidgets import TreeViewFile\nimport os\nfrom os.path import join, split, dirname\n\nclass FileView(TreeView):\n    def on_touch_down(self, touch):\n        node = self.get_node_at_pos(touch.pos)\n        if not node:\n            return\n        if node.disabled:\n            return\n        # toggle node or selection ?\n        self.toggle_node(node)\n        self.select_node(node)\n        # node.dispatch('on_touch_down', touch)\n        return True\n\n\n\nclass FileExplorer(Screen):\n    tree_view = ObjectProperty(None)\n\n    def __init__(self, **k):\n        super(FileExplorer, self).__init__(**k)\n        # self.load_directory('widgets')  #test\n\n    def load_directory(self, directory):\n        '''\n        load a directory all it files and subdirectory\n        on the the tree view '''\n        tree_view = self.tree_view\n        for node in tree_view.iterate_all_nodes(node=None):\n            tree_view.remove_node(node)\n        dir_nodes = {}\n        for dirpath, dirnames, filenames in os.walk(directory):\n            try:\n                top= dir_nodes[dirname(dirpath)]\n            except KeyError:\n                top=None\n\n            parent = tree_view.add_node(TreeViewLabel(text=split(dirpath)[1]), top)\n            dir_nodes[dirpath] = parent\n\n            for file in filenames:\n                tree_view.add_node(TreeViewFile(text=file,path=join(dirpath,file)),\n                        parent)\n\n\nBuilder.load_string('''\n<TreeViewLabel>:\n    width: self.texture_size[0]\n    shorten_from: 'right'\n    shorten: True\n    height: dp(24)\n    text_size: self.width, None\n\n<FileExplorer>:\n    tree_view: tree_view\n    canvas.before:\n        Color:\n            rgba: .1,.1,.1,1\n        Rectangle:\n            size: self.size\n    size_hint_x: None\n    width: '160dp'\n    GridLayout:\n        cols: 1\n        Label:\n            text: 'Explorer!'\n            font_size: '16dp'\n            size_hint_y: None\n            height: '32dp'\n        ScrollView:\n            id: tree_scroll\n            bar_width: 10\n            scroll_type: ['bars', 'content']\n            FileView:\n                id: tree_view\n                indent_level: '12dp'\n                indent_start: '16dp'\n                size_hint: 1, None\n                height: max(tree_scroll.height, self.minimum_height)\n\n''')\n"
  },
  {
    "path": "kivystudio/components/sibebar/fileexplorer/filewidgets.py",
    "content": "from kivy.uix.treeview import TreeViewNode, TreeViewLabel\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.lang import Builder\nfrom kivy.properties import ListProperty, StringProperty, BooleanProperty\n\nfrom kivystudio.tools.iconfonts import icon\nfrom kivystudio.tools import quicktools\nfrom kivystudio.behaviors import HoverBehavior\n\nimport os\n\n# class TreeViewFile(HoverBehavior, TreeViewNode, BoxLayout):\nclass TreeViewFile(TreeViewLabel):\n    hover_color = ListProperty([.15,.15,.15,0])\n    ' default color when the mouse hovers over the widget'\n\n    path = StringProperty('')\n    ' path to the file or directory '\n\n    display_name = StringProperty('')\n    ' name displayed for the file or directory '\n\n    display_icon = StringProperty('')\n    ''' icon displayed on the right side of the file\n    or directory '''\n\n    def on_hover(self, *a):\n        if self.hover:\n            self.hover_color = (.14,.14,.14,.8)\n        else:\n            self.hover_color = (.15,.15,.15,0)\n\n    def on_is_selected(self, *args):\n        if self.is_selected:\n            quicktools.open_file(self.path)\n\n    def on_path(self, *a):\n        if os.path.isdir(self.path):\n            self.display_icon = icon('fa-caret-right',16)\n        elif os.path.isfile(self.path):\n            self.display_icon = icon('fa-file-code-o', 16)\n\n        self.display_name = os.path.split(self.path)[1]\n\n\n\nBuilder.load_string('''\n#: import icon kivystudio.tools.iconfonts.icon\n<TreeViewFile>:\n    size_hint_y: None\n    height: '24dp'\n    canvas.before:\n        Color:\n            rgba: self.hover_color\n        Rectangle:\n            size: self.size\n            pos: self.pos\n\n<TreeViewFile1>:\n    size_hint_y: None\n    height: '24dp'\n    canvas.before:\n        Clear\n        Color:\n            rgba: self.hover_color\n        Rectangle:\n            size: self.size\n            pos: self.pos\n    canvas.after:\n        Clear\n    IconLabel:\n        size_hint_x: None\n        width: '24dp'\n        text: root.display_icon\n        color: .2,.5,1,1\n    Label:\n        text: root.display_name\n''')\n"
  },
  {
    "path": "kivystudio/components/sibebar/generalsearch.py",
    "content": "from kivy.uix.screenmanager import Screen\nfrom kivy.lang import Builder\n\nBuilder.load_string('''\n<GeneralSearch>:\n    size_hint_x: None\n    width: '160dp'\n    canvas.before:\n        Color:\n            rgba: .1,.1,.1,1\n        Rectangle:\n            size: self.size\n    Label:\n        text: 'Search....'\n''')\n\nclass GeneralSearch(Screen):\n    pass\n\n"
  },
  {
    "path": "kivystudio/components/sibebar/gitmanager.py",
    "content": "from kivy.uix.screenmanager import Screen\nfrom kivy.lang import Builder\n\nBuilder.load_string('''\n<GitManager>:\n    size_hint_x: None\n    width: '160dp'\n    canvas.before:\n        Color:\n            rgba: .1,.1,.1,1\n        Rectangle:\n            size: self.size\n    Label:\n        text: 'Git'\n''')\n\n\nclass GitManager(Screen):\n    pass\n"
  },
  {
    "path": "kivystudio/components/sibebar/sidebar.kv",
    "content": "#: import icon kivystudio.tools.iconfonts.icon\n\n<SideBar>:\n    size_hint_x:  None\n    width: '46dp'\n    FloatLayout:\n        size_hint_x:  None\n        width: '46dp'\n        canvas.before:\n            Color:\n                rgba: .12,.12,.12,1\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\n        GridLayout:\n            cols: 1\n            size_hint_y: None\n            height: self.minimum_height\n            pos_hint: {'center_x': .5, 'center_y': .5}\n            SideButter:\n                info_text: 'Search (Ctrl+Shift+F)'\n                text: '%s'%(icon('fa-search'))\n                tab_type: 'generalsearch'\n                on_state: root.toggle_bar(self)\n            SideButter:\n                id: explorer_btn\n                info_text: 'Explorer (Ctrl+Shift+E)'\n                text: '%s'%(icon('fa-folder-open'))\n                tab_type: 'fileexplorer'\n                on_state: root.toggle_bar(self)\n            SideButter:\n                info_text: 'Settings (Ctrl+Shift+S)'\n                text: '%s'%(icon('fa-cogs'))\n                tab_type: 'gitmanager'\n                on_state: root.toggle_bar(self)\n            SideButter:\n                info_text: 'Source Control (Ctrl+Shift+G)'\n                text: '%s'%(icon('fa-github'))\n                tab_type: 'gitmanager'\n                on_state: root.toggle_bar(self)\n\n\n<SideButter>:\n    size_hint: 1, None\n    height: '46dp'\n    font_size: '32dp'\n    markup: True\n    color: .5,.5,.5,1\n    on_state:\n        if self.state=='down': self.color=(1,1,1,1)\n        else: self.color=(.5,.5,.5,1)\n    group: 'side_butters'\n"
  },
  {
    "path": "kivystudio/components/terminal/__init__.py",
    "content": "from kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.behaviors import ToggleButtonBehavior\nfrom kivy.uix.label import Label\nfrom kivy.uix.screenmanager import Screen\nfrom kivy import properties as prop\nfrom kivy.clock import Clock\n\nfrom kivy.lang import Builder\nfrom kivystudio.libs.resizablebehavior import ResizableBehavior\n\nfrom .logger_space import ErrorLogger\n\nclass TerminalSpace(ResizableBehavior, BoxLayout):\n\n    manager = prop.ObjectProperty(None)\n    ''' Instance of screen manager used '''\n\n    tab_container = prop.ObjectProperty(None)\n    ''' instance of a gridlayout where tha tab lays'''\n\n    state = prop.OptionProperty('open', options=['open', 'close'])\n\n    def __init__(self, **k):\n        super(TerminalSpace, self).__init__(**k)\n        self.logger = ErrorLogger()\n        self.add_widget(self.logger, title='Logs')\n\n    def add_widget(self, widget, title=''):\n        if len(self.children) > 1:\n            tab = TerminalTab()\n            tab.text=title\n            tab.name=title\n            tab.bind(state=self.tab_state)\n            self.tab_container.add_widget(tab)\n            Clock.schedule_once(lambda dt: setattr(tab, 'state', 'down'))\n            screen = Screen(name=title)\n            screen.add_widget(widget)\n            self.manager.add_widget(screen)\n        else:\n            super(TerminalSpace, self).add_widget(widget)\n\n    def tab_state(self, tab, state):\n        panel = self.manager.get_screen(tab.name).children[0]\n        if state=='down':\n            self.manager.current = tab.name\n            for item in panel.top_pannel_items:\n                self.top_pannel.add_widget(item, 2)\n        else:\n            for item in panel.top_pannel_items:\n                if item in self.top_pannel.children:\n                    self.top_pannel.remove_widget(item)\n\n \n    def on_state(self, *args):\n        if self.state=='open':\n            self.height = self.norm_height\n        else:\n            self.height='48dp'\n\n    def toggle_state(self):\n        if self.state=='open':\n            self.state='close'\n        else:\n            self.state='open'\n\nclass TerminalTab(ToggleButtonBehavior, Label):\n\n    def on_state(self, *a):\n        if self.state=='down':\n            self.text = \"[u]\" + self.text + \"[/u]\"\n            self.color = (.9,.9,.9,1)\n        else:\n            self.text = self.text.replace('[u]','').replace('[/u]','')\n            self.color = (.5,.5,.5,1)\n\n\nBuilder.load_string('''\n<TerminalSpace>:\n    resizable_up: True\n    tab_container: tab_container\n    top_pannel: top_pannel\n    manager: manager\n    orientation: 'vertical'\n    pos_hint: {'y': 0, 'center_x': .5}\n    size_hint_y: None\n    max_norm_height: dp(380)\n    norm_height: dp(200)\n    height: self.norm_height\n    on_height:\n        if self.height > self.max_norm_height: height_tog.state='down'\n    canvas.before:\n        Color:\n            rgba: .12,.12,.12,1\n        Rectangle:\n            size: self.size\n            pos: self.pos\n        Color:\n            rgba: 1,1,1,1\n        Line:\n            points: [self.x,self.top,self.right,self.top]\n            width: dp(1.4)\n    BoxLayout:\n        size_hint_y: None\n        height: '48dp'\n        GridLayout:\n            id: tab_container\n            rows: 1\n        BoxLayout:\n            id: top_pannel\n            size_hint_x: None\n            width: self.minimum_width\n            IconToggleLabel:\n                id: height_tog\n                icon_normal: 'fa-angle-up'\n                icon_down: 'fa-angle-down'\n                icon: self.icon_normal\n                icon_size: 30\n                size_hint_x: None\n                width: '32dp'\n                on_state:\n                    root.state='open'\n                    if self.state=='down': root.height=root.max_norm_height\n                    else: root.height=root.norm_height\n            IconLabelButton:\n                icon: 'fa-close'\n                size_hint_x: None\n                width: '32dp'\n                on_release: root.state='close'\n    ScreenManager:\n        id: manager\n\n<TerminalTab>:\n    allow_no_selection: True\n    group: '__terminal_tab__'\n    size_hint_x: None\n    width: '94dp'\n    markup: True\n\n<TopPanelButton@IconLabelButton>:\n    icon: 'fa-close'\n    size_hint_x: None\n    width: '32dp'\n\n''')"
  },
  {
    "path": "kivystudio/components/terminal/command_terminal.py",
    "content": ""
  },
  {
    "path": "kivystudio/components/terminal/logger_space.py",
    "content": "from kivy.uix.boxlayout import BoxLayout\nfrom kivy import properties as prop\nfrom kivy.lang import Builder\nfrom kivy.factory import Factory\n\nMAX_LOG_LINES = 260\n\n\nclass ErrorLogger(BoxLayout):\n    \n    text = prop.StringProperty()\n    ''' property where the logs are stored '''\n\n    top_pannel_items = prop.ListProperty()\n\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n        clearbtn = Factory.TopPanelButton(icon='fa-trash-o')\n        clearbtn.bind(on_release=self.clear_logs)\n        self.top_pannel_items.append(clearbtn)\n\n\n    def log(self, msg):\n        lines = self.text.splitlines()\n        if len(lines) > MAX_LOG_LINES:    # clean previous logs\n            self.text = '\\n'.join(lines[int(MAX_LOG_LINES/2):])\n        self.text += msg+'\\n'\n        self.ids.scroll.scroll_y = 0\n\n    def clear_logs(self, *args):\n        self.text = ''\n\n\nclass InternalErrorLogger(BoxLayout):\n    \n    text = prop.StringProperty('Hello '*39)\n\nBuilder.load_string('''\n<ErrorLogger>:\n    ScrollView:\n        id: scroll\n\t\tbar_width: '10dp'\n        scroll_type: ['bars', 'content']\n        Label:\n            text: root.text\n            text_size: self.width, None\n            size_hint_y: None\n            height: self.texture_size[1]\n            valign: 'top'\n            halign: 'left'\n            color: .8,.8,.8,1\n            markup: True\n            font_size: '14sp'\n\n\n''')"
  },
  {
    "path": "kivystudio/components/topmenu/__init__.py",
    "content": "\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.dropdown import DropDown\nfrom kivy.uix.button import Button\nfrom kivy.uix.behaviors import ToggleButtonBehavior, ButtonBehavior\n\nfrom kivy.clock import Clock\nfrom kivy.lang import Builder\nfrom kivy.properties import ListProperty, BooleanProperty, ObjectProperty\n\nfrom kivystudio.behaviors import HoverBehavior\nfrom . import dropmenu\n\n__all__ = ('TopMenu',)\n\n\nclass TopMenu(GridLayout):\n    \n    drop_on_hover = BooleanProperty(False)\n    menu = ObjectProperty()\n\n    def __init__(self, **kwargs):\n        super(TopMenu, self).__init__(**kwargs)\n\n    # def drop(self, btn, hover):\n    #     if hover and not self.dropdown.parent:\n    #         self.dropdown.drop_list=btn.drop_list\n    #         self.dropdown.open(btn)\n    #     else:\n    #         Clock.schedule_once(self.decide_drop)\n    \n    # def decide_drop(self, dt):\n    #     if not self.dropdown.hover:\n    #         self.dropdown.dismiss()\n\n        \n    def open_menu(self, widget):\n        if self.menu:   \n            x = self.menu.dismiss()\n        menu_name = self.remove_underscore(widget.text) + 'TopMenu'\n        setattr(self, 'menu_name', getattr(dropmenu, menu_name)())\n        self.menu = getattr(self, 'menu_name')\n        self.menu.open(self.children[widget.index])\n    \n    def remove_underscore(self, text):\n        return  text.replace('[u]','').replace('[/u]','')\n\n    def add_underscore(self,text):\n        return \"[u]\" + text + \"[/u]\"\n\n\nclass TopMenuItem(HoverBehavior, ButtonBehavior, Label):\n\n    def on_hover(self, *args):\n        widget, hover = args\n        if hover:\n            widget.text = self.parent.add_underscore(widget.text)\n            widget.color = (.1,.5,.1,1)\n        else:\n            widget.text = self.parent.remove_underscore(widget.text)\n            widget.color = (0,0,0,1)\n    \n\nBuilder.load_string('''\n\n<TopMenu>:\n    size_hint_y: None\n    height: '24dp'\n    rows: 1\n    canvas.before:\n        Color:\n            rgba: .85,.85,.85,1\n        Rectangle:\n            size: self.size\n            pos: self.pos\n    TopMenuItem:\n        text: 'File'\n        index:4\n        on_release: root.open_menu(self)\n\n    TopMenuItem:\n        text: 'Edit'\n        index:3\n        on_release: root.open_menu(self)\n\n    TopMenuItem:\n        text: 'View'\n        index:2\n        on_release: root.open_menu(self)\n    \n    TopMenuItem:\n        text: 'Selection'\n        index:1\n        on_release: root.open_menu(self)\n    \n    TopMenuItem:\n        text: 'Help'\n        index:0\n        on_release: root.open_menu(self)\n\n<TopMenuItem>:\n    size_hint_x: None\n    width: '60dp'\n    markup: True\n    color: (0,0,0,1)\n\n\n\n''')\n"
  },
  {
    "path": "kivystudio/components/topmenu/dropmenu.kv",
    "content": "#: import icon kivystudio.tools.iconfonts.icon\n\n<FileTopMenu>:\n    auto_width: False\n    width: '300dp'\n    MenuButton:\n        on_release: root.new_file()\n        MenuLabel:\n            text: 'New File'\n        MenuLabel:\n            halign:'right'\n            text: 'Ctrl+N'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.open_file()\n        MenuLabel:\n            text: 'Open File'\n        MenuLabel:\n            halign:'right'\n            text: 'Ctrl+O'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.open_folder()\n        MenuLabel:\n            text: 'Open Folder'\n        MenuLabel:\n            halign:'right'\n            text: '[Ctrl+K Ctrl+O]'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.save()\n        MenuLabel:\n            text: 'Save'\n        MenuLabel:\n            halign:'right'\n            text: 'Ctrl+S'\n            type: 'shortcut'\n    ToggleMenuButton:\n        text: 'Auto Save'\n        state: 'down' if settings.auto_save else 'normal'\n        on_state:\n            if self.state=='down': settings.auto_save=1\n            else: settings.auto_save=0\n    ToggleMenuButton:\n        text: 'Auto emulation'\n        state: 'down' if settings.auto_emulate else 'normal'\n        on_state:\n            if self.state=='down': settings.auto_emulate=1\n            else: settings.auto_emulate=0\n    MenuButton:\n        on_release: root.save_as()\n        MenuLabel:\n            text: 'Save as'\n        MenuLabel:\n            halign:'right'\n            text: 'Ctrl+Shift+S'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.save_all()\n        MenuLabel:\n            text: 'Save All'\n    MenuButton:\n        on_release: root.exit_window()\n        MenuLabel:\n            text: 'Exit'\n        MenuLabel:\n            halign:'right'\n            text: 'Ctrl+Q'\n            type: 'shortcut'\n\n<EditTopMenu>:\n    auto_width: False\n    width: '300dp'\n    MenuButton:\n        on_release: \n        MenuLabel:\n            text: 'Edit File'\n        MenuLabel:\n            halign:'right'\n            text: ''\n            type: 'shortcut'\n\n<ViewTopMenu>:\n    auto_width: False\n    width: '300dp'\n    MenuButton:\n        on_release: \n        MenuLabel:\n            text: 'View File'\n        MenuLabel:\n            halign:'right'\n            text: ''\n            type: 'shortcut'\n\n<SelectionTopMenu>:\n    auto_width: False\n    width: '300dp'\n    MenuButton:\n        on_release: \n        MenuLabel:\n            text: 'Selection File'\n        MenuLabel:\n            halign:'right'\n            text: ''\n            type: 'shortcut'\n\n<HelpTopMenu>:\n    auto_width: False\n    width: '300dp'\n    MenuButton:\n        on_release: print('help was clicked!')\n        MenuLabel:\n            text: 'Help'\n\n<MenuLabel@Label>:\n    text_size: self.size\n    halign: 'left'\n    valign: 'middle'\n    padding: '20dp', 0\n    type: 'text'\n    color: ((0/255,0/255,0/255,.9) if self.type=='text' else (160/255,160/255,160/255,.9)) if self.parent else (236/255,243.255,1,.5)\n\n<MenuButton>:\n    size_hint_y: None\n    height: '30dp'\n    canvas_color: 1,1,1,1\n    text_colors: ((.1,.1,.1,1), (.5,.5,.5,1))   \n    on_hover:\n        if self.hover: self.canvas_color = .2,.5,1,1; self.text_colors=((1,1,1,1),(1,1,1,1))\n        else: self.canvas_color = 1,1,1,1; self.text_colors=((0,0,0,1), (.5,.5,.5,1))\n    canvas.before:\n        Color:\n            rgba: self.canvas_color\n        Rectangle:\n            size: self.size\n            pos: self.pos\n\n<ToggleMenuButton>:\n    size_hint_y: None\n    height: '30dp'\n    canvas_color: 1,1,1,1\n    text_colors: (.1,.1,.1,1)\n    text: ''\n    on_hover: \n        if self.hover: self.canvas_color = .2,.5,1,1;self.state;\n        else: self.canvas_color = (1,1,1,1)\n    on_state: tick.state=self.state\n    canvas.before:\n        Color:\n            rgba: self.canvas_color\n        Rectangle:\n            size: self.size\n            pos: self.pos\n\n    MenuLabel:\n        text: root.text\n    IconToggleLabel:\n        size_hint_x: None\n        width: '48dp'\n        id: tick\n        color: .2,.2,.2,1\n        on_state:\n            if self.state=='normal': self.text='';print(self.state)\n            else: self.text = icon('fa-check', 16)\n        on_parent: self.state='down'"
  },
  {
    "path": "kivystudio/components/topmenu/dropmenu.py",
    "content": "from kivy.uix.behaviors import ButtonBehavior, ToggleButtonBehavior\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.lang import Builder\n\nfrom kivystudio.behaviors import HoverBehavior\nfrom kivystudio.widgets.dropdown import DropDownBase\nfrom kivystudio import tools\n\ntools.load_kv(__file__,'dropmenu.kv')\n\n\nclass MenuButton(HoverBehavior, ButtonBehavior, BoxLayout):\n    def on_hover(self, widget, hover):\n        if hover: \n            self.canvas_color = .2,.5,1,1\n            if len(self.children) > 1:\n                    self.children[0].color = (1,1,1,1)\n        else: \n            self.canvas_color = (1,1,1,1)\n            if len(self.children) > 1: \n                    self.children[0].color = (.5,.5,.5,1); \n        \n        \n\nclass ToggleMenuButton(HoverBehavior, ToggleButtonBehavior, BoxLayout):\n    pass\n\nclass FileTopMenu(DropDownBase):\n    \n    def __init__(self, **k):\n        super(FileTopMenu, self).__init__(**k)\n\n    def new_file(self):\n        tools.quicktools.open_new_file()\n\n    def open_file(self):\n        tools.quicktools.open_file()\n\n    def open_folder(self):\n        tools.quicktools.open_file()\n    \n    def open_recent(self):\n        tools.quicktools.open_recent()\n\n    def save(self):\n        tools.quicktools.save()\n\n    def save_all(self):\n        tools.quicktools.save_all()\n\n    def save_as(self):\n        tools.quicktools.save_as()\n\n    def exit_window(self):\n        tools.quicktools.exit_window()\n        \n    \nclass EditTopMenu(DropDownBase):\n    def __init__(self, **k):\n        super(EditTopMenu, self).__init__(**k)\n\nclass ViewTopMenu(DropDownBase):\n    def __init__(self, **k):\n        super(ViewTopMenu, self).__init__(**k)\n\nclass SelectionTopMenu(DropDownBase):\n    def __init__(self, **k):\n        super(SelectionTopMenu, self).__init__(**k)\n\nclass HelpTopMenu(DropDownBase):\n    def __init__(self, **k):\n        super(HelpTopMenu, self).__init__(**k)\n        \n"
  },
  {
    "path": "kivystudio/libs/__init__.py",
    "content": ""
  },
  {
    "path": "kivystudio/libs/resizablebehavior/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 Kivy Garden\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "kivystudio/libs/resizablebehavior/README.md",
    "content": "# Resizable Behavior\n\nA behavior for kivy widgets that allows them to be resized by touching/clickin on a corner and dragging.    \n     \n     \n[Youtube demostration video](https://www.youtube.com/watch?v=8VqLV4McmK0)     \n      \n      \nBelow is also a **screenshot of the included resizable widget application**.     \n     \n     \n![ScreenShot](https://raw.github.com/kivy-garden/garden.resizable_behavior/master/doc/screenshot.png)\n\n## Usage    \n\nImport and inherit like any other kivy behavior\n```python\nfrom kivy.garden.resizablebehavior import ResizableBehavior\nfrom kivy.uix.button import Button\n\nclass ResizableButton(ResizableBehavior, Button):\n    pass\n```\n\nEnable / disable resizing of a specific side in kwargs or after\n```python\nres_button = ResizableButton(\n    resizable_left = False,\n    resizable_right = True,\n    resizable_up = False,\n    resizable_down = True)\n\nres_button.resizable_left = False\nres_button.resizable_right = True\nres_button.resizable_up = False\nres_button.resizable_down = True\n```\n\nLock / unlock resizing\n```python\nres_button.resize_lock = True\n```\n    \nAdjust the size of resizable border in kwargs or after\n```python\nres_button = ResizableButton(resizable_border=8999)\n\nres_button.resizable_border = 100\n```\n\nOffset the resizable_border (by default it is inside the widget) in kwargs or after     \n```python\nres_button = ResizableButton(resizable_border_offset=100)\n\n#A value of resizable_border * 0.5 will center it on the edge of the ResizableButton\nres_button.resizable_border_offset = res_button.resizable_border * 0.5\n```\n\nSet min and max sizes in kwargs or after     \n```python\nres_button = ResizableButton(\n    min_resizable_width = 100,\n    min_resizable_height = 101,\n    max_resizable_width = 102,\n    max_resizable_height = 103)\n    \nres_button.min_resizable_width = 100\nres_button.min_resizable_height = 101\nres_button.max_resizable_width = 102\nres_button.max_resizable_height = 103\n```\n\nEnable / disable the cursor\n```python\nres_button.set_cursor_mode(0) # Disabled\nres_button.set_cursor_mode(1) # Enabled\n# SDL2 system cursors might be added to kivy core in future\n```\n\nChange the size of the cursor\n```python\nres_button.set_cursor_size(width_int, height_int)\n```\n\nChange cursor icons\n```python\nres_button.set_cursor_icons(\n    'img/1.png',     # The horizontal icon\n    'img/2.png',     # The 45 degree clockwise icon\n    'img/3.png',     # The 90 degree clockwise icon\n    'img/4.png')     # The 135 degree clockwise icon\n```\n"
  },
  {
    "path": "kivystudio/libs/resizablebehavior/__init__.py",
    "content": "from .resize import ResizableBehavior\n"
  },
  {
    "path": "kivystudio/libs/resizablebehavior/modal_cursor.py",
    "content": "from kivy.properties import BooleanProperty, StringProperty, ListProperty\nfrom kivy.graphics import InstructionGroup\nfrom kivy.uix.modalview import ModalView\nfrom kivy.graphics import Rectangle\nfrom kivy.core.window import Window\nfrom kivy.uix.widget import Widget\nfrom kivy.metrics import dp, cm\nfrom time import time\nimport os\npath = os.path.split(os.path.realpath(__file__))[0]\n\n\nclass CursorModalView(ModalView):\n    '''\n    The CursorModalView is the parent of ResizeCursor\n    '''\n\n    last_opened = 0.0\n\n    def __init__(self, **kwargs):\n        super(CursorModalView, self).__init__(**kwargs)\n        self.auto_dismiss = False\n        self.size_hint = (None, None)\n        self.background_color = (0, 0, 0, 0)\n        self.pos = (-9999, -9999)\n        self.cursor = ResizeCursor()\n        self.add_widget(self.cursor)\n        self.open()\n\n    def open(self, *largs):\n        self._window = self._search_window()\n        if not self._window:\n            Logger.warning('ModalView: cannot open view, no window found.')\n            return\n        if self.parent:\n            self.parent.remove_widget(self)\n        self._window.add_widget(self)\n\n    def put_on_top(self, *args):\n        self.dismiss()\n        self.open()\n\n    def on_hidden(self, val):\n        # View has to be reopened to get it on top of other widgets\n        timenow = time()\n        if not val and timenow > self.last_opened + 1:\n            self.dismiss()\n            self.open()\n            self.last_opened = timenow\n\n    def on_touch_down(self, *args):\n        pass\n\n    def on_touch_up(self, *args):\n        pass\n\n    def on_touch_move(self, *args):\n        pass\n\n\nclass ResizeCursor(Widget):\n    '''\n    The ResizeCursor is the mouse cursor\n    '''\n\n    hidden = BooleanProperty(True)\n    '''State of cursors visibility\n    It is switched to True when mouse is inside the widgets resize border\n    and False when it isn't.\n\n    :attr:`hidden` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    resize_icon_paths = ListProperty([\n    '{}/resize_horizontal.png'.format(path),\n    '{}/resize2.png'.format(path),\n    '{}/resize_vertical.png'.format(path),\n    '{}/resize1.png'.format(path),\n    ])\n    '''Cursor icon paths,\n\n    :attr:`resize_icon_paths` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [\n    'resize_horizontal.png',\n    'resize2.png',\n    'resize_vertical.png',\n    'resize1.png',\n    ]\n    '''\n\n    grabbed_by = None\n    '''Object reference.\n    Is used to prevent attribute changes from multiple widgets at same time.\n\n    :attr:`grabbed_by` defaults to None.\n    '''\n\n    sides = ()\n    source = StringProperty('')\n\n    def __init__(self, **kwargs):\n        super(ResizeCursor, self).__init__(**kwargs)\n        self.size_hint = (None, None)\n        self.pos_hint = (None, None)\n        self.source = ''\n        self.rect = Rectangle(pos=(-9998,-9998), size=(1, 1))\n        self.size = (dp(22), dp(22))\n        self.pos = [-9998, -9998]\n\n        # Makes an instruction group with a rectangle and\n        # loads an image inside it\n        # Binds its properties to mouse positional changes and events triggered\n        instr = InstructionGroup()\n        instr.add(self.rect)\n        self.canvas.after.add(instr)\n        self.bind(pos=lambda obj, val: setattr(self.rect, 'pos', val))\n        self.bind(source=lambda obj, val: setattr(self.rect, 'source', val))\n        self.bind(hidden=lambda obj, val: self.on_mouse_move(Window.mouse_pos))\n        Window.bind(mouse_pos=lambda obj, val: self.on_mouse_move(val))\n\n    def on_size(self, obj, val):\n        self.rect.size = val\n\n    def on_hidden(self, obj, val):\n        if not self.disabled:\n            self.parent.on_hidden(val)\n            if val:\n                Window.show_cursor = True\n            else:\n                Window.show_cursor = False\n\n    def on_mouse_move(self, val):\n        if self.hidden or self.disabled or not self.source:\n            if self.pos[0] != -9999:\n                self.pos[0] = -9999\n        else:\n            self.pos[0] = val[0] - self.width / 2.0\n            self.pos[1] = val[1] - self.height / 2.0\n\n    def change_side(self, left, right, up, down):\n        # Changes images when ResizableBehavior.hovering_resizable\n        # state changes\n        if self.disabled:\n            return\n        if not self.hidden and self.sides != (left, right, up, down):\n            if left and up or right and down:\n                self.source = self.resize_icon_paths[1]\n            elif left and down or right and up:\n                self.source = self.resize_icon_paths[3]\n            elif left or right:\n                self.source = self.resize_icon_paths[0]\n            elif up or down:\n                self.source = self.resize_icon_paths[2]\n            else:\n                if not any((left, right, up, down)):\n                    self.pos[0] = -9999\n            self.sides = (left, right, up, down)\n\n    def grab(self, wid):\n        self.grabbed_by = wid\n\n    def ungrab(self, wid):\n        if self.grabbed_by == wid:\n            self.grabbed_by = None\n\n    def on_disabled(self, obj, val):\n        if not val:\n            Window.show_cursor = True\n"
  },
  {
    "path": "kivystudio/libs/resizablebehavior/resize.py",
    "content": "'''\nResizable Behavior\n===============\n\nThe :class:`~kivy.uix.behaviors.resize.ResizableBehavior`\n`mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides Resize behavior.\nWhen combined with a widget, dragging at the resize enabled widget edge\ndefined by the\n:attr:`~kivy.uix.behaviors.resize.ResizableBehavior.resizable_border`\nwill resize the widget.\n\nFor an overview of behaviors, please refer to the :mod:`~kivy.uix.behaviors`\ndocumentation.\n\nExample\n-------\n\nThe following example adds resize behavior to a sidebar to make it resizable\n\n    from kivy.app import App\n    from kivy.uix.floatlayout import FloatLayout\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.uix.behaviors import ResizableBehavior\n    from kivy.uix.label import Label\n    from kivy.metrics import cm\n    from kivy.uix.button import Button\n    from kivy.graphics import *\n\n\n    class ResizableSideBar(ResizableBehavior, BoxLayout):\n        def __init__(self, **kwargs):\n            super(ResizableSideBar, self).__init__(**kwargs)\n            self.bg = Rectangle(pos=self.pos, size=self.size)\n            self.resizable_right = True\n            for x in range(1, 10):\n                lbl = Label(size_hint=(1, None), height=(cm(1)))\n                lbl.text = 'Text '+str(x)\n                self.add_widget(lbl)\n            self.bind(size=lambda obj, val: setattr(self.bg, 'size', val))\n\n            instr = InstructionGroup()\n            instr.add(Color(0.6, 0.6, 0.7, 1))\n            instr.add(self.bg)\n            self.canvas.before.add(instr)\n\n    class Sample(FloatLayout):\n        def __init__(self, **kwargs):\n            super(Sample, self).__init__(**kwargs)\n            sb = ResizableSideBar(orientation='vertical', size_hint=(None, 1))\n            sb.width = cm(4)\n            self.add_widget(sb)\n\n\n    class SampleApp(App):\n        def build(self):\n            return Sample()\n\n\n    SampleApp().run()\n\nSee :class:`~kivy.uix.behaviors.ResizableBehavior` for details.\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.properties import BooleanProperty, NumericProperty\nfrom kivy.metrics import dp, cm\nfrom .modal_cursor import CursorModalView\nfrom kivy.core.window import Window\nfrom kivy.logger import Logger\nfrom kivy.app import App\n\n\n__all__ = ('ResizableBehavior', )\n_modalview = CursorModalView()\n\n\nclass ResizableBehavior(object):\n    '''\n    The ResizableBehavior `mixin <https://en.wikipedia.org/wiki/Mixin>`_\n    class provides Resize behavior.\n    When combined with a widget, dragging at the resize enabled widget edge\n    defined by the\n    :attr:`~kivy.uix.behaviors.resize.ResizableBehavior.resizable_border`\n    will resize the widget. Please see the :mod:`drag behaviors module\n    <kivy.uix.behaviors.resize>` documentation for more information.\n    '''\n\n    hovering_resizable = BooleanProperty(False)\n    '''State of mouse hover.\n    It is switched to True when mouse is inside the widgets resize border\n    and False when it isn't.\n\n    :attr:`hovering_resizable` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    resizable_border = NumericProperty(dp(20))\n    '''Widgets resizable border size on each side.\n    Minimum resizing size is limited to resizable_border * 3 on all sides\n\n    :attr:`resizable_border` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20 dp.\n    '''\n\n    resizable_border_offset = NumericProperty(0)\n    '''Positive values move the resizable_border outside of the widget\n    and negative values put it closer to the center of the widget.\n    A value of resizable_border * 0.5 will center it on the widgets border,\n    which is the most expected behavior, but can sometimes interfere with\n    nearby widgets.\n\n    :attr:`resizable_border_offset` is a\n    :class:`~kivy.properties.NumericProperty` and defaults to 0.\n    '''\n\n    min_resizable_width = NumericProperty(0)\n    '''Minimum width\n\n    :attr:`min_resizable_width` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0 (disabled).\n    '''\n\n    min_resizable_height = NumericProperty(0)\n    '''Minimum height\n\n    :attr:`min_resizable_height` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0 (disabled).\n    '''\n\n    max_resizable_width = NumericProperty(0)\n    '''Maximum width\n\n    :attr:`max_resizable_width` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0 (disabled).\n    '''\n\n    max_resizable_height = NumericProperty(0)\n    '''Maximum height\n\n    :attr:`max_resizable_height` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0 (disabled).\n    '''\n\n    resizable_left = BooleanProperty(False)\n    '''Enable / disable resizing on left side\n\n    :attr:`resizable_left` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizable_right = BooleanProperty(False)\n    '''Enable / disable resizing on right side\n\n    :attr:`resizable_right` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizable_up = BooleanProperty(False)\n    '''Enable / disable resizing on upper side\n\n    :attr:`resizable_up` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizable_down = BooleanProperty(False)\n    '''Enable / disable resizing on lower side\n\n    :attr:`resizable_down` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizing_left = BooleanProperty(False)\n    '''A State which is enabled/disabled depending on the position relative to\n    the left resize border\n    It is switched to True when mouse is inside the left resize border and\n    False when it isn't.\n    It adjusts the mouse cursor and manages resizing when touch is moved.\n\n    :attr:`resizing_left` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizing_right = BooleanProperty(False)\n    '''A State which is enabled/disabled depending on the position relative to\n    the right resize border\n    It is switched to True when mouse is inside the right resize border and\n    False when it isn't.\n    It adjusts the mouse cursor and manages resizing when touch is moved.\n\n    :attr:`resizing_right` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizing_up = BooleanProperty(False)\n    '''A State which is enabled/disabled depending on the position relative\n    to the upper resize border\n    It is switched to True when mouse is inside the upper resize border and\n    False when it isn't.\n    It adjusts the mouse cursor and manages resizing when touch is moved.\n\n    :attr:`resizing_up` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizing_down = BooleanProperty(False)\n    '''A State which is enabled/disabled depending on the position relative\n    to the lower resize border\n    It is switched to True when mouse is inside the lower resize border and\n    False when it isn't.\n    It adjusts the mouse cursor and manages resizing when touch is moved.\n\n    :attr:`resizing_down` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    resizing = BooleanProperty(False)\n    '''State of widget resizing.\n    It is switched to True when a resize border is touched and back to\n    False when it is released.\n    It manages resizing when touch is moved.\n\n    :attr:`resizing` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    can_move_resize = BooleanProperty(True)\n    '''Move widget when resizing down or left.\n    To keep position on screen in a floatlayout,\n    actual postition has to be adjusted.\n    Resizing and changing position variables is problematic\n    inside movement restricting widgets,\n    (StackLayout, BoxLayout, others) this property manages that.\n\n    :attr:`can_move_resize` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    resize_lock = BooleanProperty(False)\n    '''Enable / disable resizing\n\n    :attr:`resize_lock` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    cursor = _modalview.cursor\n\n    def __init__(self, **kwargs):\n        super(ResizableBehavior, self).__init__(**kwargs)\n        Window.bind(mouse_pos=self.on_mouse_move)\n        Clock.schedule_once(_modalview.put_on_top, 0)\n        self.oldpos, self.oldsize = [], []\n\n    def on_enter_resizable(self):\n        self.cursor.hidden = False\n\n    def on_leave_resizable(self):\n        self.cursor.hidden = True\n\n    def on_mouse_move(self, _, pos):\n        if self.resize_lock:\n            return\n\n        if self.cursor and self.cursor.grabbed_by is None:\n            oldhover = self.hovering_resizable\n            pos = self.to_widget(pos[0]+self.pos[0], pos[1]+self.pos[1])  #added by Snu\n            self.hovering_resizable = self.check_resizable_side(pos[0], pos[1])\n            if oldhover != self.hovering_resizable:\n                if self.hovering_resizable:\n                    self.on_enter_resizable()\n                else:\n                    self.on_leave_resizable()\n\n    def check_resizable_side(self, x, y):\n        # Add small performance increase when distance is too high\n        # for possible hovering\n\n        if abs(self.x - x) > self.width + self.resizable_border_offset:\n            return False\n        elif abs(self.y - y) > self.height + self.resizable_border_offset:\n            return False\n\n        startx = self.x - self.resizable_border_offset\n        endx = self.right + self.resizable_border_offset\n        starty = self.y - self.resizable_border_offset\n        endy = self.top + self.resizable_border_offset\n        if self.resizable_left:\n            self.resizing_left = False\n            if startx <= x <= startx + self.resizable_border:\n                if starty <= y <= endy:\n                    self.resizing_left = True\n        if self.resizable_right and not self.resizing_left:\n            self.resizing_right = False\n            if endx - self.resizable_border <= x <= endx:\n                if starty <= y <= endy:\n                    self.resizing_right = True\n        if self.resizable_up:\n            self.resizing_up = False\n            if endy - self.resizable_border <= y <= endy:\n                if startx <= x <= endx:\n                    self.resizing_up = True\n        if self.resizable_down and not self.resizing_up:\n            self.resizing_down = False\n            if starty <= y <= starty + self.resizable_border:\n                if startx <= x <= endx:\n                    self.resizing_down = True\n\n        if any((self.resizing_left, self.resizing_right,\n                self.resizing_up, self.resizing_down)):\n            if self.cursor:\n                self.cursor.change_side(\n                    self.resizing_left, self.resizing_right,\n                    self.resizing_up, self.resizing_down)\n            return True\n        else:\n            return False\n\n    def on_touch_down(self, touch):\n        if not self.hovering_resizable:\n            return super(ResizableBehavior, self).on_touch_down(touch)\n\n        if self.resize_lock:\n            return super(ResizableBehavior, self).on_touch_down(touch)\n\n        if not any([\n            self.resizing_right, self.resizing_left,\n            self.resizing_down, self.resizing_up\n        ]):\n            return super(ResizableBehavior, self).on_touch_down(touch)\n\n        self.oldpos = list(self.pos)\n        self.oldsize = list(self.size)\n        self.resizing = True\n        self.cursor.grab(self)\n        return True\n\n    def on_touch_move(self, touch):\n        if not self.resizing:\n            return super(ResizableBehavior, self).on_touch_move(touch)\n        self.resize_widget(touch)\n\n    def resize_widget(self, touch):\n        rb3 = self.resizable_border * 3\n\n        if self.resizing_right:\n            if touch.pos[0] > self.pos[0] + rb3:\n                self.width = touch.pos[0] - self.pos[0]\n\n        elif self.resizing_left:\n            if touch.pos[0] < self.oldpos[0] + self.oldsize[0] - rb3:\n                if self.can_move_resize:\n                    self.pos[0] = touch.pos[0]\n                    self.width = self.oldpos[0] - touch.pos[0] + \\\n                        self.oldsize[0]\n                else:\n                    self.width = abs(touch.pos[0] - self.pos[0])\n                    if self.width < rb3:\n                        self.width = rb3\n\n        if self.resizing_down:\n            if touch.pos[1] < self.oldpos[1] + self.oldsize[1] - rb3:\n                if self.can_move_resize:\n                    self.pos[1] = touch.pos[1]\n                    self.height = self.oldpos[1] - touch.pos[1] + \\\n                        self.oldsize[1]\n                else:\n                    self.height = abs(touch.pos[1] - self.pos[1])\n                    if self.height < rb3:\n                        self.height = rb3\n\n        elif self.resizing_up:\n            if touch.pos[1] > self.pos[1] + rb3:\n                self.height = touch.pos[1] - self.pos[1]\n\n        self.check_min_max_size(touch)\n        return True\n\n    def check_min_max_size(self, touch):\n        # Resizes widgets back to min / max when smaller / bigger\n        # Resets position only when it's necessary\n        if self.min_resizable_width:\n            if self.width < self.min_resizable_width:\n                if self.pos[0] != self.oldpos[0]:\n                    self.width = self.min_resizable_width\n                    self.pos[0] = self.oldpos[0] + self.oldsize[0] - self.width\n                else:\n                    self.width = self.min_resizable_width\n\n        if self.max_resizable_width:\n            if self.width > self.max_resizable_width:\n                if self.pos[0] != self.oldpos[0]:\n                    self.width = self.max_resizable_width\n                    self.pos[0] = self.oldpos[0] + self.oldsize[0] - self.width\n                else:\n                    self.width = self.max_resizable_width\n\n        if self.min_resizable_height:\n            if self.height < self.min_resizable_height:\n                if self.pos[1] != self.oldpos[1]:\n                    self.height = self.min_resizable_height\n                    self.pos[1] = (\n                        self.oldpos[1] + self.oldsize[1] - self.height)\n                else:\n                    self.height = self.min_resizable_height\n\n        if self.max_resizable_height:\n            if self.height > self.max_resizable_height:\n                if self.pos[1] != self.oldpos[1]:\n                    self.height = self.max_resizable_height\n                    self.pos[1] = (\n                        self.oldpos[1] + self.oldsize[1] - self.height)\n                else:\n                    self.height = self.max_resizable_height\n\n    def on_touch_up(self, touch):\n        if not self.resizing:\n            return super(ResizableBehavior, self).on_touch_up(touch)\n        self.resizing = False\n        self.resizing_right = False\n        self.resizing_left = False\n        self.resizing_down = False\n        self.resizing_up = False\n        self.cursor.ungrab(self)\n        self.on_mouse_move(None, touch.pos)\n        return True\n\n    def on_resize_lock(self, obj, locked):\n        'Resets behavior to default values when resizing is locked'\n        if locked:\n            self.resizing = False\n            self.resizing_right = False\n            self.resizing_left = False\n            self.resizing_down = False\n            self.resizing_up = False\n            Window.show_cursor = True\n            self.cursor.ungrab(self)\n            self.cursor.hidden = True\n\n    def set_cursor_size(self, size):\n        '''Default cursor size is (dp(22), dp(22)).\n        Use this method to change it\n        '''\n        self.cursor.size = size\n\n    def set_cursor_icons(self, hor, deg45, deg90, deg135):\n        '''Change cursor icon paths.\n        Function takes 4 arguments, first is horizontal,\n        next 3 are turned 45, 90, 135 degrees clockwise.\n        '''\n        self.cursor.resize_icon_paths[0] = hor\n        self.cursor.resize_icon_paths[1] = deg45\n        self.cursor.resize_icon_paths[2] = deg90\n        self.cursor.resize_icon_paths[3] = deg135\n\n    def set_cursor_mode(self, value):\n        '''Method takes expects one integer\n        0 - Disables the resize cursor\n        1 - Default mode, os cursor is hidden and replaced with resize cursor\n        when mouse position enters widgets resizable_border\n        '''\n        if value == 0 and not self.cursor.disabled:\n            self.cursor.disabled = True\n        elif value == 1 and self.cursor.disabled:\n            self.cursor.disabled = False\n"
  },
  {
    "path": "kivystudio/main.kv",
    "content": "#: import icon kivystudio.tools.iconfonts.icon\n#: import settings kivystudio.settings.settings_obj\n\n<Assembly>:\n    orientation: 'vertical'\n    TopMenu:\n    BoxLayout:\n        id: box\n"
  },
  {
    "path": "kivystudio/main.py",
    "content": "'''\nKivyStudio main.py\nentry point for the Application\n'''\n\nimport sys, os\nsys.path = [os.pardir] + sys.path\n\n# from kivy.config import Config\n# Config.set('modules', 'monitor', '')\n\nfrom kivy.app import App\nfrom os.path import dirname, join\nfrom kivy.lang import Builder\nfrom kivystudio import tools\n\nfilepath = dirname(__file__)\ntools.load_kv(__file__,'main.kv')\n\n# registering custom icons\ntools.iconfonts.register('awesome_font',\n    join(filepath,'resources/font-awesome.ttf'),\n    join(filepath, 'resources/font-awesome.fontd'))\n\nfrom kivystudio.assembler import Assembler\n\n\nclass KivyStudio(App):\n\n    def build(self):\n        return Assembler\n    \n    def run(self):\n        super(KivyStudio, self).run()\n\n\nstudio_app = KivyStudio()\n\ndef main():\n    studio_app.run()\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "kivystudio/parser/__init__.py",
    "content": "import os, sys\nimport traceback\nfrom threading import Thread\nfrom functools import partial\ntry:\n    from importlib import reload\nexcept:      # for py 2 compatibility\n    pass\n\nfrom kivy.lang import Builder\nfrom kivy.clock import mainthread\nfrom kivy.uix.widget import Widget\nfrom kivy.resources import resource_add_path, resource_remove_path\n\nfrom kivystudio.components.emulator_area import get_emulator_area\nfrom kivystudio.tools.logger import Logger\n\ndef emulate_file(filename, threaded=False):\n    if not filename:\n        Logger.error(\"KivyStudio: No file selected press Ctrl-E to select file for emulation\")\n        return\n\n    Logger.info(\"Emulator: Starting Emulation on file '{}'\".format(filename))\n    root=None\n    if not os.path.exists(filename):\n        Logger.error(\"KivyStudio: file {} not found\".format(filename))\n        return\n\n    with open(filename) as fn:\n        file_content =  fn.read()\n\n    if app_not_run_properly(file_content):\n        Logger.error(\"Emulator: App not run properly 'try running under if __name__ == '__main__':\")\n        return\n\n    dirname=os.path.dirname(filename)\n    sys.path.append(dirname)\n    os.chdir(dirname)\n    resource_add_path(dirname)\n\n    get_emulator_area().screen_display.screen.clear_widgets()\n    if threaded:\n        Thread(target=partial(start_emulation, filename,\n                            file_content, threaded=threaded)).start()\n    else:\n        start_emulation(filename, file_content, threaded=threaded)\n\ndef start_emulation(filename, file_content, threaded=False):\n    root = None\n    has_error = False\n    if os.path.splitext(filename)[1] =='.kv':    # load the kivy file directly\n        try:    # cacthing error with kivy files\n            Builder.unload_file(filename)\n            root = Builder.load_file(filename)\n        except:\n            has_error = True\n            trace = traceback.format_exc()\n            Logger.error(\"Emulator: {}\".format(trace))\n\n    elif os.path.splitext(filename)[1] =='.py':\n        load_defualt_kv(filename, file_content)\n        try:    # cahching error with python files\n            root = load_py_file(filename, file_content)\n        except:\n            has_error = True\n            trace = traceback.format_exc()\n            Logger.error(\"Emulator: {}\".format(trace))\n    else:\n        Logger.warning(\"KivyStudio: can't emulate file type {}\".format(filename))\n\n    if not root and not has_error:\n        Logger.error('Emulator: No root widget found.')\n    elif not isinstance(root,Widget) and not has_error:\n        Logger.error(\"KivyStudio: root instance found = '{}' and is not a widget\".format(root))\n    elif root:\n        if threaded:\n            emulation_done(root, filename)\n        else:\n            get_emulator_area().screen_display.screen.add_widget(root)\n\n    dirname=os.path.dirname(filename)\n    sys.path.pop()\n    resource_remove_path(dirname)\n\n@mainthread\ndef emulation_done(root, filename):\n    ' add root on the main thread '\n    if root:\n        get_emulator_area().screen_display.screen.add_widget(root)\n\n\ndef load_defualt_kv(filename, file_content):\n    ''' load the default kivy file\n        associated the the python file,\n        usaully lowercase of the app class\n    '''\n    app_cls_name = get_app_cls_name(file_content)\n    if app_cls_name is None:\n        return\n\n    kv_name = app_cls_name.lower()\n    if app_cls_name.endswith('App'):\n        kv_name = app_cls_name[:len(app_cls_name)-3].lower()\n\n    if app_cls_name:\n        file_dir = os.path.dirname(filename)\n        kv_filename = os.path.join(file_dir, kv_name+'.kv')\n\n        if os.path.exists(kv_filename):\n            try:    # cacthing error with kivy files\n                Builder.unload_file(kv_filename)\n                root = Builder.load_file(kv_filename)\n            except:\n                trace = traceback.format_exc()\n                Logger.error(\"KivyStudio: You kivy file has a problem\")\n                Logger.error(\"KivyStudio: {}\".format(trace))\n\n\ndef get_app_cls_name(file_content):\n\n    lines = file_content.splitlines()\n    app_cls = get_import_as('from kivy.app import App', lines)\n    if not app_cls:\n    \tapp_cls = get_import_as('from kivymd.app import MDApp', lines)\n\n    def check_app_cls(line):\n        line = line.strip()\n        return line.startswith('class') and line.endswith('(%s):'%app_cls)\n\n    found = list(filter(check_app_cls, lines))\n    if found:\n        line = found[0]\n        cls_name = line.split('(')[0].split(' ')[1]\n        return cls_name\n\n\ndef get_root_from_runTouch(filename):\n    with open(filename) as fn:\n        text =  fn.read()\n\n    lines = text.splitlines()\n    run_touch = get_import_as('from kivy.base import runTouchApp', lines)\n\n    def check_run_touch(line):\n        line = line.strip()\n        return line.startswith('%s(' % run_touch)\n\n    found = list(filter(check_run_touch, lines))\n\n    if found:\n        line = found[0]\n        root_name = line.strip().split('(')[1].split(')')[0]\n\n        root_file = import_from_dir(filename)\n        root = getattr(reload(root_file), root_name)\n        return root\n\n\ndef load_py_file(filename, file_content):\n\n    app_cls_name = get_app_cls_name(file_content)\n    if app_cls_name:\n\n        root_file = import_from_dir(filename)\n        app_cls = getattr(reload(root_file), app_cls_name)\n        root = app_cls().build()\n        return root\n    \n    run_root = get_root_from_runTouch(filename)\n    if run_root:\n        return run_root\n\n\ndef import_from_dir(filename):\n    ''' force python to import this file\n    from the project_ dir'''\n\n    dirname, file = os.path.split(filename)\n    sys.path = [dirname] + sys.path\n\n    import_word = os.path.splitext(file)[0]\n    imported = __import__(import_word)\n    return imported\n\n\ndef get_import_as(start, lines):\n    ''' get the variable used by user when importing as.\n        Ex: from kivy import platform\n            it will return plaform\n        Ex: from kivy import platform as plt\n            it will return plt\n    '''\n    line = list(filter(lambda line: line.strip().startswith(start), lines))\n    if line:\n        words = line[0].split(' ')\n        import_word = words[len(words)-1]\n        return import_word\n\ndef app_not_run_properly(file_content):\n    \n    lines = file_content.splitlines()\n    run_touch = get_import_as('from kivy.base import runTouchApp', lines)\n\n    def check_run_touch(line):\n        return line.startswith('%s(' % run_touch)\n    found1 = list(filter(check_run_touch, lines))\n\n    def check_run_app(line):\n        app_name = get_app_cls_name(file_content)\n        return line.endswith('run()') and line.startswith(app_name)\n    found2 = list(filter(check_run_app, lines))\n\n    return found1 or found2\n"
  },
  {
    "path": "kivystudio/resources/font-awesome.fontd",
    "content": "{\"fa-camera\": 61488, \"fa-building-o\": 61687, \"fa-align-left\": 61494, \"fa-hand-o-up\": 61606, \"fa-external-link-square\": 61772, \"fa-cubes\": 61875, \"fa-get-pocket\": 62053, \"fa-share-alt-square\": 61921, \"fa-comment-o\": 61669, \"fa-thumbs-o-down\": 61576, \"fa-heart\": 61444, \"fa-file-photo-o\": 61893, \"fa-list\": 61498, \"fa-calendar-o\": 61747, \"fa-euro\": 61779, \"fa-life-buoy\": 61901, \"fa-stethoscope\": 61681, \"fa-bookmark\": 61486, \"fa-barcode\": 61482, \"fa-th-large\": 61449, \"fa-square\": 61640, \"fa-bank\": 61852, \"fa-times-circle-o\": 61532, \"fa-tachometer\": 61668, \"fa-bell-o\": 61602, \"fa-leaf\": 61548, \"fa-skype\": 61822, \"fa-certificate\": 61603, \"fa-car\": 61881, \"fa-ship\": 61978, \"fa-navicon\": 61641, \"fa-arrows-alt\": 61618, \"fa-server\": 62003, \"fa-cab\": 61882, \"fa-clone\": 62029, \"fa-wifi\": 61931, \"fa-meanpath\": 61964, \"fa-send-o\": 61913, \"fa-subscript\": 61740, \"fa-shirtsinbulk\": 61972, \"fa-sticky-note\": 62025, \"fa-road\": 61464, \"fa-times-circle\": 61527, \"fa-cart-arrow-down\": 61976, \"fa-safari\": 62055, \"fa-file-code-o\": 61897, \"fa-tty\": 61924, \"fa-list-ul\": 61642, \"fa-shopping-basket\": 62097, \"fa-arrow-circle-o-down\": 61466, \"fa-file-movie-o\": 61896, \"fa-slideshare\": 61927, \"fa-toggle-left\": 61841, \"fa-circle-o-notch\": 61902, \"fa-check-circle\": 61528, \"fa-mars-stroke-h\": 61995, \"fa-chevron-circle-up\": 61753, \"fa-circle\": 61713, \"fa-y-combinator-square\": 61908, \"fa-gbp\": 61780, \"fa-umbrella\": 61673, \"fa-sort-numeric-asc\": 61794, \"fa-pencil-square\": 61771, \"fa-soccer-ball-o\": 61923, \"fa-bicycle\": 61958, \"fa-user-times\": 62005, \"fa-trash-o\": 61460, \"fa-recycle\": 61880, \"fa-bell-slash-o\": 61943, \"fa-share-square-o\": 61509, \"fa-yc-square\": 61908, \"fa-users\": 61632, \"fa-yen\": 61783, \"fa-unlink\": 61735, \"fa-ban\": 61534, \"fa-sort-amount-asc\": 61792, \"fa-film\": 61448, \"fa-caret-down\": 61655, \"fa-file-text\": 61788, \"fa-list-alt\": 61474, \"fa-th-list\": 61451, \"fa-life-ring\": 61901, \"fa-filter\": 61616, \"fa-bluetooth-b\": 62100, \"fa-caret-up\": 61656, \"fa-sign-out\": 61579, \"fa-pencil\": 61504, \"fa-ticket\": 61765, \"fa-area-chart\": 61950, \"fa-skyatlas\": 61974, \"fa-opencart\": 62013, \"fa-hand-o-left\": 61605, \"fa-dedent\": 61499, \"fa-html5\": 61755, \"fa-at\": 61946, \"fa-dropbox\": 61803, \"fa-file-zip-o\": 61894, \"fa-long-arrow-up\": 61814, \"fa-stack-overflow\": 61804, \"fa-product-hunt\": 62088, \"fa-chevron-circle-left\": 61751, \"fa-check-square\": 61770, \"fa-cloud-download\": 61677, \"fa-caret-square-o-down\": 61776, \"fa-microphone-slash\": 61745, \"fa-folder\": 61563, \"fa-keyboard-o\": 61724, \"fa-bar-chart-o\": 61568, \"fa-transgender-alt\": 61989, \"fa-reddit-alien\": 62081, \"fa-openid\": 61851, \"fa-sort-asc\": 61662, \"fa-pause-circle\": 62091, \"fa-archive\": 61831, \"fa-eraser\": 61741, \"fa-cart-plus\": 61975, \"fa-inbox\": 61468, \"fa-truck\": 61649, \"fa-file-word-o\": 61890, \"fa-pied-piper-alt\": 61864, \"fa-object-ungroup\": 62024, \"fa-phone-square\": 61592, \"fa-eye\": 61550, \"fa-sun-o\": 61829, \"fa-folder-o\": 61716, \"fa-rebel\": 61904, \"fa-bars\": 61641, \"fa-cc-paypal\": 61940, \"fa-simplybuilt\": 61973, \"fa-won\": 61785, \"fa-hand-lizard-o\": 62040, \"fa-balance-scale\": 62030, \"fa-frown-o\": 61721, \"fa-repeat\": 61470, \"fa-arrow-circle-o-up\": 61467, \"fa-taxi\": 61882, \"fa-map-o\": 62072, \"fa-question\": 61736, \"fa-meh-o\": 61722, \"fa-terminal\": 61728, \"fa-caret-left\": 61657, \"fa-stop\": 61517, \"fa-tv\": 62060, \"fa-spoon\": 61873, \"fa-th\": 61450, \"fa-files-o\": 61637, \"fa-pause\": 61516, \"fa-mail-reply\": 61714, \"fa-cutlery\": 61685, \"fa-linux\": 61820, \"fa-battery-empty\": 62020, \"fa-hourglass-start\": 62033, \"fa-pause-circle-o\": 62092, \"fa-arrow-circle-left\": 61608, \"fa-shopping-cart\": 61562, \"fa-map-pin\": 62070, \"fa-youtube-play\": 61802, \"fa-drupal\": 61865, \"fa-bed\": 62006, \"fa-battery-quarter\": 62019, \"fa-weixin\": 61911, \"fa-exchange\": 61676, \"fa-gg-circle\": 62049, \"fa-angle-double-up\": 61698, \"fa-forward\": 61518, \"fa-hand-pointer-o\": 62042, \"fa-cog\": 61459, \"fa-reddit-square\": 61858, \"fa-arrow-circle-down\": 61611, \"fa-battery-three-quarters\": 62017, \"fa-venus-double\": 61990, \"fa-tumblr-square\": 61812, \"fa-angellist\": 61961, \"fa-toggle-off\": 61956, \"fa-info\": 61737, \"fa-eyedropper\": 61947, \"fa-behance\": 61876, \"fa-map-signs\": 62071, \"fa-file-audio-o\": 61895, \"fa-gavel\": 61667, \"fa-glass\": 61440, \"fa-hand-o-right\": 61604, \"fa-cube\": 61874, \"fa-pinterest-square\": 61651, \"fa-cc-stripe\": 61941, \"fa-battery-full\": 62016, \"fa-lightbulb-o\": 61675, \"fa-caret-square-o-up\": 61777, \"fa-video-camera\": 61501, \"fa-jsfiddle\": 61900, \"fa-long-arrow-left\": 61815, \"fa-caret-right\": 61658, \"fa-volume-down\": 61479, \"fa-tags\": 61484, \"fa-arrow-up\": 61538, \"fa-folder-open-o\": 61717, \"fa-shield\": 61746, \"fa-dashcube\": 61968, \"fa-rotate-right\": 61470, \"fa-angle-double-down\": 61699, \"fa-facebook\": 61594, \"fa-hand-scissors-o\": 62039, \"fa-scribd\": 62090, \"fa-sort\": 61660, \"fa-twitter-square\": 61569, \"fa-power-off\": 61457, \"fa-gratipay\": 61828, \"fa-mars\": 61986, \"fa-header\": 61916, \"fa-user\": 61447, \"fa-exclamation-circle\": 61546, \"fa-level-down\": 61769, \"fa-vine\": 61898, \"fa-tint\": 61507, \"fa-wordpress\": 61850, \"fa-expeditedssl\": 62014, \"fa-slack\": 61848, \"fa-cut\": 61636, \"fa-key\": 61572, \"fa-tripadvisor\": 62050, \"fa-opera\": 62058, \"fa-object-group\": 62023, \"fa-heartbeat\": 61982, \"fa-laptop\": 61705, \"fa-bomb\": 61922, \"fa-angle-double-left\": 61696, \"fa-quote-left\": 61709, \"fa-paw\": 61872, \"fa-reddit\": 61857, \"fa-cc-visa\": 61936, \"fa-circle-o\": 61708, \"fa-odnoklassniki-square\": 62052, \"fa-cc-jcb\": 62027, \"fa-mail-reply-all\": 61730, \"fa-lastfm\": 61954, \"fa-group\": 61632, \"fa-microphone\": 61744, \"fa-camera-retro\": 61571, \"fa-maxcdn\": 61750, \"fa-buysellads\": 61965, \"fa-play-circle-o\": 61469, \"fa-ge\": 61905, \"fa-i-cursor\": 62022, \"fa-percent\": 62101, \"fa-photo\": 61502, \"fa-toggle-on\": 61957, \"fa-fax\": 61868, \"fa-code-fork\": 61734, \"fa-y-combinator\": 62011, \"fa-map\": 62073, \"fa-try\": 61845, \"fa-diamond\": 61977, \"fa-neuter\": 61996, \"fa-quote-right\": 61710, \"fa-mobile\": 61707, \"fa-bell-slash\": 61942, \"fa-trademark\": 62044, \"fa-file-video-o\": 61896, \"fa-mixcloud\": 62089, \"fa-plus-circle\": 61525, \"fa-folder-open\": 61564, \"fa-css3\": 61756, \"fa-fast-forward\": 61520, \"fa-toggle-down\": 61776, \"fa-credit-card\": 61597, \"fa-caret-square-o-left\": 61841, \"fa-hourglass-3\": 62035, \"fa-hourglass-2\": 62034, \"fa-hourglass-1\": 62033, \"fa-angle-down\": 61703, \"fa-edge\": 62082, \"fa-trello\": 61825, \"fa-train\": 62008, \"fa-sheqel\": 61963, \"fa-file-powerpoint-o\": 61892, \"fa-arrow-left\": 61536, \"fa-television\": 62060, \"fa-life-saver\": 61901, \"fa-copy\": 61637, \"fa-sticky-note-o\": 62026, \"fa-mars-double\": 61991, \"fa-star-half-o\": 61731, \"fa-black-tie\": 62078, \"fa-chevron-up\": 61559, \"fa-chevron-down\": 61560, \"fa-fonticons\": 62080, \"fa-check-circle-o\": 61533, \"fa-plug\": 61926, \"fa-deviantart\": 61885, \"fa-dashboard\": 61668, \"fa-hourglass-o\": 62032, \"fa-plus\": 61543, \"fa-cc-discover\": 61938, \"fa-hashtag\": 62098, \"fa-gamepad\": 61723, \"fa-rub\": 61784, \"fa-history\": 61914, \"fa-sign-in\": 61584, \"fa-sort-amount-desc\": 61793, \"fa-rss-square\": 61763, \"fa-transgender\": 61988, \"fa-graduation-cap\": 61853, \"fa-whatsapp\": 62002, \"fa-mercury\": 61987, \"fa-amazon\": 62064, \"fa-medkit\": 61690, \"fa-bug\": 61832, \"fa-twitch\": 61928, \"fa-file-archive-o\": 61894, \"fa-forumbee\": 61969, \"fa-cny\": 61783, \"fa-arrows\": 61511, \"fa-map-marker\": 61505, \"fa-wheelchair\": 61843, \"fa-plus-square\": 61694, \"fa-male\": 61827, \"fa-institution\": 61852, \"fa-envelope-o\": 61443, \"fa-xing-square\": 61801, \"fa-step-forward\": 61521, \"fa-stumbleupon-circle\": 61859, \"fa-pencil-square-o\": 61508, \"fa-weibo\": 61834, \"fa-gear\": 61459, \"fa-rocket\": 61749, \"fa-bluetooth\": 62099, \"fa-search-plus\": 61454, \"fa-stop-circle\": 62093, \"fa-bell\": 61683, \"fa-undo\": 61666, \"fa-fast-backward\": 61513, \"fa-sliders\": 61918, \"fa-hotel\": 62006, \"fa-steam\": 61878, \"fa-hand-paper-o\": 62038, \"fa-circle-thin\": 61915, \"fa-share-square\": 61773, \"fa-asterisk\": 61545, \"fa-arrow-down\": 61539, \"fa-random\": 61556, \"fa-share-alt\": 61920, \"fa-beer\": 61692, \"fa-exclamation-triangle\": 61553, \"fa-commenting\": 62074, \"fa-volume-up\": 61480, \"fa-flag-checkered\": 61726, \"fa-ellipsis-h\": 61761, \"fa-hand-spock-o\": 62041, \"fa-crop\": 61733, \"fa-paragraph\": 61917, \"fa-battery-3\": 62017, \"fa-ellipsis-v\": 61762, \"fa-gift\": 61547, \"fa-strikethrough\": 61644, \"fa-motorcycle\": 61980, \"fa-life-bouy\": 61901, \"fa-reply-all\": 61730, \"fa-paper-plane-o\": 61913, \"fa-star-half\": 61577, \"fa-download\": 61465, \"fa-usb\": 62087, \"fa-chevron-circle-down\": 61754, \"fa-calculator\": 61932, \"fa-gg\": 62048, \"fa-contao\": 62061, \"fa-hand-o-down\": 61607, \"fa-leanpub\": 61970, \"fa-star-o\": 61446, \"fa-pie-chart\": 61952, \"fa-venus\": 61985, \"fa-inr\": 61782, \"fa-rupee\": 61782, \"fa-eur\": 61779, \"fa-tumblr\": 61811, \"fa-indent\": 61500, \"fa-mars-stroke-v\": 61994, \"fa-git\": 61907, \"fa-envelope\": 61664, \"fa-bitbucket-square\": 61810, \"fa-legal\": 61667, \"fa-gittip\": 61828, \"fa-chevron-left\": 61523, \"fa-cogs\": 61573, \"fa-arrow-circle-o-left\": 61840, \"fa-briefcase\": 61617, \"fa-user-md\": 61680, \"fa-angle-left\": 61700, \"fa-yc\": 62011, \"fa-long-arrow-right\": 61816, \"fa-coffee\": 61684, \"fa-copyright\": 61945, \"fa-toggle-up\": 61777, \"fa-support\": 61901, \"fa-youtube-square\": 61798, \"fa-cc-mastercard\": 61937, \"fa-unsorted\": 61660, \"fa-compress\": 61542, \"fa-android\": 61819, \"fa-font\": 61489, \"fa-arrow-right\": 61537, \"fa-minus\": 61544, \"fa-bitbucket\": 61809, \"fa-facebook-f\": 61594, \"fa-subway\": 62009, \"fa-headphones\": 61477, \"fa-paperclip\": 61638, \"fa-industry\": 62069, \"fa-rmb\": 61783, \"fa-minus-square\": 61766, \"fa-moon-o\": 61830, \"fa-file-excel-o\": 61891, \"fa-line-chart\": 61953, \"fa-fighter-jet\": 61691, \"fa-sort-alpha-desc\": 61790, \"fa-spotify\": 61884, \"fa-star-half-empty\": 61731, \"fa-share\": 61540, \"fa-comment\": 61557, \"fa-mars-stroke\": 61993, \"fa-stack-exchange\": 61837, \"fa-pied-piper\": 61863, \"fa-building\": 61869, \"fa-thumbs-up\": 61796, \"fa-chevron-circle-right\": 61752, \"fa-adjust\": 61506, \"fa-sellsy\": 61971, \"fa-paypal\": 61933, \"fa-signal\": 61458, \"fa-sort-up\": 61662, \"fa-shekel\": 61963, \"fa-codiepie\": 62084, \"fa-calendar-plus-o\": 62065, \"fa-digg\": 61862, \"fa-save\": 61639, \"fa-shopping-bag\": 62096, \"fa-eye-slash\": 61552, \"fa-backward\": 61514, \"fa-hand-stop-o\": 62038, \"fa-mail-forward\": 61540, \"fa-link\": 61633, \"fa-table\": 61646, \"fa-tag\": 61483, \"fa-turkish-lira\": 61845, \"fa-envelope-square\": 61849, \"fa-optin-monster\": 62012, \"fa-money\": 61654, \"fa-instagram\": 61805, \"fa-volume-off\": 61478, \"fa-unlock-alt\": 61758, \"fa-minus-circle\": 61526, \"fa-hacker-news\": 61908, \"fa-hand-grab-o\": 62037, \"fa-adn\": 61808, \"fa-list-ol\": 61643, \"fa-magnet\": 61558, \"fa-calendar-minus-o\": 62066, \"fa-linkedin\": 61665, \"fa-paper-plane\": 61912, \"fa-mouse-pointer\": 62021, \"fa-reply\": 61714, \"fa-smile-o\": 61720, \"fa-hourglass-half\": 62034, \"fa-behance-square\": 61877, \"fa-twitter\": 61593, \"fa-expand\": 61541, \"fa-flask\": 61635, \"fa-flash\": 61671, \"fa-trophy\": 61585, \"fa-long-arrow-down\": 61813, \"fa-odnoklassniki\": 62051, \"fa-angle-double-right\": 61697, \"fa-home\": 61461, \"fa-bolt\": 61671, \"fa-italic\": 61491, \"fa-comments\": 61574, \"fa-commenting-o\": 62075, \"fa-toggle-right\": 61778, \"fa-file\": 61787, \"fa-bold\": 61490, \"fa-internet-explorer\": 62059, \"fa-cc-amex\": 61939, \"fa-sort-down\": 61661, \"fa-anchor\": 61757, \"fa-medium\": 62010, \"fa-calendar\": 61555, \"fa-superscript\": 61739, \"fa-wechat\": 61911, \"fa-file-text-o\": 61686, \"fa-cloud\": 61634, \"fa-user-plus\": 62004, \"fa-times\": 61453, \"fa-street-view\": 61981, \"fa-trash\": 61944, \"fa-paste\": 61674, \"fa-ambulance\": 61689, \"fa-suitcase\": 61682, \"fa-binoculars\": 61925, \"fa-user-secret\": 61979, \"fa-sort-alpha-asc\": 61789, \"fa-picture-o\": 61502, \"fa-cc\": 61962, \"fa-calendar-times-o\": 62067, \"fa-phone\": 61589, \"fa-github-square\": 61586, \"fa-hand-peace-o\": 62043, \"fa-windows\": 61818, \"fa-500px\": 62062, \"fa-calendar-check-o\": 62068, \"fa-clock-o\": 61463, \"fa-connectdevelop\": 61966, \"fa-text-height\": 61492, \"fa-houzz\": 62076, \"fa-align-right\": 61496, \"fa-angle-right\": 61701, \"fa-hand-rock-o\": 62037, \"fa-heart-o\": 61578, \"fa-steam-square\": 61879, \"fa-underline\": 61645, \"fa-file-image-o\": 61893, \"fa-bus\": 61959, \"fa-play-circle\": 61764, \"fa-plus-square-o\": 61846, \"fa-rss\": 61598, \"fa-battery-0\": 62020, \"fa-battery-1\": 62019, \"fa-battery-2\": 62018, \"fa-google-plus-square\": 61652, \"fa-battery-4\": 62016, \"fa-caret-square-o-right\": 61778, \"fa-child\": 61870, \"fa-space-shuttle\": 61847, \"fa-pinterest-p\": 62001, \"fa-outdent\": 61499, \"fa-lock\": 61475, \"fa-dot-circle-o\": 61842, \"fa-git-square\": 61906, \"fa-clipboard\": 61674, \"fa-mortar-board\": 61853, \"fa-university\": 61852, \"fa-github\": 61595, \"fa-jpy\": 61783, \"fa-vk\": 61833, \"fa-print\": 61487, \"fa-code\": 61729, \"fa-book\": 61485, \"fa-pinterest\": 61650, \"fa-youtube\": 61799, \"fa-fire\": 61549, \"fa-hourglass-end\": 62035, \"fa-tasks\": 61614, \"fa-xing\": 61800, \"fa-ioxhost\": 61960, \"fa-play\": 61515, \"fa-flag-o\": 61725, \"fa-battery-half\": 62018, \"fa-search\": 61442, \"fa-genderless\": 61997, \"fa-renren\": 61835, \"fa-database\": 61888, \"fa-plane\": 61554, \"fa-sort-numeric-desc\": 61795, \"fa-intersex\": 61988, \"fa-tree\": 61883, \"fa-scissors\": 61636, \"fa-question-circle\": 61529, \"fa-close\": 61453, \"fa-crosshairs\": 61531, \"fa-apple\": 61817, \"fa-wrench\": 61613, \"fa-sitemap\": 61672, \"fa-language\": 61867, \"fa-automobile\": 61881, \"fa-hourglass\": 62036, \"fa-bar-chart\": 61568, \"fa-file-o\": 61462, \"fa-krw\": 61785, \"fa-soundcloud\": 61886, \"fa-floppy-o\": 61639, \"fa-upload\": 61587, \"fa-arrow-circle-o-right\": 61838, \"fa-info-circle\": 61530, \"fa-cloud-upload\": 61678, \"fa-facebook-official\": 62000, \"fa-search-minus\": 61456, \"fa-music\": 61441, \"fa-stumbleupon\": 61860, \"fa-star-half-full\": 61731, \"fa-file-picture-o\": 61893, \"fa-image\": 61502, \"fa-mobile-phone\": 61707, \"fa-dollar\": 61781, \"fa-google-wallet\": 61934, \"fa-feed\": 61598, \"fa-vimeo\": 62077, \"fa-futbol-o\": 61923, \"fa-hdd-o\": 61600, \"fa-remove\": 61453, \"fa-bullseye\": 61760, \"fa-location-arrow\": 61732, \"fa-female\": 61826, \"fa-joomla\": 61866, \"fa-thumb-tack\": 61581, \"fa-align-justify\": 61497, \"fa-external-link\": 61582, \"fa-arrow-circle-right\": 61609, \"fa-level-up\": 61768, \"fa-gears\": 61573, \"fa-foursquare\": 61824, \"fa-venus-mars\": 61992, \"fa-yelp\": 61929, \"fa-exclamation\": 61738, \"fa-star\": 61445, \"fa-google-plus\": 61653, \"fa-ra\": 61904, \"fa-h-square\": 61693, \"fa-lastfm-square\": 61955, \"fa-registered\": 62045, \"fa-edit\": 61508, \"fa-unlock\": 61596, \"fa-sort-desc\": 61661, \"fa-tencent-weibo\": 61909, \"fa-thumbs-down\": 61797, \"fa-eject\": 61522, \"fa-linkedin-square\": 61580, \"fa-pagelines\": 61836, \"fa-chain\": 61633, \"fa-yahoo\": 61854, \"fa-send\": 61912, \"fa-check\": 61452, \"fa-compass\": 61774, \"fa-viacoin\": 62007, \"fa-angle-up\": 61702, \"fa-wikipedia-w\": 62054, \"fa-qrcode\": 61481, \"fa-paint-brush\": 61948, \"fa-bookmark-o\": 61591, \"fa-usd\": 61781, \"fa-chevron-right\": 61524, \"fa-ruble\": 61784, \"fa-delicious\": 61861, \"fa-btc\": 61786, \"fa-lemon-o\": 61588, \"fa-arrow-circle-up\": 61610, \"fa-comments-o\": 61670, \"fa-chrome\": 62056, \"fa-check-square-o\": 61510, \"fa-ils\": 61963, \"fa-birthday-cake\": 61949, \"fa-tablet\": 61706, \"fa-codepen\": 61899, \"fa-stop-circle-o\": 62094, \"fa-chain-broken\": 61735, \"fa-puzzle-piece\": 61742, \"fa-creative-commons\": 62046, \"fa-spinner\": 61712, \"fa-newspaper-o\": 61930, \"fa-globe\": 61612, \"fa-firefox\": 62057, \"fa-vimeo-square\": 61844, \"fa-magic\": 61648, \"fa-align-center\": 61495, \"fa-warning\": 61553, \"fa-desktop\": 61704, \"fa-cc-diners-club\": 62028, \"fa-thumbs-o-up\": 61575, \"fa-dribbble\": 61821, \"fa-square-o\": 61590, \"fa-columns\": 61659, \"fa-flickr\": 61806, \"fa-retweet\": 61561, \"fa-flag\": 61476, \"fa-google\": 61856, \"fa-file-sound-o\": 61895, \"fa-bitcoin\": 61786, \"fa-text-width\": 61493, \"fa-arrows-v\": 61565, \"fa-hospital-o\": 61688, \"fa-step-backward\": 61512, \"fa-bullhorn\": 61601, \"fa-fire-extinguisher\": 61748, \"fa-arrows-h\": 61566, \"fa-refresh\": 61473, \"fa-fort-awesome\": 62086, \"fa-github-alt\": 61715, \"fa-reorder\": 61641, \"fa-modx\": 62085, \"fa-facebook-square\": 61570, \"fa-empire\": 61905, \"fa-credit-card-alt\": 62083, \"fa-qq\": 61910, \"fa-rouble\": 61784, \"fa-minus-square-o\": 61767, \"fa-rotate-left\": 61666, \"fa-file-pdf-o\": 61889}"
  },
  {
    "path": "kivystudio/settings.py",
    "content": "import os\nfrom kivy.event import EventDispatcher\nfrom kivy.config import ConfigParser\nfrom kivy.properties import ConfigParserProperty\nfrom kivystudio.tools import get_user_data_dir\nfrom kivy.core.window  import Window\n\nWindow.maximize()\n\nconfig = ConfigParser('kivystudio')\nconfig.adddefaultsection('application')\nconfig.adddefaultsection('graphics')\nconfig_file = os.path.join(get_user_data_dir('kivystudio'), 'config.ini')\nconfig.read(config_file)\n\nclass SettingDispatcher(EventDispatcher):\n\n    auto_save = ConfigParserProperty(0, 'application', 'auto_save', 'kivystudio',val_type=int)\n\n    auto_emulate = ConfigParserProperty(1, 'application', 'auto_emulate', 'kivystudio',val_type=int)\n\n    dpi_scale = ConfigParserProperty(1, 'graphics', 'dpi_scale', 'kivystudio',val_type=float)\n\nsettings_obj = SettingDispatcher()\n"
  },
  {
    "path": "kivystudio/tools/__init__.py",
    "content": "\nimport os\nfrom os.path import dirname, join, exists, expanduser\nfrom kivy import platform\nfrom kivy.lang import Builder\nfrom kivy.core.window import Window\n\ndef set_auto_mouse_position(widget):\n    ''' functions trys to position widget\n    automaticaly on the mouse pos'''\n\n    if Window.mouse_pos[0]+widget.width > Window.width:\n        widget.x = Window.mouse_pos[0]\n\n    else:\n        widget.x = Window.mouse_pos[0]\n    \n    if (Window.mouse_pos[1]+widget.height > Window.height):\n        widget.top = Window.mouse_pos[1]-16\n    else:\n        widget.top = Window.mouse_pos[1]-16\n\ndef load_kv(filepath, file):\n\t''' load a kivy file from the current\n\t\tdirectory of the file calling this func\n\t\twhere filepath is __file__ and file is a kv file''' \n\tfilepath = dirname(filepath)\n\tBuilder.load_file(join(filepath, file))\n\n\ndef get_user_data_dir(name):\n    # Determine and return the user_data_dir.\n    data_dir = \"\"\n    if platform == 'ios':\n        raise NotImplemented()\n    elif platform == 'android':\n        raise NotImplemented()\n    elif platform == 'win':\n        data_dir = os.path.join(os.environ['APPDATA'], name)\n    elif platform == 'macosx':\n        data_dir = '~/Library/Application Support/{}'.format(name)\n        data_dir = expanduser(data_dir)\n    else:  # _platform == 'linux' or anything else...:\n        data_dir = os.environ.get('XDG_CONFIG_HOME', '~/.config')\n        data_dir = expanduser(join(data_dir, name))\n    if not exists(data_dir):\n        os.mkdir(data_dir)\n    return data_dir\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/LICENSE",
    "content": "Copyright (c) 2010-2015 Kivy Team and other contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/README.md",
    "content": "![Screenshot](https://github.com/jeysonmc/garden.iconfonts/blob/master/screenshot.png \"Scrennshot\")\n\n\nKivy-iconfonts\n==============\n\nSimple helper functions to make easier to use icon fonts in Labels and derived widgets\n\nUsage\n=====\n\nOnce you have a .fontd file (see below) for your ttf iconfont generated you can use it like this:\n\nIn your main.py register your font:\n```python\n    iconfonts.register('default_font', 'iconfont_sample.ttf', 'iconfont_sample.fontd')\n```\n\nIn your kv file or string:\n```yaml\n    #: import icon kivy.garden.iconfonts.icon\n    Button:\n        markup: True # Always turn markup on\n        text: \"%s\"%(icon('icon-comment'))\n```\nSee __init__.py for another example.\n\nGenerating a fontd file\n=====================\n\nA .fontd file is just a python dictionary filled with icon_code: unicode_value entries. This information is extracted from a css file (all iconfonts packages I've seen have one).\n\n**Example with Font-Awesome**\n\n1. Download Font-Awesome (http://fortawesome.github.io/Font-Awesome/)\n2. Copy both the TTF and CSS files (fonts/fontawesome-webfont.ttf and css/font-awesome.css) to your project\n3. Create and execute a python script to generate your fontd file:\n```python\niconfonts.create_fontdict_file('font-awesome.css', 'font-awesome.fontd')\n```\n4. If everything went well your font dictionary file exists. You can delete the css file (font-awesome.css)\n\n\nMore IconFonts\n==============\n- http://fortawesome.github.io/Font-Awesome/\n- http://fontello.com/\n- https://icomoon.io\n\nLICENSE\n=======\n\nMIT (except sample font that I got from http://fontello.com)\n\n\nCredits\n=======\n\nAuthor: Jeyson Molina <jeyson.mco@gmail.com>\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/__init__.py",
    "content": "\"\"\"\nKivy-iconfonts\n==============\n\nSimple helper functions to make easier to use icon fonts in Labels and derived\nwidgets.\n\"\"\"\nfrom .iconfonts import *\n\n\nif __name__ == '__main__':\n    from kivy.lang import Builder\n    from kivy.base import runTouchApp\n    from kivy.animation import Animation\n    from os.path import join, dirname\n\n    kv = \"\"\"\n#: import icon iconfonts.icon\nBoxLayout:\n    Button:\n        markup: True\n        text: \"%s\"%(icon('icon-comment', 32))\n    Button:\n        markup: True\n        text: \"%s\"%(icon('icon-emo-happy', 64))\n\n    Button:\n        markup: True\n        text: \"%s Text\"%(icon('icon-plus-circled', 24))\n\n    Button:\n        markup: True\n        text: \"%s\"%(icon('icon-doc-text-inv', 64, 'ff3333'))\n\n    Label:\n        id: _anim\n        markup: True\n        text: \"%s\"%(icon('icon-spin6', 32))\n        font_color: 1, 0, 0, 1\n        p: 0\n        canvas:\n            Clear\n            PushMatrix\n            Rotate:\n                angle: -self.p\n                origin: self.center_x , self.center_y\n            Rectangle:\n                size: (32, 32)\n                pos: self.center_x - 16, self.center_y - 16\n                texture: self.texture\n            PopMatrix\n    \"\"\"\n\n    register('default_font', 'iconfont_sample.ttf',\n             join(dirname(__file__), 'iconfont_sample.fontd'))\n\n    root = Builder.load_string(kv)\n    an = Animation(p=360, duration=2) + Animation(p=0, duration=0)\n    an.repeat = True\n    an.start(root.ids['_anim'])\n    runTouchApp(root)\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/iconfonts.py",
    "content": "import re\nimport json\nfrom collections import OrderedDict\nfrom kivy.compat import PY2\n\n_register = OrderedDict()\n\nif not PY2:\n    unichr = chr\n\n\ndef register(name, ttf_fname, fontd_fname):\n    \"\"\"Register an Iconfont\n    :param name: font name identifier.\n    :param ttf_fname: ttf filename (path)\n    :param fontd_fname: fontdic filename. (See create_fontdic)\n    \"\"\"\n    with open(fontd_fname, 'r') as f:\n        fontd = json.loads(f.read())\n        _register[name] = ttf_fname, fontd_fname, fontd\n\n\ndef icon(code, size=None, color=None, font_name=None):\n    \"\"\" Gets an icon from iconfont.\n    :param code: Icon codename (ex: 'icon-name')\n    :param size: Icon size\n    :param color: Icon color\n    :param font_name: Registered font name. If None first one is used.\n    :returns: icon text (with markups)\n    \"\"\"\n    font = list(_register.keys())[0] if font_name is None else font_name\n    font_data = _register[font]\n    s = \"[font=%s]%s[/font]\" % (font_data[0], unichr(font_data[2][code]))\n    if size is not None:\n        s = \"[size=%s]%s[/size]\" % (size, s)\n    if color is not None:\n        s = \"[color=%s]%s[/color]\" % (color, s)\n\n    return s\n\n\ndef create_fontdict_file(css_fname, output_fname):\n    \"\"\"Creates a font dictionary file. Basically creates a dictionary filled\n    with icon_code: unicode_value entries\n    obtained from a CSS file.\n    :param css_fname: CSS filename where font's rules are declared.\n    :param output_fname: Fontd file destination\n    \"\"\"\n    with open(css_fname, 'r') as f:\n        data = f.read()\n        res = _parse(data)\n        with open(output_fname, 'w') as o:\n            o.write(json.dumps(res))\n        return res\n\n\ndef _parse(data):\n    # find start index where icons rules start\n    pat_start = re.compile('}.+content:', re.DOTALL)\n    rules_start = [x for x in re.finditer(pat_start, data)][0].start()\n    data = data[rules_start:]  # crop data\n    data = data.replace(\"\\\\\", '0x')  # replace unicodes\n    data = data.replace(\"'\", '\"')  # replace quotes\n    # iterate rule indices and extract value\n    pat_keys = re.compile('[a-zA-Z0-9_-]+:before')\n    res = dict()\n    for i in re.finditer(pat_keys, data):\n        start = i.start()\n        end = data.find('}', start)\n        key = i.group().replace(':before', '')\n        try:\n            value = int(data[start:end].split('\"')[1], 0)\n        except (IndexError, ValueError):\n            continue\n        res[key] = value\n    return res\n\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/test/font-awesome.css",
    "content": "/*!\n *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.5.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:\"\\f000\"}.fa-music:before{content:\"\\f001\"}.fa-search:before{content:\"\\f002\"}.fa-envelope-o:before{content:\"\\f003\"}.fa-heart:before{content:\"\\f004\"}.fa-star:before{content:\"\\f005\"}.fa-star-o:before{content:\"\\f006\"}.fa-user:before{content:\"\\f007\"}.fa-film:before{content:\"\\f008\"}.fa-th-large:before{content:\"\\f009\"}.fa-th:before{content:\"\\f00a\"}.fa-th-list:before{content:\"\\f00b\"}.fa-check:before{content:\"\\f00c\"}.fa-remove:before,.fa-close:before,.fa-times:before{content:\"\\f00d\"}.fa-search-plus:before{content:\"\\f00e\"}.fa-search-minus:before{content:\"\\f010\"}.fa-power-off:before{content:\"\\f011\"}.fa-signal:before{content:\"\\f012\"}.fa-gear:before,.fa-cog:before{content:\"\\f013\"}.fa-trash-o:before{content:\"\\f014\"}.fa-home:before{content:\"\\f015\"}.fa-file-o:before{content:\"\\f016\"}.fa-clock-o:before{content:\"\\f017\"}.fa-road:before{content:\"\\f018\"}.fa-download:before{content:\"\\f019\"}.fa-arrow-circle-o-down:before{content:\"\\f01a\"}.fa-arrow-circle-o-up:before{content:\"\\f01b\"}.fa-inbox:before{content:\"\\f01c\"}.fa-play-circle-o:before{content:\"\\f01d\"}.fa-rotate-right:before,.fa-repeat:before{content:\"\\f01e\"}.fa-refresh:before{content:\"\\f021\"}.fa-list-alt:before{content:\"\\f022\"}.fa-lock:before{content:\"\\f023\"}.fa-flag:before{content:\"\\f024\"}.fa-headphones:before{content:\"\\f025\"}.fa-volume-off:before{content:\"\\f026\"}.fa-volume-down:before{content:\"\\f027\"}.fa-volume-up:before{content:\"\\f028\"}.fa-qrcode:before{content:\"\\f029\"}.fa-barcode:before{content:\"\\f02a\"}.fa-tag:before{content:\"\\f02b\"}.fa-tags:before{content:\"\\f02c\"}.fa-book:before{content:\"\\f02d\"}.fa-bookmark:before{content:\"\\f02e\"}.fa-print:before{content:\"\\f02f\"}.fa-camera:before{content:\"\\f030\"}.fa-font:before{content:\"\\f031\"}.fa-bold:before{content:\"\\f032\"}.fa-italic:before{content:\"\\f033\"}.fa-text-height:before{content:\"\\f034\"}.fa-text-width:before{content:\"\\f035\"}.fa-align-left:before{content:\"\\f036\"}.fa-align-center:before{content:\"\\f037\"}.fa-align-right:before{content:\"\\f038\"}.fa-align-justify:before{content:\"\\f039\"}.fa-list:before{content:\"\\f03a\"}.fa-dedent:before,.fa-outdent:before{content:\"\\f03b\"}.fa-indent:before{content:\"\\f03c\"}.fa-video-camera:before{content:\"\\f03d\"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:\"\\f03e\"}.fa-pencil:before{content:\"\\f040\"}.fa-map-marker:before{content:\"\\f041\"}.fa-adjust:before{content:\"\\f042\"}.fa-tint:before{content:\"\\f043\"}.fa-edit:before,.fa-pencil-square-o:before{content:\"\\f044\"}.fa-share-square-o:before{content:\"\\f045\"}.fa-check-square-o:before{content:\"\\f046\"}.fa-arrows:before{content:\"\\f047\"}.fa-step-backward:before{content:\"\\f048\"}.fa-fast-backward:before{content:\"\\f049\"}.fa-backward:before{content:\"\\f04a\"}.fa-play:before{content:\"\\f04b\"}.fa-pause:before{content:\"\\f04c\"}.fa-stop:before{content:\"\\f04d\"}.fa-forward:before{content:\"\\f04e\"}.fa-fast-forward:before{content:\"\\f050\"}.fa-step-forward:before{content:\"\\f051\"}.fa-eject:before{content:\"\\f052\"}.fa-chevron-left:before{content:\"\\f053\"}.fa-chevron-right:before{content:\"\\f054\"}.fa-plus-circle:before{content:\"\\f055\"}.fa-minus-circle:before{content:\"\\f056\"}.fa-times-circle:before{content:\"\\f057\"}.fa-check-circle:before{content:\"\\f058\"}.fa-question-circle:before{content:\"\\f059\"}.fa-info-circle:before{content:\"\\f05a\"}.fa-crosshairs:before{content:\"\\f05b\"}.fa-times-circle-o:before{content:\"\\f05c\"}.fa-check-circle-o:before{content:\"\\f05d\"}.fa-ban:before{content:\"\\f05e\"}.fa-arrow-left:before{content:\"\\f060\"}.fa-arrow-right:before{content:\"\\f061\"}.fa-arrow-up:before{content:\"\\f062\"}.fa-arrow-down:before{content:\"\\f063\"}.fa-mail-forward:before,.fa-share:before{content:\"\\f064\"}.fa-expand:before{content:\"\\f065\"}.fa-compress:before{content:\"\\f066\"}.fa-plus:before{content:\"\\f067\"}.fa-minus:before{content:\"\\f068\"}.fa-asterisk:before{content:\"\\f069\"}.fa-exclamation-circle:before{content:\"\\f06a\"}.fa-gift:before{content:\"\\f06b\"}.fa-leaf:before{content:\"\\f06c\"}.fa-fire:before{content:\"\\f06d\"}.fa-eye:before{content:\"\\f06e\"}.fa-eye-slash:before{content:\"\\f070\"}.fa-warning:before,.fa-exclamation-triangle:before{content:\"\\f071\"}.fa-plane:before{content:\"\\f072\"}.fa-calendar:before{content:\"\\f073\"}.fa-random:before{content:\"\\f074\"}.fa-comment:before{content:\"\\f075\"}.fa-magnet:before{content:\"\\f076\"}.fa-chevron-up:before{content:\"\\f077\"}.fa-chevron-down:before{content:\"\\f078\"}.fa-retweet:before{content:\"\\f079\"}.fa-shopping-cart:before{content:\"\\f07a\"}.fa-folder:before{content:\"\\f07b\"}.fa-folder-open:before{content:\"\\f07c\"}.fa-arrows-v:before{content:\"\\f07d\"}.fa-arrows-h:before{content:\"\\f07e\"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:\"\\f080\"}.fa-twitter-square:before{content:\"\\f081\"}.fa-facebook-square:before{content:\"\\f082\"}.fa-camera-retro:before{content:\"\\f083\"}.fa-key:before{content:\"\\f084\"}.fa-gears:before,.fa-cogs:before{content:\"\\f085\"}.fa-comments:before{content:\"\\f086\"}.fa-thumbs-o-up:before{content:\"\\f087\"}.fa-thumbs-o-down:before{content:\"\\f088\"}.fa-star-half:before{content:\"\\f089\"}.fa-heart-o:before{content:\"\\f08a\"}.fa-sign-out:before{content:\"\\f08b\"}.fa-linkedin-square:before{content:\"\\f08c\"}.fa-thumb-tack:before{content:\"\\f08d\"}.fa-external-link:before{content:\"\\f08e\"}.fa-sign-in:before{content:\"\\f090\"}.fa-trophy:before{content:\"\\f091\"}.fa-github-square:before{content:\"\\f092\"}.fa-upload:before{content:\"\\f093\"}.fa-lemon-o:before{content:\"\\f094\"}.fa-phone:before{content:\"\\f095\"}.fa-square-o:before{content:\"\\f096\"}.fa-bookmark-o:before{content:\"\\f097\"}.fa-phone-square:before{content:\"\\f098\"}.fa-twitter:before{content:\"\\f099\"}.fa-facebook-f:before,.fa-facebook:before{content:\"\\f09a\"}.fa-github:before{content:\"\\f09b\"}.fa-unlock:before{content:\"\\f09c\"}.fa-credit-card:before{content:\"\\f09d\"}.fa-feed:before,.fa-rss:before{content:\"\\f09e\"}.fa-hdd-o:before{content:\"\\f0a0\"}.fa-bullhorn:before{content:\"\\f0a1\"}.fa-bell:before{content:\"\\f0f3\"}.fa-certificate:before{content:\"\\f0a3\"}.fa-hand-o-right:before{content:\"\\f0a4\"}.fa-hand-o-left:before{content:\"\\f0a5\"}.fa-hand-o-up:before{content:\"\\f0a6\"}.fa-hand-o-down:before{content:\"\\f0a7\"}.fa-arrow-circle-left:before{content:\"\\f0a8\"}.fa-arrow-circle-right:before{content:\"\\f0a9\"}.fa-arrow-circle-up:before{content:\"\\f0aa\"}.fa-arrow-circle-down:before{content:\"\\f0ab\"}.fa-globe:before{content:\"\\f0ac\"}.fa-wrench:before{content:\"\\f0ad\"}.fa-tasks:before{content:\"\\f0ae\"}.fa-filter:before{content:\"\\f0b0\"}.fa-briefcase:before{content:\"\\f0b1\"}.fa-arrows-alt:before{content:\"\\f0b2\"}.fa-group:before,.fa-users:before{content:\"\\f0c0\"}.fa-chain:before,.fa-link:before{content:\"\\f0c1\"}.fa-cloud:before{content:\"\\f0c2\"}.fa-flask:before{content:\"\\f0c3\"}.fa-cut:before,.fa-scissors:before{content:\"\\f0c4\"}.fa-copy:before,.fa-files-o:before{content:\"\\f0c5\"}.fa-paperclip:before{content:\"\\f0c6\"}.fa-save:before,.fa-floppy-o:before{content:\"\\f0c7\"}.fa-square:before{content:\"\\f0c8\"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:\"\\f0c9\"}.fa-list-ul:before{content:\"\\f0ca\"}.fa-list-ol:before{content:\"\\f0cb\"}.fa-strikethrough:before{content:\"\\f0cc\"}.fa-underline:before{content:\"\\f0cd\"}.fa-table:before{content:\"\\f0ce\"}.fa-magic:before{content:\"\\f0d0\"}.fa-truck:before{content:\"\\f0d1\"}.fa-pinterest:before{content:\"\\f0d2\"}.fa-pinterest-square:before{content:\"\\f0d3\"}.fa-google-plus-square:before{content:\"\\f0d4\"}.fa-google-plus:before{content:\"\\f0d5\"}.fa-money:before{content:\"\\f0d6\"}.fa-caret-down:before{content:\"\\f0d7\"}.fa-caret-up:before{content:\"\\f0d8\"}.fa-caret-left:before{content:\"\\f0d9\"}.fa-caret-right:before{content:\"\\f0da\"}.fa-columns:before{content:\"\\f0db\"}.fa-unsorted:before,.fa-sort:before{content:\"\\f0dc\"}.fa-sort-down:before,.fa-sort-desc:before{content:\"\\f0dd\"}.fa-sort-up:before,.fa-sort-asc:before{content:\"\\f0de\"}.fa-envelope:before{content:\"\\f0e0\"}.fa-linkedin:before{content:\"\\f0e1\"}.fa-rotate-left:before,.fa-undo:before{content:\"\\f0e2\"}.fa-legal:before,.fa-gavel:before{content:\"\\f0e3\"}.fa-dashboard:before,.fa-tachometer:before{content:\"\\f0e4\"}.fa-comment-o:before{content:\"\\f0e5\"}.fa-comments-o:before{content:\"\\f0e6\"}.fa-flash:before,.fa-bolt:before{content:\"\\f0e7\"}.fa-sitemap:before{content:\"\\f0e8\"}.fa-umbrella:before{content:\"\\f0e9\"}.fa-paste:before,.fa-clipboard:before{content:\"\\f0ea\"}.fa-lightbulb-o:before{content:\"\\f0eb\"}.fa-exchange:before{content:\"\\f0ec\"}.fa-cloud-download:before{content:\"\\f0ed\"}.fa-cloud-upload:before{content:\"\\f0ee\"}.fa-user-md:before{content:\"\\f0f0\"}.fa-stethoscope:before{content:\"\\f0f1\"}.fa-suitcase:before{content:\"\\f0f2\"}.fa-bell-o:before{content:\"\\f0a2\"}.fa-coffee:before{content:\"\\f0f4\"}.fa-cutlery:before{content:\"\\f0f5\"}.fa-file-text-o:before{content:\"\\f0f6\"}.fa-building-o:before{content:\"\\f0f7\"}.fa-hospital-o:before{content:\"\\f0f8\"}.fa-ambulance:before{content:\"\\f0f9\"}.fa-medkit:before{content:\"\\f0fa\"}.fa-fighter-jet:before{content:\"\\f0fb\"}.fa-beer:before{content:\"\\f0fc\"}.fa-h-square:before{content:\"\\f0fd\"}.fa-plus-square:before{content:\"\\f0fe\"}.fa-angle-double-left:before{content:\"\\f100\"}.fa-angle-double-right:before{content:\"\\f101\"}.fa-angle-double-up:before{content:\"\\f102\"}.fa-angle-double-down:before{content:\"\\f103\"}.fa-angle-left:before{content:\"\\f104\"}.fa-angle-right:before{content:\"\\f105\"}.fa-angle-up:before{content:\"\\f106\"}.fa-angle-down:before{content:\"\\f107\"}.fa-desktop:before{content:\"\\f108\"}.fa-laptop:before{content:\"\\f109\"}.fa-tablet:before{content:\"\\f10a\"}.fa-mobile-phone:before,.fa-mobile:before{content:\"\\f10b\"}.fa-circle-o:before{content:\"\\f10c\"}.fa-quote-left:before{content:\"\\f10d\"}.fa-quote-right:before{content:\"\\f10e\"}.fa-spinner:before{content:\"\\f110\"}.fa-circle:before{content:\"\\f111\"}.fa-mail-reply:before,.fa-reply:before{content:\"\\f112\"}.fa-github-alt:before{content:\"\\f113\"}.fa-folder-o:before{content:\"\\f114\"}.fa-folder-open-o:before{content:\"\\f115\"}.fa-smile-o:before{content:\"\\f118\"}.fa-frown-o:before{content:\"\\f119\"}.fa-meh-o:before{content:\"\\f11a\"}.fa-gamepad:before{content:\"\\f11b\"}.fa-keyboard-o:before{content:\"\\f11c\"}.fa-flag-o:before{content:\"\\f11d\"}.fa-flag-checkered:before{content:\"\\f11e\"}.fa-terminal:before{content:\"\\f120\"}.fa-code:before{content:\"\\f121\"}.fa-mail-reply-all:before,.fa-reply-all:before{content:\"\\f122\"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:\"\\f123\"}.fa-location-arrow:before{content:\"\\f124\"}.fa-crop:before{content:\"\\f125\"}.fa-code-fork:before{content:\"\\f126\"}.fa-unlink:before,.fa-chain-broken:before{content:\"\\f127\"}.fa-question:before{content:\"\\f128\"}.fa-info:before{content:\"\\f129\"}.fa-exclamation:before{content:\"\\f12a\"}.fa-superscript:before{content:\"\\f12b\"}.fa-subscript:before{content:\"\\f12c\"}.fa-eraser:before{content:\"\\f12d\"}.fa-puzzle-piece:before{content:\"\\f12e\"}.fa-microphone:before{content:\"\\f130\"}.fa-microphone-slash:before{content:\"\\f131\"}.fa-shield:before{content:\"\\f132\"}.fa-calendar-o:before{content:\"\\f133\"}.fa-fire-extinguisher:before{content:\"\\f134\"}.fa-rocket:before{content:\"\\f135\"}.fa-maxcdn:before{content:\"\\f136\"}.fa-chevron-circle-left:before{content:\"\\f137\"}.fa-chevron-circle-right:before{content:\"\\f138\"}.fa-chevron-circle-up:before{content:\"\\f139\"}.fa-chevron-circle-down:before{content:\"\\f13a\"}.fa-html5:before{content:\"\\f13b\"}.fa-css3:before{content:\"\\f13c\"}.fa-anchor:before{content:\"\\f13d\"}.fa-unlock-alt:before{content:\"\\f13e\"}.fa-bullseye:before{content:\"\\f140\"}.fa-ellipsis-h:before{content:\"\\f141\"}.fa-ellipsis-v:before{content:\"\\f142\"}.fa-rss-square:before{content:\"\\f143\"}.fa-play-circle:before{content:\"\\f144\"}.fa-ticket:before{content:\"\\f145\"}.fa-minus-square:before{content:\"\\f146\"}.fa-minus-square-o:before{content:\"\\f147\"}.fa-level-up:before{content:\"\\f148\"}.fa-level-down:before{content:\"\\f149\"}.fa-check-square:before{content:\"\\f14a\"}.fa-pencil-square:before{content:\"\\f14b\"}.fa-external-link-square:before{content:\"\\f14c\"}.fa-share-square:before{content:\"\\f14d\"}.fa-compass:before{content:\"\\f14e\"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:\"\\f150\"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:\"\\f151\"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:\"\\f152\"}.fa-euro:before,.fa-eur:before{content:\"\\f153\"}.fa-gbp:before{content:\"\\f154\"}.fa-dollar:before,.fa-usd:before{content:\"\\f155\"}.fa-rupee:before,.fa-inr:before{content:\"\\f156\"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:\"\\f157\"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:\"\\f158\"}.fa-won:before,.fa-krw:before{content:\"\\f159\"}.fa-bitcoin:before,.fa-btc:before{content:\"\\f15a\"}.fa-file:before{content:\"\\f15b\"}.fa-file-text:before{content:\"\\f15c\"}.fa-sort-alpha-asc:before{content:\"\\f15d\"}.fa-sort-alpha-desc:before{content:\"\\f15e\"}.fa-sort-amount-asc:before{content:\"\\f160\"}.fa-sort-amount-desc:before{content:\"\\f161\"}.fa-sort-numeric-asc:before{content:\"\\f162\"}.fa-sort-numeric-desc:before{content:\"\\f163\"}.fa-thumbs-up:before{content:\"\\f164\"}.fa-thumbs-down:before{content:\"\\f165\"}.fa-youtube-square:before{content:\"\\f166\"}.fa-youtube:before{content:\"\\f167\"}.fa-xing:before{content:\"\\f168\"}.fa-xing-square:before{content:\"\\f169\"}.fa-youtube-play:before{content:\"\\f16a\"}.fa-dropbox:before{content:\"\\f16b\"}.fa-stack-overflow:before{content:\"\\f16c\"}.fa-instagram:before{content:\"\\f16d\"}.fa-flickr:before{content:\"\\f16e\"}.fa-adn:before{content:\"\\f170\"}.fa-bitbucket:before{content:\"\\f171\"}.fa-bitbucket-square:before{content:\"\\f172\"}.fa-tumblr:before{content:\"\\f173\"}.fa-tumblr-square:before{content:\"\\f174\"}.fa-long-arrow-down:before{content:\"\\f175\"}.fa-long-arrow-up:before{content:\"\\f176\"}.fa-long-arrow-left:before{content:\"\\f177\"}.fa-long-arrow-right:before{content:\"\\f178\"}.fa-apple:before{content:\"\\f179\"}.fa-windows:before{content:\"\\f17a\"}.fa-android:before{content:\"\\f17b\"}.fa-linux:before{content:\"\\f17c\"}.fa-dribbble:before{content:\"\\f17d\"}.fa-skype:before{content:\"\\f17e\"}.fa-foursquare:before{content:\"\\f180\"}.fa-trello:before{content:\"\\f181\"}.fa-female:before{content:\"\\f182\"}.fa-male:before{content:\"\\f183\"}.fa-gittip:before,.fa-gratipay:before{content:\"\\f184\"}.fa-sun-o:before{content:\"\\f185\"}.fa-moon-o:before{content:\"\\f186\"}.fa-archive:before{content:\"\\f187\"}.fa-bug:before{content:\"\\f188\"}.fa-vk:before{content:\"\\f189\"}.fa-weibo:before{content:\"\\f18a\"}.fa-renren:before{content:\"\\f18b\"}.fa-pagelines:before{content:\"\\f18c\"}.fa-stack-exchange:before{content:\"\\f18d\"}.fa-arrow-circle-o-right:before{content:\"\\f18e\"}.fa-arrow-circle-o-left:before{content:\"\\f190\"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:\"\\f191\"}.fa-dot-circle-o:before{content:\"\\f192\"}.fa-wheelchair:before{content:\"\\f193\"}.fa-vimeo-square:before{content:\"\\f194\"}.fa-turkish-lira:before,.fa-try:before{content:\"\\f195\"}.fa-plus-square-o:before{content:\"\\f196\"}.fa-space-shuttle:before{content:\"\\f197\"}.fa-slack:before{content:\"\\f198\"}.fa-envelope-square:before{content:\"\\f199\"}.fa-wordpress:before{content:\"\\f19a\"}.fa-openid:before{content:\"\\f19b\"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:\"\\f19c\"}.fa-mortar-board:before,.fa-graduation-cap:before{content:\"\\f19d\"}.fa-yahoo:before{content:\"\\f19e\"}.fa-google:before{content:\"\\f1a0\"}.fa-reddit:before{content:\"\\f1a1\"}.fa-reddit-square:before{content:\"\\f1a2\"}.fa-stumbleupon-circle:before{content:\"\\f1a3\"}.fa-stumbleupon:before{content:\"\\f1a4\"}.fa-delicious:before{content:\"\\f1a5\"}.fa-digg:before{content:\"\\f1a6\"}.fa-pied-piper:before{content:\"\\f1a7\"}.fa-pied-piper-alt:before{content:\"\\f1a8\"}.fa-drupal:before{content:\"\\f1a9\"}.fa-joomla:before{content:\"\\f1aa\"}.fa-language:before{content:\"\\f1ab\"}.fa-fax:before{content:\"\\f1ac\"}.fa-building:before{content:\"\\f1ad\"}.fa-child:before{content:\"\\f1ae\"}.fa-paw:before{content:\"\\f1b0\"}.fa-spoon:before{content:\"\\f1b1\"}.fa-cube:before{content:\"\\f1b2\"}.fa-cubes:before{content:\"\\f1b3\"}.fa-behance:before{content:\"\\f1b4\"}.fa-behance-square:before{content:\"\\f1b5\"}.fa-steam:before{content:\"\\f1b6\"}.fa-steam-square:before{content:\"\\f1b7\"}.fa-recycle:before{content:\"\\f1b8\"}.fa-automobile:before,.fa-car:before{content:\"\\f1b9\"}.fa-cab:before,.fa-taxi:before{content:\"\\f1ba\"}.fa-tree:before{content:\"\\f1bb\"}.fa-spotify:before{content:\"\\f1bc\"}.fa-deviantart:before{content:\"\\f1bd\"}.fa-soundcloud:before{content:\"\\f1be\"}.fa-database:before{content:\"\\f1c0\"}.fa-file-pdf-o:before{content:\"\\f1c1\"}.fa-file-word-o:before{content:\"\\f1c2\"}.fa-file-excel-o:before{content:\"\\f1c3\"}.fa-file-powerpoint-o:before{content:\"\\f1c4\"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:\"\\f1c5\"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:\"\\f1c6\"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:\"\\f1c7\"}.fa-file-movie-o:before,.fa-file-video-o:before{content:\"\\f1c8\"}.fa-file-code-o:before{content:\"\\f1c9\"}.fa-vine:before{content:\"\\f1ca\"}.fa-codepen:before{content:\"\\f1cb\"}.fa-jsfiddle:before{content:\"\\f1cc\"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:\"\\f1cd\"}.fa-circle-o-notch:before{content:\"\\f1ce\"}.fa-ra:before,.fa-rebel:before{content:\"\\f1d0\"}.fa-ge:before,.fa-empire:before{content:\"\\f1d1\"}.fa-git-square:before{content:\"\\f1d2\"}.fa-git:before{content:\"\\f1d3\"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:\"\\f1d4\"}.fa-tencent-weibo:before{content:\"\\f1d5\"}.fa-qq:before{content:\"\\f1d6\"}.fa-wechat:before,.fa-weixin:before{content:\"\\f1d7\"}.fa-send:before,.fa-paper-plane:before{content:\"\\f1d8\"}.fa-send-o:before,.fa-paper-plane-o:before{content:\"\\f1d9\"}.fa-history:before{content:\"\\f1da\"}.fa-circle-thin:before{content:\"\\f1db\"}.fa-header:before{content:\"\\f1dc\"}.fa-paragraph:before{content:\"\\f1dd\"}.fa-sliders:before{content:\"\\f1de\"}.fa-share-alt:before{content:\"\\f1e0\"}.fa-share-alt-square:before{content:\"\\f1e1\"}.fa-bomb:before{content:\"\\f1e2\"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:\"\\f1e3\"}.fa-tty:before{content:\"\\f1e4\"}.fa-binoculars:before{content:\"\\f1e5\"}.fa-plug:before{content:\"\\f1e6\"}.fa-slideshare:before{content:\"\\f1e7\"}.fa-twitch:before{content:\"\\f1e8\"}.fa-yelp:before{content:\"\\f1e9\"}.fa-newspaper-o:before{content:\"\\f1ea\"}.fa-wifi:before{content:\"\\f1eb\"}.fa-calculator:before{content:\"\\f1ec\"}.fa-paypal:before{content:\"\\f1ed\"}.fa-google-wallet:before{content:\"\\f1ee\"}.fa-cc-visa:before{content:\"\\f1f0\"}.fa-cc-mastercard:before{content:\"\\f1f1\"}.fa-cc-discover:before{content:\"\\f1f2\"}.fa-cc-amex:before{content:\"\\f1f3\"}.fa-cc-paypal:before{content:\"\\f1f4\"}.fa-cc-stripe:before{content:\"\\f1f5\"}.fa-bell-slash:before{content:\"\\f1f6\"}.fa-bell-slash-o:before{content:\"\\f1f7\"}.fa-trash:before{content:\"\\f1f8\"}.fa-copyright:before{content:\"\\f1f9\"}.fa-at:before{content:\"\\f1fa\"}.fa-eyedropper:before{content:\"\\f1fb\"}.fa-paint-brush:before{content:\"\\f1fc\"}.fa-birthday-cake:before{content:\"\\f1fd\"}.fa-area-chart:before{content:\"\\f1fe\"}.fa-pie-chart:before{content:\"\\f200\"}.fa-line-chart:before{content:\"\\f201\"}.fa-lastfm:before{content:\"\\f202\"}.fa-lastfm-square:before{content:\"\\f203\"}.fa-toggle-off:before{content:\"\\f204\"}.fa-toggle-on:before{content:\"\\f205\"}.fa-bicycle:before{content:\"\\f206\"}.fa-bus:before{content:\"\\f207\"}.fa-ioxhost:before{content:\"\\f208\"}.fa-angellist:before{content:\"\\f209\"}.fa-cc:before{content:\"\\f20a\"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:\"\\f20b\"}.fa-meanpath:before{content:\"\\f20c\"}.fa-buysellads:before{content:\"\\f20d\"}.fa-connectdevelop:before{content:\"\\f20e\"}.fa-dashcube:before{content:\"\\f210\"}.fa-forumbee:before{content:\"\\f211\"}.fa-leanpub:before{content:\"\\f212\"}.fa-sellsy:before{content:\"\\f213\"}.fa-shirtsinbulk:before{content:\"\\f214\"}.fa-simplybuilt:before{content:\"\\f215\"}.fa-skyatlas:before{content:\"\\f216\"}.fa-cart-plus:before{content:\"\\f217\"}.fa-cart-arrow-down:before{content:\"\\f218\"}.fa-diamond:before{content:\"\\f219\"}.fa-ship:before{content:\"\\f21a\"}.fa-user-secret:before{content:\"\\f21b\"}.fa-motorcycle:before{content:\"\\f21c\"}.fa-street-view:before{content:\"\\f21d\"}.fa-heartbeat:before{content:\"\\f21e\"}.fa-venus:before{content:\"\\f221\"}.fa-mars:before{content:\"\\f222\"}.fa-mercury:before{content:\"\\f223\"}.fa-intersex:before,.fa-transgender:before{content:\"\\f224\"}.fa-transgender-alt:before{content:\"\\f225\"}.fa-venus-double:before{content:\"\\f226\"}.fa-mars-double:before{content:\"\\f227\"}.fa-venus-mars:before{content:\"\\f228\"}.fa-mars-stroke:before{content:\"\\f229\"}.fa-mars-stroke-v:before{content:\"\\f22a\"}.fa-mars-stroke-h:before{content:\"\\f22b\"}.fa-neuter:before{content:\"\\f22c\"}.fa-genderless:before{content:\"\\f22d\"}.fa-facebook-official:before{content:\"\\f230\"}.fa-pinterest-p:before{content:\"\\f231\"}.fa-whatsapp:before{content:\"\\f232\"}.fa-server:before{content:\"\\f233\"}.fa-user-plus:before{content:\"\\f234\"}.fa-user-times:before{content:\"\\f235\"}.fa-hotel:before,.fa-bed:before{content:\"\\f236\"}.fa-viacoin:before{content:\"\\f237\"}.fa-train:before{content:\"\\f238\"}.fa-subway:before{content:\"\\f239\"}.fa-medium:before{content:\"\\f23a\"}.fa-yc:before,.fa-y-combinator:before{content:\"\\f23b\"}.fa-optin-monster:before{content:\"\\f23c\"}.fa-opencart:before{content:\"\\f23d\"}.fa-expeditedssl:before{content:\"\\f23e\"}.fa-battery-4:before,.fa-battery-full:before{content:\"\\f240\"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:\"\\f241\"}.fa-battery-2:before,.fa-battery-half:before{content:\"\\f242\"}.fa-battery-1:before,.fa-battery-quarter:before{content:\"\\f243\"}.fa-battery-0:before,.fa-battery-empty:before{content:\"\\f244\"}.fa-mouse-pointer:before{content:\"\\f245\"}.fa-i-cursor:before{content:\"\\f246\"}.fa-object-group:before{content:\"\\f247\"}.fa-object-ungroup:before{content:\"\\f248\"}.fa-sticky-note:before{content:\"\\f249\"}.fa-sticky-note-o:before{content:\"\\f24a\"}.fa-cc-jcb:before{content:\"\\f24b\"}.fa-cc-diners-club:before{content:\"\\f24c\"}.fa-clone:before{content:\"\\f24d\"}.fa-balance-scale:before{content:\"\\f24e\"}.fa-hourglass-o:before{content:\"\\f250\"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:\"\\f251\"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:\"\\f252\"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:\"\\f253\"}.fa-hourglass:before{content:\"\\f254\"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:\"\\f255\"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:\"\\f256\"}.fa-hand-scissors-o:before{content:\"\\f257\"}.fa-hand-lizard-o:before{content:\"\\f258\"}.fa-hand-spock-o:before{content:\"\\f259\"}.fa-hand-pointer-o:before{content:\"\\f25a\"}.fa-hand-peace-o:before{content:\"\\f25b\"}.fa-trademark:before{content:\"\\f25c\"}.fa-registered:before{content:\"\\f25d\"}.fa-creative-commons:before{content:\"\\f25e\"}.fa-gg:before{content:\"\\f260\"}.fa-gg-circle:before{content:\"\\f261\"}.fa-tripadvisor:before{content:\"\\f262\"}.fa-odnoklassniki:before{content:\"\\f263\"}.fa-odnoklassniki-square:before{content:\"\\f264\"}.fa-get-pocket:before{content:\"\\f265\"}.fa-wikipedia-w:before{content:\"\\f266\"}.fa-safari:before{content:\"\\f267\"}.fa-chrome:before{content:\"\\f268\"}.fa-firefox:before{content:\"\\f269\"}.fa-opera:before{content:\"\\f26a\"}.fa-internet-explorer:before{content:\"\\f26b\"}.fa-tv:before,.fa-television:before{content:\"\\f26c\"}.fa-contao:before{content:\"\\f26d\"}.fa-500px:before{content:\"\\f26e\"}.fa-amazon:before{content:\"\\f270\"}.fa-calendar-plus-o:before{content:\"\\f271\"}.fa-calendar-minus-o:before{content:\"\\f272\"}.fa-calendar-times-o:before{content:\"\\f273\"}.fa-calendar-check-o:before{content:\"\\f274\"}.fa-industry:before{content:\"\\f275\"}.fa-map-pin:before{content:\"\\f276\"}.fa-map-signs:before{content:\"\\f277\"}.fa-map-o:before{content:\"\\f278\"}.fa-map:before{content:\"\\f279\"}.fa-commenting:before{content:\"\\f27a\"}.fa-commenting-o:before{content:\"\\f27b\"}.fa-houzz:before{content:\"\\f27c\"}.fa-vimeo:before{content:\"\\f27d\"}.fa-black-tie:before{content:\"\\f27e\"}.fa-fonticons:before{content:\"\\f280\"}.fa-reddit-alien:before{content:\"\\f281\"}.fa-edge:before{content:\"\\f282\"}.fa-credit-card-alt:before{content:\"\\f283\"}.fa-codiepie:before{content:\"\\f284\"}.fa-modx:before{content:\"\\f285\"}.fa-fort-awesome:before{content:\"\\f286\"}.fa-usb:before{content:\"\\f287\"}.fa-product-hunt:before{content:\"\\f288\"}.fa-mixcloud:before{content:\"\\f289\"}.fa-scribd:before{content:\"\\f28a\"}.fa-pause-circle:before{content:\"\\f28b\"}.fa-pause-circle-o:before{content:\"\\f28c\"}.fa-stop-circle:before{content:\"\\f28d\"}.fa-stop-circle-o:before{content:\"\\f28e\"}.fa-shopping-bag:before{content:\"\\f290\"}.fa-shopping-basket:before{content:\"\\f291\"}.fa-hashtag:before{content:\"\\f292\"}.fa-bluetooth:before{content:\"\\f293\"}.fa-bluetooth-b:before{content:\"\\f294\"}.fa-percent:before{content:\"\\f295\"}\n"
  },
  {
    "path": "kivystudio/tools/iconfonts/test/font-awesome.fontd",
    "content": "{\"fa-camera\": 61488, \"fa-building-o\": 61687, \"fa-align-left\": 61494, \"fa-hand-o-up\": 61606, \"fa-external-link-square\": 61772, \"fa-cubes\": 61875, \"fa-get-pocket\": 62053, \"fa-share-alt-square\": 61921, \"fa-comment-o\": 61669, \"fa-thumbs-o-down\": 61576, \"fa-heart\": 61444, \"fa-file-photo-o\": 61893, \"fa-list\": 61498, \"fa-calendar-o\": 61747, \"fa-euro\": 61779, \"fa-life-buoy\": 61901, \"fa-stethoscope\": 61681, \"fa-bookmark\": 61486, \"fa-barcode\": 61482, \"fa-th-large\": 61449, \"fa-square\": 61640, \"fa-bank\": 61852, \"fa-times-circle-o\": 61532, \"fa-tachometer\": 61668, \"fa-bell-o\": 61602, \"fa-leaf\": 61548, \"fa-skype\": 61822, \"fa-certificate\": 61603, \"fa-car\": 61881, \"fa-ship\": 61978, \"fa-navicon\": 61641, \"fa-arrows-alt\": 61618, \"fa-server\": 62003, \"fa-cab\": 61882, \"fa-clone\": 62029, \"fa-wifi\": 61931, \"fa-meanpath\": 61964, \"fa-send-o\": 61913, \"fa-subscript\": 61740, \"fa-shirtsinbulk\": 61972, \"fa-sticky-note\": 62025, \"fa-road\": 61464, \"fa-times-circle\": 61527, \"fa-cart-arrow-down\": 61976, \"fa-safari\": 62055, \"fa-file-code-o\": 61897, \"fa-tty\": 61924, \"fa-list-ul\": 61642, \"fa-shopping-basket\": 62097, \"fa-arrow-circle-o-down\": 61466, \"fa-file-movie-o\": 61896, \"fa-slideshare\": 61927, \"fa-toggle-left\": 61841, \"fa-circle-o-notch\": 61902, \"fa-check-circle\": 61528, \"fa-mars-stroke-h\": 61995, \"fa-chevron-circle-up\": 61753, \"fa-circle\": 61713, \"fa-y-combinator-square\": 61908, \"fa-gbp\": 61780, \"fa-umbrella\": 61673, \"fa-sort-numeric-asc\": 61794, \"fa-pencil-square\": 61771, \"fa-soccer-ball-o\": 61923, \"fa-bicycle\": 61958, \"fa-user-times\": 62005, \"fa-trash-o\": 61460, \"fa-recycle\": 61880, \"fa-bell-slash-o\": 61943, \"fa-share-square-o\": 61509, \"fa-yc-square\": 61908, \"fa-users\": 61632, \"fa-yen\": 61783, \"fa-unlink\": 61735, \"fa-ban\": 61534, \"fa-sort-amount-asc\": 61792, \"fa-film\": 61448, \"fa-caret-down\": 61655, \"fa-file-text\": 61788, \"fa-list-alt\": 61474, \"fa-th-list\": 61451, \"fa-life-ring\": 61901, \"fa-filter\": 61616, \"fa-bluetooth-b\": 62100, \"fa-caret-up\": 61656, \"fa-sign-out\": 61579, \"fa-pencil\": 61504, \"fa-ticket\": 61765, \"fa-area-chart\": 61950, \"fa-skyatlas\": 61974, \"fa-opencart\": 62013, \"fa-hand-o-left\": 61605, \"fa-dedent\": 61499, \"fa-html5\": 61755, \"fa-at\": 61946, \"fa-dropbox\": 61803, \"fa-file-zip-o\": 61894, \"fa-long-arrow-up\": 61814, \"fa-stack-overflow\": 61804, \"fa-product-hunt\": 62088, \"fa-chevron-circle-left\": 61751, \"fa-check-square\": 61770, \"fa-cloud-download\": 61677, \"fa-caret-square-o-down\": 61776, \"fa-microphone-slash\": 61745, \"fa-folder\": 61563, \"fa-keyboard-o\": 61724, \"fa-bar-chart-o\": 61568, \"fa-transgender-alt\": 61989, \"fa-reddit-alien\": 62081, \"fa-openid\": 61851, \"fa-sort-asc\": 61662, \"fa-pause-circle\": 62091, \"fa-archive\": 61831, \"fa-eraser\": 61741, \"fa-cart-plus\": 61975, \"fa-inbox\": 61468, \"fa-truck\": 61649, \"fa-file-word-o\": 61890, \"fa-pied-piper-alt\": 61864, \"fa-object-ungroup\": 62024, \"fa-phone-square\": 61592, \"fa-eye\": 61550, \"fa-sun-o\": 61829, \"fa-folder-o\": 61716, \"fa-rebel\": 61904, \"fa-bars\": 61641, \"fa-cc-paypal\": 61940, \"fa-simplybuilt\": 61973, \"fa-won\": 61785, \"fa-hand-lizard-o\": 62040, \"fa-balance-scale\": 62030, \"fa-frown-o\": 61721, \"fa-repeat\": 61470, \"fa-arrow-circle-o-up\": 61467, \"fa-taxi\": 61882, \"fa-map-o\": 62072, \"fa-question\": 61736, \"fa-meh-o\": 61722, \"fa-terminal\": 61728, \"fa-caret-left\": 61657, \"fa-stop\": 61517, \"fa-tv\": 62060, \"fa-spoon\": 61873, \"fa-th\": 61450, \"fa-files-o\": 61637, \"fa-pause\": 61516, \"fa-mail-reply\": 61714, \"fa-cutlery\": 61685, \"fa-linux\": 61820, \"fa-battery-empty\": 62020, \"fa-hourglass-start\": 62033, \"fa-pause-circle-o\": 62092, \"fa-arrow-circle-left\": 61608, \"fa-shopping-cart\": 61562, \"fa-map-pin\": 62070, \"fa-youtube-play\": 61802, \"fa-drupal\": 61865, \"fa-bed\": 62006, \"fa-battery-quarter\": 62019, \"fa-weixin\": 61911, \"fa-exchange\": 61676, \"fa-gg-circle\": 62049, \"fa-angle-double-up\": 61698, \"fa-forward\": 61518, \"fa-hand-pointer-o\": 62042, \"fa-cog\": 61459, \"fa-reddit-square\": 61858, \"fa-arrow-circle-down\": 61611, \"fa-battery-three-quarters\": 62017, \"fa-venus-double\": 61990, \"fa-tumblr-square\": 61812, \"fa-angellist\": 61961, \"fa-toggle-off\": 61956, \"fa-info\": 61737, \"fa-eyedropper\": 61947, \"fa-behance\": 61876, \"fa-map-signs\": 62071, \"fa-file-audio-o\": 61895, \"fa-gavel\": 61667, \"fa-glass\": 61440, \"fa-hand-o-right\": 61604, \"fa-cube\": 61874, \"fa-pinterest-square\": 61651, \"fa-cc-stripe\": 61941, \"fa-battery-full\": 62016, \"fa-lightbulb-o\": 61675, \"fa-caret-square-o-up\": 61777, \"fa-video-camera\": 61501, \"fa-jsfiddle\": 61900, \"fa-long-arrow-left\": 61815, \"fa-caret-right\": 61658, \"fa-volume-down\": 61479, \"fa-tags\": 61484, \"fa-arrow-up\": 61538, \"fa-folder-open-o\": 61717, \"fa-shield\": 61746, \"fa-dashcube\": 61968, \"fa-rotate-right\": 61470, \"fa-angle-double-down\": 61699, \"fa-facebook\": 61594, \"fa-hand-scissors-o\": 62039, \"fa-scribd\": 62090, \"fa-sort\": 61660, \"fa-twitter-square\": 61569, \"fa-power-off\": 61457, \"fa-gratipay\": 61828, \"fa-mars\": 61986, \"fa-header\": 61916, \"fa-user\": 61447, \"fa-exclamation-circle\": 61546, \"fa-level-down\": 61769, \"fa-vine\": 61898, \"fa-tint\": 61507, \"fa-wordpress\": 61850, \"fa-expeditedssl\": 62014, \"fa-slack\": 61848, \"fa-cut\": 61636, \"fa-key\": 61572, \"fa-tripadvisor\": 62050, \"fa-opera\": 62058, \"fa-object-group\": 62023, \"fa-heartbeat\": 61982, \"fa-laptop\": 61705, \"fa-bomb\": 61922, \"fa-angle-double-left\": 61696, \"fa-quote-left\": 61709, \"fa-paw\": 61872, \"fa-reddit\": 61857, \"fa-cc-visa\": 61936, \"fa-circle-o\": 61708, \"fa-odnoklassniki-square\": 62052, \"fa-cc-jcb\": 62027, \"fa-mail-reply-all\": 61730, \"fa-lastfm\": 61954, \"fa-group\": 61632, \"fa-microphone\": 61744, \"fa-camera-retro\": 61571, \"fa-maxcdn\": 61750, \"fa-buysellads\": 61965, \"fa-play-circle-o\": 61469, \"fa-ge\": 61905, \"fa-i-cursor\": 62022, \"fa-percent\": 62101, \"fa-photo\": 61502, \"fa-toggle-on\": 61957, \"fa-fax\": 61868, \"fa-code-fork\": 61734, \"fa-y-combinator\": 62011, \"fa-map\": 62073, \"fa-try\": 61845, \"fa-diamond\": 61977, \"fa-neuter\": 61996, \"fa-quote-right\": 61710, \"fa-mobile\": 61707, \"fa-bell-slash\": 61942, \"fa-trademark\": 62044, \"fa-file-video-o\": 61896, \"fa-mixcloud\": 62089, \"fa-plus-circle\": 61525, \"fa-folder-open\": 61564, \"fa-css3\": 61756, \"fa-fast-forward\": 61520, \"fa-toggle-down\": 61776, \"fa-credit-card\": 61597, \"fa-caret-square-o-left\": 61841, \"fa-hourglass-3\": 62035, \"fa-hourglass-2\": 62034, \"fa-hourglass-1\": 62033, \"fa-angle-down\": 61703, \"fa-edge\": 62082, \"fa-trello\": 61825, \"fa-train\": 62008, \"fa-sheqel\": 61963, \"fa-file-powerpoint-o\": 61892, \"fa-arrow-left\": 61536, \"fa-television\": 62060, \"fa-life-saver\": 61901, \"fa-copy\": 61637, \"fa-sticky-note-o\": 62026, \"fa-mars-double\": 61991, \"fa-star-half-o\": 61731, \"fa-black-tie\": 62078, \"fa-chevron-up\": 61559, \"fa-chevron-down\": 61560, \"fa-fonticons\": 62080, \"fa-check-circle-o\": 61533, \"fa-plug\": 61926, \"fa-deviantart\": 61885, \"fa-dashboard\": 61668, \"fa-hourglass-o\": 62032, \"fa-plus\": 61543, \"fa-cc-discover\": 61938, \"fa-hashtag\": 62098, \"fa-gamepad\": 61723, \"fa-rub\": 61784, \"fa-history\": 61914, \"fa-sign-in\": 61584, \"fa-sort-amount-desc\": 61793, \"fa-rss-square\": 61763, \"fa-transgender\": 61988, \"fa-graduation-cap\": 61853, \"fa-whatsapp\": 62002, \"fa-mercury\": 61987, \"fa-amazon\": 62064, \"fa-medkit\": 61690, \"fa-bug\": 61832, \"fa-twitch\": 61928, \"fa-file-archive-o\": 61894, \"fa-forumbee\": 61969, \"fa-cny\": 61783, \"fa-arrows\": 61511, \"fa-map-marker\": 61505, \"fa-wheelchair\": 61843, \"fa-plus-square\": 61694, \"fa-male\": 61827, \"fa-institution\": 61852, \"fa-envelope-o\": 61443, \"fa-xing-square\": 61801, \"fa-step-forward\": 61521, \"fa-stumbleupon-circle\": 61859, \"fa-pencil-square-o\": 61508, \"fa-weibo\": 61834, \"fa-gear\": 61459, \"fa-rocket\": 61749, \"fa-bluetooth\": 62099, \"fa-search-plus\": 61454, \"fa-stop-circle\": 62093, \"fa-bell\": 61683, \"fa-undo\": 61666, \"fa-fast-backward\": 61513, \"fa-sliders\": 61918, \"fa-hotel\": 62006, \"fa-steam\": 61878, \"fa-hand-paper-o\": 62038, \"fa-circle-thin\": 61915, \"fa-share-square\": 61773, \"fa-asterisk\": 61545, \"fa-arrow-down\": 61539, \"fa-random\": 61556, \"fa-share-alt\": 61920, \"fa-beer\": 61692, \"fa-exclamation-triangle\": 61553, \"fa-commenting\": 62074, \"fa-volume-up\": 61480, \"fa-flag-checkered\": 61726, \"fa-ellipsis-h\": 61761, \"fa-hand-spock-o\": 62041, \"fa-crop\": 61733, \"fa-paragraph\": 61917, \"fa-battery-3\": 62017, \"fa-ellipsis-v\": 61762, \"fa-gift\": 61547, \"fa-strikethrough\": 61644, \"fa-motorcycle\": 61980, \"fa-life-bouy\": 61901, \"fa-reply-all\": 61730, \"fa-paper-plane-o\": 61913, \"fa-star-half\": 61577, \"fa-download\": 61465, \"fa-usb\": 62087, \"fa-chevron-circle-down\": 61754, \"fa-calculator\": 61932, \"fa-gg\": 62048, \"fa-contao\": 62061, \"fa-hand-o-down\": 61607, \"fa-leanpub\": 61970, \"fa-star-o\": 61446, \"fa-pie-chart\": 61952, \"fa-venus\": 61985, \"fa-inr\": 61782, \"fa-rupee\": 61782, \"fa-eur\": 61779, \"fa-tumblr\": 61811, \"fa-indent\": 61500, \"fa-mars-stroke-v\": 61994, \"fa-git\": 61907, \"fa-envelope\": 61664, \"fa-bitbucket-square\": 61810, \"fa-legal\": 61667, \"fa-gittip\": 61828, \"fa-chevron-left\": 61523, \"fa-cogs\": 61573, \"fa-arrow-circle-o-left\": 61840, \"fa-briefcase\": 61617, \"fa-user-md\": 61680, \"fa-angle-left\": 61700, \"fa-yc\": 62011, \"fa-long-arrow-right\": 61816, \"fa-coffee\": 61684, \"fa-copyright\": 61945, \"fa-toggle-up\": 61777, \"fa-support\": 61901, \"fa-youtube-square\": 61798, \"fa-cc-mastercard\": 61937, \"fa-unsorted\": 61660, \"fa-compress\": 61542, \"fa-android\": 61819, \"fa-font\": 61489, \"fa-arrow-right\": 61537, \"fa-minus\": 61544, \"fa-bitbucket\": 61809, \"fa-facebook-f\": 61594, \"fa-subway\": 62009, \"fa-headphones\": 61477, \"fa-paperclip\": 61638, \"fa-industry\": 62069, \"fa-rmb\": 61783, \"fa-minus-square\": 61766, \"fa-moon-o\": 61830, \"fa-file-excel-o\": 61891, \"fa-line-chart\": 61953, \"fa-fighter-jet\": 61691, \"fa-sort-alpha-desc\": 61790, \"fa-spotify\": 61884, \"fa-star-half-empty\": 61731, \"fa-share\": 61540, \"fa-comment\": 61557, \"fa-mars-stroke\": 61993, \"fa-stack-exchange\": 61837, \"fa-pied-piper\": 61863, \"fa-building\": 61869, \"fa-thumbs-up\": 61796, \"fa-chevron-circle-right\": 61752, \"fa-adjust\": 61506, \"fa-sellsy\": 61971, \"fa-paypal\": 61933, \"fa-signal\": 61458, \"fa-sort-up\": 61662, \"fa-shekel\": 61963, \"fa-codiepie\": 62084, \"fa-calendar-plus-o\": 62065, \"fa-digg\": 61862, \"fa-save\": 61639, \"fa-shopping-bag\": 62096, \"fa-eye-slash\": 61552, \"fa-backward\": 61514, \"fa-hand-stop-o\": 62038, \"fa-mail-forward\": 61540, \"fa-link\": 61633, \"fa-table\": 61646, \"fa-tag\": 61483, \"fa-turkish-lira\": 61845, \"fa-envelope-square\": 61849, \"fa-optin-monster\": 62012, \"fa-money\": 61654, \"fa-instagram\": 61805, \"fa-volume-off\": 61478, \"fa-unlock-alt\": 61758, \"fa-minus-circle\": 61526, \"fa-hacker-news\": 61908, \"fa-hand-grab-o\": 62037, \"fa-adn\": 61808, \"fa-list-ol\": 61643, \"fa-magnet\": 61558, \"fa-calendar-minus-o\": 62066, \"fa-linkedin\": 61665, \"fa-paper-plane\": 61912, \"fa-mouse-pointer\": 62021, \"fa-reply\": 61714, \"fa-smile-o\": 61720, \"fa-hourglass-half\": 62034, \"fa-behance-square\": 61877, \"fa-twitter\": 61593, \"fa-expand\": 61541, \"fa-flask\": 61635, \"fa-flash\": 61671, \"fa-trophy\": 61585, \"fa-long-arrow-down\": 61813, \"fa-odnoklassniki\": 62051, \"fa-angle-double-right\": 61697, \"fa-home\": 61461, \"fa-bolt\": 61671, \"fa-italic\": 61491, \"fa-comments\": 61574, \"fa-commenting-o\": 62075, \"fa-toggle-right\": 61778, \"fa-file\": 61787, \"fa-bold\": 61490, \"fa-internet-explorer\": 62059, \"fa-cc-amex\": 61939, \"fa-sort-down\": 61661, \"fa-anchor\": 61757, \"fa-medium\": 62010, \"fa-calendar\": 61555, \"fa-superscript\": 61739, \"fa-wechat\": 61911, \"fa-file-text-o\": 61686, \"fa-cloud\": 61634, \"fa-user-plus\": 62004, \"fa-times\": 61453, \"fa-street-view\": 61981, \"fa-trash\": 61944, \"fa-paste\": 61674, \"fa-ambulance\": 61689, \"fa-suitcase\": 61682, \"fa-binoculars\": 61925, \"fa-user-secret\": 61979, \"fa-sort-alpha-asc\": 61789, \"fa-picture-o\": 61502, \"fa-cc\": 61962, \"fa-calendar-times-o\": 62067, \"fa-phone\": 61589, \"fa-github-square\": 61586, \"fa-hand-peace-o\": 62043, \"fa-windows\": 61818, \"fa-500px\": 62062, \"fa-calendar-check-o\": 62068, \"fa-clock-o\": 61463, \"fa-connectdevelop\": 61966, \"fa-text-height\": 61492, \"fa-houzz\": 62076, \"fa-align-right\": 61496, \"fa-angle-right\": 61701, \"fa-hand-rock-o\": 62037, \"fa-heart-o\": 61578, \"fa-steam-square\": 61879, \"fa-underline\": 61645, \"fa-file-image-o\": 61893, \"fa-bus\": 61959, \"fa-play-circle\": 61764, \"fa-plus-square-o\": 61846, \"fa-rss\": 61598, \"fa-battery-0\": 62020, \"fa-battery-1\": 62019, \"fa-battery-2\": 62018, \"fa-google-plus-square\": 61652, \"fa-battery-4\": 62016, \"fa-caret-square-o-right\": 61778, \"fa-child\": 61870, \"fa-space-shuttle\": 61847, \"fa-pinterest-p\": 62001, \"fa-outdent\": 61499, \"fa-lock\": 61475, \"fa-dot-circle-o\": 61842, \"fa-git-square\": 61906, \"fa-clipboard\": 61674, \"fa-mortar-board\": 61853, \"fa-university\": 61852, \"fa-github\": 61595, \"fa-jpy\": 61783, \"fa-vk\": 61833, \"fa-print\": 61487, \"fa-code\": 61729, \"fa-book\": 61485, \"fa-pinterest\": 61650, \"fa-youtube\": 61799, \"fa-fire\": 61549, \"fa-hourglass-end\": 62035, \"fa-tasks\": 61614, \"fa-xing\": 61800, \"fa-ioxhost\": 61960, \"fa-play\": 61515, \"fa-flag-o\": 61725, \"fa-battery-half\": 62018, \"fa-search\": 61442, \"fa-genderless\": 61997, \"fa-renren\": 61835, \"fa-database\": 61888, \"fa-plane\": 61554, \"fa-sort-numeric-desc\": 61795, \"fa-intersex\": 61988, \"fa-tree\": 61883, \"fa-scissors\": 61636, \"fa-question-circle\": 61529, \"fa-close\": 61453, \"fa-crosshairs\": 61531, \"fa-apple\": 61817, \"fa-wrench\": 61613, \"fa-sitemap\": 61672, \"fa-language\": 61867, \"fa-automobile\": 61881, \"fa-hourglass\": 62036, \"fa-bar-chart\": 61568, \"fa-file-o\": 61462, \"fa-krw\": 61785, \"fa-soundcloud\": 61886, \"fa-floppy-o\": 61639, \"fa-upload\": 61587, \"fa-arrow-circle-o-right\": 61838, \"fa-info-circle\": 61530, \"fa-cloud-upload\": 61678, \"fa-facebook-official\": 62000, \"fa-search-minus\": 61456, \"fa-music\": 61441, \"fa-stumbleupon\": 61860, \"fa-star-half-full\": 61731, \"fa-file-picture-o\": 61893, \"fa-image\": 61502, \"fa-mobile-phone\": 61707, \"fa-dollar\": 61781, \"fa-google-wallet\": 61934, \"fa-feed\": 61598, \"fa-vimeo\": 62077, \"fa-futbol-o\": 61923, \"fa-hdd-o\": 61600, \"fa-remove\": 61453, \"fa-bullseye\": 61760, \"fa-location-arrow\": 61732, \"fa-female\": 61826, \"fa-joomla\": 61866, \"fa-thumb-tack\": 61581, \"fa-align-justify\": 61497, \"fa-external-link\": 61582, \"fa-arrow-circle-right\": 61609, \"fa-level-up\": 61768, \"fa-gears\": 61573, \"fa-foursquare\": 61824, \"fa-venus-mars\": 61992, \"fa-yelp\": 61929, \"fa-exclamation\": 61738, \"fa-star\": 61445, \"fa-google-plus\": 61653, \"fa-ra\": 61904, \"fa-h-square\": 61693, \"fa-lastfm-square\": 61955, \"fa-registered\": 62045, \"fa-edit\": 61508, \"fa-unlock\": 61596, \"fa-sort-desc\": 61661, \"fa-tencent-weibo\": 61909, \"fa-thumbs-down\": 61797, \"fa-eject\": 61522, \"fa-linkedin-square\": 61580, \"fa-pagelines\": 61836, \"fa-chain\": 61633, \"fa-yahoo\": 61854, \"fa-send\": 61912, \"fa-check\": 61452, \"fa-compass\": 61774, \"fa-viacoin\": 62007, \"fa-angle-up\": 61702, \"fa-wikipedia-w\": 62054, \"fa-qrcode\": 61481, \"fa-paint-brush\": 61948, \"fa-bookmark-o\": 61591, \"fa-usd\": 61781, \"fa-chevron-right\": 61524, \"fa-ruble\": 61784, \"fa-delicious\": 61861, \"fa-btc\": 61786, \"fa-lemon-o\": 61588, \"fa-arrow-circle-up\": 61610, \"fa-comments-o\": 61670, \"fa-chrome\": 62056, \"fa-check-square-o\": 61510, \"fa-ils\": 61963, \"fa-birthday-cake\": 61949, \"fa-tablet\": 61706, \"fa-codepen\": 61899, \"fa-stop-circle-o\": 62094, \"fa-chain-broken\": 61735, \"fa-puzzle-piece\": 61742, \"fa-creative-commons\": 62046, \"fa-spinner\": 61712, \"fa-newspaper-o\": 61930, \"fa-globe\": 61612, \"fa-firefox\": 62057, \"fa-vimeo-square\": 61844, \"fa-magic\": 61648, \"fa-align-center\": 61495, \"fa-warning\": 61553, \"fa-desktop\": 61704, \"fa-cc-diners-club\": 62028, \"fa-thumbs-o-up\": 61575, \"fa-dribbble\": 61821, \"fa-square-o\": 61590, \"fa-columns\": 61659, \"fa-flickr\": 61806, \"fa-retweet\": 61561, \"fa-flag\": 61476, \"fa-google\": 61856, \"fa-file-sound-o\": 61895, \"fa-bitcoin\": 61786, \"fa-text-width\": 61493, \"fa-arrows-v\": 61565, \"fa-hospital-o\": 61688, \"fa-step-backward\": 61512, \"fa-bullhorn\": 61601, \"fa-fire-extinguisher\": 61748, \"fa-arrows-h\": 61566, \"fa-refresh\": 61473, \"fa-fort-awesome\": 62086, \"fa-github-alt\": 61715, \"fa-reorder\": 61641, \"fa-modx\": 62085, \"fa-facebook-square\": 61570, \"fa-empire\": 61905, \"fa-credit-card-alt\": 62083, \"fa-qq\": 61910, \"fa-rouble\": 61784, \"fa-minus-square-o\": 61767, \"fa-rotate-left\": 61666, \"fa-file-pdf-o\": 61889}"
  },
  {
    "path": "kivystudio/tools/iconfonts/test/main.py",
    "content": "from kivy.uix.label import Label\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.base import runTouchApp\nfrom kivy.lang import Builder\n\nimport os, json ,sys\nfrom os.path import join, dirname\np =(dirname(dirname(join(os.getcwd(), __file__))))\nprint(p)\nsys.path.append(p)\nfrom iconfonts import register, icon\n\nfont_file = join(dirname(__file__), 'font-awesome.fontd')\nregister('awesome_font', 'font-awesome.ttf',\n     font_file)\n\n\nwith open(font_file, 'r') as f:\n    fontd = json.loads(f.read())\n\nclass Boxer(BoxLayout):\n\n\tdef search(self, text):\n\t\tadd_icons(text)\n\nroot = Builder.load_string('''\nBoxer:\n\torientation: 'vertical'\n\tTextInput:\n\t\tsize_hint_y: None\n\t\theight: '48dp'\n\t\ton_text: root.search(self.text)\n\tScrollView:\n\t\tbar_width: '24dp'\n\t\tGridLayout:\n\t\t\tid: grid\n\t\t\theight: self.minimum_height\n\t\t\tsize_hint_y: None\n\t\t\tcols: 1\n''')\n\ndef add_icons(search=''):\n\troot.ids.grid.clear_widgets()\n\tkeys = list(fontd.keys())\n\tkeys.sort()\n\tfor icon_name in keys:\n\t\tif search and icon_name.find(search)==-1:\n\t\t\tcontinue\n\t\tlb = Label(markup=True, size_hint_y=None)\n\t\tlb.text= '[color=3280ff]%s[/color] '%(icon(icon_name, 32)) + icon_name\n\t\troot.ids.grid.add_widget(lb)\n\nadd_icons()\nrunTouchApp(root)\n"
  },
  {
    "path": "kivystudio/tools/infolabel.py",
    "content": "from kivy.uix.label import Label\nfrom kivy.lang import Builder\nfrom kivy.core.window import Window\n\nfrom .__init__ import set_auto_mouse_position\n\ndef show_info_on_mouse(message=''):\n    ''' func that displays an info \n        on mouse cursor'''\n    if message:\n        if info_label in Window.children:\n            Window.remove_widget(info_label)\n\n        info_label.text = ''\n        info_label.text = message\n        set_auto_mouse_position(info_label)\n        Window.add_widget(info_label)\n\n\ndef remove_info_on_mouse():\n    if info_label in Window.children:\n        Window.remove_widget(info_label)\n\n\nclass InfoLabel(Label):\n    pass\n\n\nBuilder.load_string('''\n<InfoLabel>:\n    size_hint: None,None\n    text_size: None, self.height\n    valign: 'middle'\n    halign:'left'\n    width:  self.texture_size[0]+10\n    height: '30dp'\n    color: 1,1,1,1\n    padding: '4dp', '4dp'\n    canvas.before:\n        Color:\n            rgba: 0,0,0,.9\n        RoundedRectangle:\n            size: self.size\n            pos: self.pos\n''')\ninfo_label = InfoLabel()\n"
  },
  {
    "path": "kivystudio/tools/logger.py",
    "content": "from kivy.logger import Logger as KivyLogger\nfrom kivy.utils import get_hex_from_color, escape_markup\n\nCOLORS  = {\n    'info': (.3,1,.4,1),\n    'warning': (1,1,0,1),\n    'error': (1,.5,.2,1),\n    }\n\nclass LoggerBase:\n\n    def _format_log(self, log_type, msg):\n        msg = msg.split(':',1) + ['']\n        log_color = get_hex_from_color(COLORS[log_type])\n        log_title = \"[color=%s]&bl;[b]%-14s[/b]&br;[/color]  \" \\\n            % (log_color, log_type.upper())\n        if msg[1]:\n            log_msg = \"[%-18s] %s\" % (msg[0], msg[1])\n        else:\n            log_msg = \"%s\" % msg[0]\n        \n        return log_title+log_msg\n\n    def info(self, msg, log_out=False):\n        log = self._format_log('info', msg)\n        self._log_out(msg, log, 'info', log_out=log_out)\n        \n    def warning(self, msg, log_out=False):\n        log = self._format_log('warning', msg)\n        self._log_out(msg, log, 'warning', log_out=log_out)\n\n    def error(self, msg, log_out=False):\n        log = self._format_log('error', msg)\n        self._log_out(msg, log, 'error', log_out=log_out)\n\n    def _log_out(self, msg, log, log_type, log_out=False):\n        from kivystudio.components.codeplace import terminal\n        terminal.logger.log(log)\n        if log_out:\n            getattr(KivyLogger, log_type)(msg)\n\n    def clear_logs(self):\n        from kivystudio.components.codeplace import terminal\n        terminal.logger.clear_logs()\n\nLogger = LoggerBase()\n\nfrom kivy.clock import mainthread\n@mainthread\ndef test_log(*args):\n    Logger.info('Welcome to KivyStudio')\ntest_log()\n"
  },
  {
    "path": "kivystudio/tools/quicktools.py",
    "content": "from kivy.logger import Logger\nimport sys\nfrom kivystudio.widgets.filemanager import filemanager\n\n\ndef open_new_file():\n    ''' open a new file on\n        the CodeInput '''\n    from kivystudio.assembler import code_place\n    code_place.add_code_tab(tab_type='new_file')\n\ndef open_file(filename=''):\n    ''' open a file (existing file) on\n        the CodeInput, if filename, it open a \n        new tab for the file, else it opens a filechooser'''\n    from kivystudio.assembler import add_new_tab\n    if filename:\n        add_new_tab([filename,])\n    else:\n        filemanager.open_file(path='/root',on_selection=add_new_tab)\n\ndef open_folder(folder=''):\n    ''' open a folder, if folder, it open a \n        new project, else it opens a filechooser'''\n    from kivystudio.assembler import open_project\n    if folder:\n        open_project([folder,])\n    else:\n        filemanager.choose_dir(path='.',on_selection=open_project)\n\ndef open_recent():\n    pass\n\ndef save():\n    ''' save the current opened\n        file '''\n    from kivystudio.assembler import code_place\n    code_place.code_manager.save_current_tab()\n\ndef save_all():\n    ''' save all file currently opened '''\n    from kivystudio.assembler import code_place\n    code_place.code_manager.save_all_tabs()\n\ndef save_as():\n    pass\n\ndef exit_window():\n    exit()\n\nimport string\ndef is_binary(filename):\n    ''' checks if a file is a binary file or not \n        used to validate file before opening them in\n        the studio '''\n    s = open(filename, 'rb').read(512)\n    def func(num):\n        return bytes(chr(num).encode('utf-8'))\n\n    text_char = b''.join( list(map(func, range(32,127))) ) #+ list('\\n\\r\\t\\b') )\n    if sys.version_info[0] == 3:\n        _null_trans = b''.maketrans(b\"\",b\"\")\n    else:\n        _null_trans = string.maketrans('', '')\n\n    if not s: # empty files are considered text files\n        return False\n    \n    if b'\\0' in s:\n        # file with null bytes are likely binary\n        return True\n\n    t = s.translate(_null_trans, delete=text_char)\n\n    # t = s.translate(str.maketrans('', '', text_char))\n    # if more than 30% are non-text charaters \n    # then it is considered binary\n    if float(len(t))/float(len(s)) > 0.30:\n        return True\n    return False\n"
  },
  {
    "path": "kivystudio/widgets/__init__.py",
    "content": ""
  },
  {
    "path": "kivystudio/widgets/codeinput/__init__.py",
    "content": "from kivy.core.window import Window\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.behaviors import ToggleButtonBehavior\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.clock import Clock\nfrom kivy.metrics import dp\nfrom kivy.lang import Builder\nfrom kivy.properties import BooleanProperty, StringProperty, ListProperty, ObjectProperty\nfrom kivy.utils import get_color_from_hex\n\nfrom kivystudio.behaviors import HoverBehavior\nfrom kivystudio.widgets.rightclick_drop import RightClickDrop\n\nfrom .styles import NativeTweakStyle\nfrom .codeinput import CodeInput\nfrom .code_find import CodeInputFind\nfrom .code_extra_behavior import CodeExtraBehavior\n\nimport os\nfrom pygments import styles\n\nclass CodeInputDropDown(RightClickDrop):\n    ''' DropDown widget show when mouse \n        is right clicked on CodeInput\n        '''\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):  # so doesn't unfocus input\n            FocusBehavior.ignored_touch.append(touch)\n        return super(CodeInputDropDown,self).on_touch_down(touch)\n    \n    def open(self, code_input):\n        self.codeinput = codeinput\n        super(CodeInputDropDown,self).open()\n\n    def copy(self):\n        self.codeinput.copy()\n\n    def paste(self):\n        self.codeinput.paste()\n\n    def cut(self):\n        self.codeinput.cut()\n\n\nclass InnerCodeInput(HoverBehavior, CodeExtraBehavior, CodeInput):\n\n    path = StringProperty('')\n    '''Path of the current file\n        `path` is a :class:`~kivy.properties.StringProperty`\n    and defaults to ''\n    '''\n\n    rightclick_dropdown = None\n    ''' drop down menu that appears when the right click button is clicked\n        `rightclick_dropdown` is an instance of .code_find.CodeInputFind\n        '''\n    code_finder = None\n    '''  '''\n\n    def __init__(self, **kwargs):\n        super(InnerCodeInput, self).__init__(**kwargs)\n        self.style_name = 'native'\n        self.background_normal= ''\n        self.background_active= ''\n\n    def on_style_name(self, *args):\n        self.style = NativeTweakStyle\n        self.background_color = get_color_from_hex(self.style.background_color)\n        self._trigger_refresh_text()\n\n    def on_text(self, *args):\n        if self.focus:\n            self.parent.saved = False\n            self.check_settings()\n\n    def check_settings(self):\n        from kivystudio.settings import settings_obj\n        auto_save = settings_obj.auto_save\n        auto_emulate = settings_obj.auto_emulate\n        if auto_save:\n            self.parent.parent.save_file(auto_save=True)\n        if auto_emulate:\n            from kivystudio.parser import emulate_file\n            from kivystudio.components.emulator_area import get_emulator_area\n            if get_emulator_area().emulation_file == self.parent.filename:\n                emulate_file(self.parent.filename)\n\n    def keyboard_on_textinput(self, window, text):\n        'overiding the default textinput keyboard listener '\n        if (text == '=' or text == '-') and 'ctrl' in Window.modifiers:\n            return True\n        super(InnerCodeInput,self).keyboard_on_textinput(window, text)\n\n    def keyboard_on_key_down(self, keyboard, keycode, text, modifiers):\n        'overiding the default keyboard listener '\n        # print(keycode, modifiers)\n\n        if keycode[1] == 'tab' and 'shift' in modifiers:  # unindentation [Shit-tab]\n            self._do_reverse_indentation()\n\n        elif keycode[1] == 'tab' and self.selection_text:  # multiple indentation [Tab]\n            self.do_multiline_indent()\n\n        elif keycode[1] == 'backspace' and 'ctrl' in modifiers:   # delete word left  [Ctrl-bsc]\n            self.delete_word_left()\n\n        elif keycode[1] == '/' and 'ctrl' in modifiers:     # a comment ctrl /\n            self.do_comment()\n\n        elif keycode[1] == 'enter':\n            Clock.schedule_once(lambda dt: self.do_auto_indent())\n            return super(CodeInput, self).keyboard_on_key_down(keyboard, keycode, text, modifiers)\n\n        elif keycode[1] == 'f' and 'ctrl' in modifiers:     # ctrl f to open a search\n            self.open_code_finder()\n\n        elif keycode[0] == 27:     # on escape, do nothing\n            return True\n\n        else:\n            # then return super for others\n            return super(CodeInput, self).keyboard_on_key_down(keyboard, keycode, text, modifiers)\n    \n    def open_code_finder(self):\n        ''' open the search finder \n            on the codeinput '''\n        code_finder = InnerCodeInput.code_finder\n        if code_finder:\n            code_finder.open(self)\n        else:\n            InnerCodeInput.code_finder = CodeInputFind()\n            InnerCodeInput.code_finder.open(self)\n    \n    def open_rightclick_dropdown(self):\n        ''' open the dropdown right click \n            on the codeinput '''\n        rightclick_dropdown = InnerCodeInput.rightclick_dropdown\n        if rightclick_dropdown:\n            rightclick_dropdown.open()\n        else:\n            InnerCodeInput.rightclick_dropdown = CodeInputDropDown()\n            InnerCodeInput.rightclick_dropdown.open(self)\n\n    def on_hover(self, *a):\n        ''' changing the mouse cursor \n            on code input'''\n        if self.hover:\n            Window.set_system_cursor('ibeam')  # set cursor to ibeam\n        else:\n            Window.set_system_cursor('arrow')  # set cursor to arrow\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            if touch.button == 'right':\n                self.open_rightclick_dropdown()\n                FocusBehavior.ignored_touch.append(touch)\n                return True\n\n        if touch.button == 'left':\n            return super(InnerCodeInput,self).on_touch_down(touch)\n\n\nclass NumberingGrid(ScrollView):\n\n    def on_touch_down(self, touch):\n        if self.collide_point( *touch.pos):\n            FocusBehavior.ignored_touch.append(touch)\n            super(NumberingGrid, self).on_touch_down(touch)\n\nclass ScrollingBar(ScrollView):\n\n    def on_touch_down(self, touch):\n        if self.collide_point( *touch.pos):\n            FocusBehavior.ignored_touch.append(touch)\n            super(ScrollingBar, self).on_touch_down(touch)\n\n\nclass FullCodeInput(GridLayout):\n\n    _do_cursor_scroll =BooleanProperty(True)\n\n    code_input = ObjectProperty(None)\n\n    tab = ObjectProperty(None)\n\n    tab_type = StringProperty('code')\n\n    filename = StringProperty('')\n    ''' name current file in the input \n            :data:`filename` is a :class:`~kivy.properties.StringProperty`\n    and defaults to ''\n    '''\n\n    saved = BooleanProperty(True)\n    '''Indicates if the current file is saved or not\n        :data:`saved` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True\n    '''\n\n    def __init__(self, **kwargs):\n        super(FullCodeInput, self).__init__(**kwargs)\n        Clock.schedule_once(self.first_number)\n        self._former_line_lenght = 1\n        self.first_time = True\n\n\n    def first_number(self, dt):\n        label = Numbers_(height=dp(self.ids.code_input.line_height), text=str(1))\n        Clock.schedule_once(lambda dt: setattr(label, 'state', 'down'))\n        label.fbind('on_press', self._number_pressed)\n        self.ids.numbering.add_widget(label)\n        self._former_line_lenght = 1\n\n\n    def _number_pressed(self, lb):\n        self.ids.code_input.cursor = (self.ids.code_input.cursor[0], int(lb.text)-1)\n\n\n    def change_scroll_y(self, txt, scroll):\n        if self._do_cursor_scroll:\n\n            lines_lenght = len(txt._lines)\n            line_pos = txt.cursor_row +1\n\n            norm_y = float(line_pos) / lines_lenght\n            scroll.scroll_y  = abs(norm_y-1)\n            if line_pos == 1:\n                scroll.scroll_y  = 1\n\n        # scroll scroll numbers\n        line_num =  txt.cursor_row + 1\n        children = self.ids.numbering.children[::-1]\n        if children:\n            child = children[line_num-1]\n            self.ids.number_scroll.scroll_to(child, dp(5))\n\n            Clock.schedule_once(lambda dt: setattr(child, 'state', 'down'))\n            def toggle(chd):\n                if chd!=child:\n                    chd.state='normal'\n            map(lambda child: toggle, ToggleButtonBehavior.get_widgets(child.group))\n\n\n    def do_bar_scroll(self, txt, scroll):\n        lines_lenght = len(txt._lines)\n        line_pos = int(abs(scroll.scroll_y-1) * lines_lenght)\n        cursor_y = abs(line_pos)\n\n        txt.cursor = (txt.cursor_col, cursor_y)\n\n    def number_me(self, txt, scroll):\n        lines_lenght = len(txt._lines)\n        line_pos = txt.cursor_row +2\n\n        if not(lines_lenght <= 1) or not(self.first_time):\n\n            if lines_lenght >= self._former_line_lenght:\n\n                if line_pos == lines_lenght:\n                    self.do_new_line(txt, scroll)\n                else:\n                    self.do_new_line(txt, scroll)\n\n            else:\n                self.remove_line_numbering(txt, scroll)\n            \n            self._former_line_lenght = lines_lenght\n        self.first_time = False\n\n    def do_new_line(self, txt, scroll):\n        lines_lenght = len(txt._lines)\n\n        for line_num in range(self._former_line_lenght+1, lines_lenght+1):\n\n            label = Numbers_(height=dp(self.ids.code_input.line_height), text=str(line_num))\n            label.fbind('on_press', self._number_pressed)\n            self.ids.numbering.add_widget(label)\n        \n    def remove_line_numbering(self, txt, scroll):\n        lines_lenght = len(txt._lines)\n\n        for line_num in range(lines_lenght+1, self._former_line_lenght+1):\n            child = self.ids.numbering.children[0]\n            self.ids.numbering.remove_widget(child)\n        \n\nclass Numbers_(ToggleButtonBehavior, Label):\n\n    selected_color = ListProperty([1,1,1,1])\n    ' color of the number when selected'\n\n    normal_color = ListProperty([.5,.5,.5,1])\n    ' color of the number when selected'\n    \n    def on_state(self, *args):\n\n        if self.state == 'down':\n            self.color = self.selected_color\n            self.canvas_color = self.normal_color[:3]+[.3]\n        else:\n            self.color = self.normal_color\n            self.canvas_color = [0,0,0,0]\n\n\n\nBuilder.load_file(os.path.join(os.path.dirname(__file__),'codeinput.kv'))\n\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp\n    runTouchApp(FullCodeInput())\n\n\n    'rrt, xcode, friendly, algol'\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/code_extra_behavior.py",
    "content": "''' Etra Awesome CodeInput Mixin/Behavior\n'''\n\nclass CodeExtraBehavior(object):\n\n    def do_comment(self):\n        ' comment a line'\n        if not self.selection_text:     # single line momment\n            line = self._lines[self.cursor_row]\n            self.do_one_line_comment(line)\n\n        else:   # multiline comment\n            i = self._selection_from\n            j = self._selection_to\n            check_lines = list(filter(lambda line: line != '', self.selection_text.splitlines()))\n            lines = self.selection_text.splitlines()\n            if j > i:\n                # basically checking for lines that has a value\n                # move the cursor position\n                self.cursor = (0, self.cursor_row- len(lines))\n                # check if there are no comments in the  lines\n                if len(list(filter(lambda line: line.lstrip().startswith('#'), check_lines))) != len(check_lines):\n                    self.do_multiline_comment(lines)\n                else:\n                    self.uncomment_multiline(lines)\n            else:\n                self.cursor = (0, self.cursor_row)\n\n                # check if there are no comments in the  lines\n                if len(list(filter(lambda line: line.lstrip().startswith('#'), check_lines))) != len(check_lines):\n                    self.do_multiline_comment(lines)\n                else:\n                    self.uncomment_multiline(lines)\n\n\n    def do_multiline_comment(self, lines):\n        'comment multiple lines'\n        closest = self.get_closest_indentation(lines)\n        y_cur = self.cursor[1]\n        for i, line in enumerate(lines):\n            if line:\n                former_cur_x = self.cursor[0]\n\n                self.cursor = (closest, y_cur+i)\n\n                # if line already commented\n                if line.lstrip().startswith('#'): continue\n\n                self.insert_text('# ')\n                self.cursor = (former_cur_x, self.cursor[1])\n\n        # now cancel selection\n        self.cancel_selection()\n\n\n    def do_multiline_indent(self):\n        lines = self.selection_text.splitlines()\n        closest = self.get_closest_indentation(lines)\n        y_cur = self.cursor[1]\n        for i, line in enumerate(lines):\n            if line:\n                former_cur_x = self.cursor[0]\n\n                self.cursor = (closest, y_cur-i-1)\n\n                self.insert_text(' '*4)\n                self.cursor = (former_cur_x, self.cursor[1])\n\n        # now cancel selection\n        self.cancel_selection()\n\n    def uncomment_multiline(self, lines):\n        '''uncomment multiple line when the user from\n        the user selection'''\n\n        y_cur = self.cursor[1]\n        for i, line in enumerate(lines):\n            if line:\n                former_cur_x = self.cursor[0]\n\n                find = line.find('#')\n                self.cursor = (find, y_cur+i)\n\n                if line.lstrip().startswith('# '):\n                    offset = 2\n                    substring = '# '\n\n                elif line.lstrip().startswith('#'):\n                    offset = 1\n                    substring = '#'\n\n                new_line = line[:find] + line[find+offset:]\n                self._set_line_text(self.cursor_row, new_line)\n\n                self._set_my_undo_redo(find, offset, substring)\n\n                self._do_my_refresh(new_line)\n\n                self.cursor = (former_cur_x, self.cursor[1])\n\n        # now cancel selection\n        self.cancel_selection()\n\n\n    def do_one_line_comment(self, line):\n\n        if line:\n            if not line.lstrip().startswith('#'):    # then comment\n                strip_line = line.strip()\n                former_cur_x = self.cursor[0]\n                self.cursor = (line.index(strip_line), self.cursor[1])\n                self.insert_text('# ')\n                self.cursor = (former_cur_x, self.cursor[1])\n\n            else:   # uncomment line\n                if line.lstrip().startswith('# '):\n                    offset = 2\n                    substring = '# '\n\n                elif line.lstrip().startswith('#'):\n                    offset = 1\n                    substring = '#'\n\n                find = line.find('#')\n\n                new_line = line[:find] + line[find+offset:]\n                self._set_line_text(self.cursor_row, new_line)\n                self._set_my_undo_redo(find, offset, substring)\n\n                self._do_my_refresh(new_line)\n\n\n    def _do_my_refresh(self, new_text):\n        'the internal kivy code used to refreash the textinput'\n        # refresh just the current line instead of the whole text\n        start, finish, lines, lineflags, len_lines =\\\n            self._get_line_from_cursor(self.cursor_row, new_text)\n        # avoid trigger refresh, leads to issue with\n        # keys/text send rapidly through code.\n\n        self._refresh_text_from_property('del', start, finish, lines,\n                                         lineflags, len_lines)\n\n    def _set_my_undo_redo(self, find, offset, substring):\n        if self.cursor_row > 0:\n            old_index = len('\\n'.join(self._lines[:self.cursor_row])) + find - 1\n            new_index = old_index + offset\n        else:\n            old_index = find\n            new_index = old_index\n\n        # handle undo and redo\n        self._set_undo_redo_bkspc(\n            old_index,\n            new_index,\n            substring, False)\n\n\n    def do_auto_indent(self):\n        ''' and i guess your are thinking doesn't kivy already has an auto indent,\n            this func just check if the line endswith a ':' so it would indent it to the\n            next line\n        '''\n        line = self._lines[self.cursor_row-1].strip()   # get the previos line then strip it\n        if line.endswith(':'):\n            self.insert_text('\\t')\n\n\n    def get_closest_indentation(self, lines):\n        counter = []\n        for line in lines:\n            count = 0\n\n            for char in line:\n                if char != ' ':\n                    counter.append(count)\n                    if count == 0:  # if we found an indent at 0 then look no further\n                        break\n                    break\n                count += 1\n            else:\n                if line:\n                    counter.append(len(line))\n        return min(counter)\n\n\n    def _do_reverse_indentation(self):\n        if not self.selection_text and self._lines[self.cursor_row]:\n\n            line = self._lines[self.cursor_row].replace('\\t', '    ')\n            indent = self.get_closest_indentation([line])\n\n            if indent != 0:\n                next_indent = indent - 4\n                new_line = line[:next_indent] + line[indent:]\n\n                self._set_line_text(self.cursor_row, new_line)\n\n                self._set_my_undo_redo(next_indent-2, 4, '    ')\n\n                self._do_my_refresh(new_line)\n                self.cursor = (next_indent, self.cursor_row)\n\n        if self.selection_text:\n            i = self._selection_from\n            j = self._selection_to\n\n            lines = self.selection_text.splitlines()\n\n            if j > i:\n                self.cursor = (0, self.cursor_row- len(lines))\n            else:\n                self.cursor = (0, self.cursor_row)\n\n            self._multi_unindent(lines)\n\n            # now cancel selection for the main time\n            self.cancel_selection()\n        \n    def _multi_unindent(self, lines):\n        y_cur = self.cursor[1]\n        for i, line in enumerate(lines):\n            if line:\n                former_cur_x = self.cursor[0]\n\n                self.cursor = (0, y_cur+i)\n\n                line = line.replace('\\t', '    ')\n\n                indent = self.get_closest_indentation([line])\n\n                if indent != 0:\n                    next_indent = indent - 4\n                    new_line = line[:next_indent] + line[indent:]\n\n                    self._set_line_text(self.cursor_row, new_line)\n\n                    self._set_my_undo_redo(next_indent-2, 4, '    ')\n\n                    self._do_my_refresh(new_line)\n\n                    self.cursor = (next_indent, self.cursor_row)\n\n    def delete_word_left(self):\n        '''\n        Delete text left of the cursor to the beginning of word'''\n\n        if self._selection:\n            return None\n\n        line = self._lines[self.cursor[1]]\n        if self.cursor[0]==0:\n            return None\n\n        if line.strip()=='':\n            return None\n\n\n        former_cursor_x = self.cursor[0]\n        old_index = self.cursor_index()\n\n        self.do_cursor_movement('cursor_left', control=True)\n        new_index = self.cursor_index()\n        end_cursor = self.cursor\n\n        if self.cursor[0] != former_cursor_x:\n            new_line = line[:self.cursor[0]] + line[former_cursor_x:]\n            self._set_line_text(self.cursor_row, new_line)\n\n            substring = line[self.cursor[0]:former_cursor_x]\n\n            self._set_undo_redo_bkspc(\n                old_index,\n                new_index,\n                substring, False)\n\n            self._do_my_refresh(new_line)\n            self._set_cursor(pos=end_cursor)\n\n\n    def _split_smart(self, text):\n        ''' turns out this function isn't really smart\n        so had to override it, basically for horizontal line continuation'''\n        lines = text.split(u'\\n')\n        lines_flags = [0] + [0x01] * (len(lines) - 1)\n        return lines, lines_flags\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/code_find.py",
    "content": "from kivy.properties import BooleanProperty, ObjectProperty, StringProperty\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.core.window import Window\nfrom kivy.clock import Clock\n\nfrom kivystudio.widgets.searchinput import SearchInput\n\nclass CodeInputFind(BoxLayout):\n    '''Widget responsible for searches in Code Input\n    '''\n\n    query = StringProperty('')\n    '''Search query\n    :data:`query` is a :class:`~kivy.properties.StringProperty`\n    '''\n\n    txt_query = ObjectProperty(None)\n    '''Search query TextInput\n    :data:`txt_query` is a :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    use_regex = BooleanProperty(False)\n    '''Filter search with regex\n        :data:`use_regex` is a :class:`~kivy.properties.BooleanProperty`\n    '''\n\n    case_sensitive = BooleanProperty(False)\n    '''Filter search with case sensitive text\n        :data:`case_sensitive` is a :class:`~kivy.properties.BooleanProperty`\n    '''\n\n    code_input = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        '''Enable touche\n        '''\n        if self.collide_point(*touch.pos):\n            super(CodeInputFind, self).on_touch_down(touch)\n            return True\n\n    def find_next(self, search):\n        '''Find the next occurrence of the string according to the cursor\n        position\n        '''\n        code_input = self.code_input\n        use_regex = self.use_regex\n        case = self.case_sensitive\n\n        text = code_input.text\n        if not case:\n            text = text.upper()\n            search = search.upper()\n        lines = text.splitlines()\n\n        col = code_input.cursor_col\n        row = code_input.cursor_row\n\n        found = -1\n        size = 0  # size of string before selection\n        line = None\n        search_size = len(search)\n\n        for i, line in enumerate(lines):\n            if i >= row:\n                if use_regex:\n                    if i == row:\n                        line_find = line[col + 1:]\n                    else:\n                        line_find = line[:]\n                    found = re.search(search, line_find)\n                    if found:\n                        search_size = len(found.group(0))\n                        found = found.start()\n                    else:\n                        found = -1\n                else:\n                    # if on current line, consider col\n                    if i == row:\n                        found = line.find(search, col + 1)\n                    else:\n                        found = line.find(search)\n                # has found the string. found variable indicates the initial po\n                if found != -1:\n                    code_input.cursor = (found, i)\n                    break\n            size += len(line)\n\n        if found != -1:\n            pos = text.find(line) + found\n            code_input.select_text(pos, pos + search_size)\n            return True\n        else:\n            return False\n\n    def find_prev(self, search):\n        '''Find the previous occurrence of the string according to the cursor\n        position\n        '''\n        code_input = self.code_input\n        use_regex = self.use_regex\n        case = self.case_sensitive\n\n        code_input = self.code_input\n        text = code_input.text\n        if not case:\n            text = text.upper()\n            search = search.upper()\n        lines = text.splitlines()\n\n        col = code_input.cursor_col\n        row = code_input.cursor_row\n        lines = lines[:row + 1]\n        lines.reverse()\n        line_number = len(lines)\n\n        found = -1\n        line = None\n        search_size = len(search)\n\n        for i, line in enumerate(lines):\n            i = line_number - i - 1\n            if use_regex:\n                if i == row:\n                    line_find = line[:col]\n                else:\n                    line_find = line[:]\n                found = re.search(search, line_find)\n                if found:\n                    search_size = len(found.group(0))\n                    found = found.start()\n                else:\n                    found = -1\n            else:\n                # if on current line, consider col\n                if i == row:\n                    found = line[:col].find(search)\n                else:\n                    found = line.find(search)\n            # has found the string. found variable indicates the initial po\n            if found != -1:\n                code_input.cursor = (found, i)\n                break\n\n        if found != -1:\n            pos = text.find(line) + found\n            code_input.select_text(pos, pos + search_size)\n            return True\n        else:\n            return False\n    \n    def find(self,search):\n        if not self.find_next(search):\n            self.find_prev(search)\n        Clock.schedule_once(lambda *args: setattr(self.ids.input, 'focus', True))\n\n    def open(self,code_input):\n        self.code_input=code_input\n        self.ids.input.focus=True\n        if not self.parent:\n            Window.add_widget(self)\n            self.top = code_input.top\n            self.right= code_input.right\n            code_input.bind(top=self.setter('top'))\n            code_input.bind(right=self.setter('right'))\n\n    def dismiss(self):\n        if self.parent:\n            self.parent.remove_widget(self)\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/codeinput.kv",
    "content": "\n<FullCodeInput>:\n    cols: 3\n    code_input: code_input\n    NumberingGrid:\n        id: number_scroll\n        size_hint_x: None\n        width: '50dp'\n        bar_color: 1,0,0,0\n        bar_inactive_color: self.bar_color\n        scroll_type: ['bars']\n        bar_width: 0\n        canvas.before:\n            Color:\n                rgba: (0.12, 0.12, 0.125, 1)\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\n        # canvas to show division\n        canvas.after:\n            Color:\n                rgba: (0, 0, 0, .4)\n            Line:\n                points: [self.right,self.y, self.right,self.height]\n            Color:\n                rgba: (0, 0, 0, .3)\n            Line:\n                points: [self.right+1,self.y, self.right+1,self.height]\n            Color:\n                rgba: (0, 0, 0, .2)\n            Line:\n                points: [self.right+2,self.y, self.right+2,self.height]\n            Color:\n                rgba: (0, 0, 0, .1)\n            Line:\n                points: [self.right+3,self.y, self.right+3,self.height]\n                width: 2\n\n        GridLayout:\n            cols: 1\n            id: numbering\n            size_hint_y: None\n            height: self.minimum_height\n            padding: [0, '6dp', 0, '6dp']\n\n    InnerCodeInput:\n        id: code_input\n        auto_indent: True\n        size_hint_y: 1\n        height: scroll.height\n        cursor_color: 1,1,1,1\n        on_cursor_row: root.change_scroll_y(code_input, scroll)\n        _line_lenght: len(self._lines)\n        on__line_lenght: root.number_me(self, scroll)\n        selection_color: .8,.8,.8,.4\n        font_size: sp(14) * settings.dpi_scale\n        line_highlight_color: 1,1,.8,.1\n        on_selection_text:\n            if self.selection_text: self.line_highlight_color = 0,0,0,0\n            else: self.line_highlight_color = 1,1,.8,.1\n        on_focus:\n            if not self.focus: self.line_highlight_color = 0,0,0,0\n            else: self.line_highlight_color = 1,1,.8,.1\n\n        # canvas to show highlighted line\n        canvas.after:\n            Color:\n                rgba: self.line_highlight_color\n            Rectangle:\n                size: self.width, self.line_height + dp(3)\n                pos: self.x, self.cursor_pos[1] -  self.line_height -dp(1.5)\n\n\n    ScrollingBar:\n        bar_width: '12dp'\n        scroll_type: ['bars', 'content']\n        bar_inactive_color:  1,1,1,.4\n        bar_active_color:  1,1,1,.2\n        id: scroll\n        kv_lang_area: code_input\n        size_hint_x: None\n        width: '12dp'\n        on_scroll_start: root._do_cursor_scroll==False\n        on_scroll_move: root.do_bar_scroll(code_input, self)\n        on_scroll_stop: root._do_cursor_scroll==True\n\n        canvas.before:\n            Color:\n                rgba: code_input.background_color\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\n        # canvas to show division\n        canvas.after:\n            Color:\n                rgba: (0, 0, 0, .4)\n            Line:\n                points: [self.x,self.y, self.x,self.height]\n            Color:\n                rgba: (0, 0, 0, .3)\n            Line:\n                points: [self.x-1,self.y, self.x-1,self.height]\n            Color:\n                rgba: (0, 0, 0, .2)\n            Line:\n                points: [self.x-2,self.y, self.x-2,self.height]\n            Color:\n                rgba: (0, 0, 0, .1)\n            Line:\n                points: [self.x-3,self.y, self.x-3,self.height]\n                width: 2\n\n        Widget:\n            size_hint_y: None\n            height: code_input.minimum_height\n\n<Numbers_>:\n    font_size: '13dp'\n    size_hint_y: None\n    color: self.normal_color\n    group: '_line_numbers_'\n    allow_no_selection: False\n\n<CodeInputDropDown>:\n    MenuButton:\n        on_release: root.copy()\n        MenuLabel:\n            text: 'Copy'\n        MenuLabel:\n            text: 'Ctrl+C'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.cut()\n        MenuLabel:\n            text: 'Cut'\n        MenuLabel:\n            text: 'Ctrl+X'\n            type: 'shortcut'\n    MenuButton:\n        on_release: root.paste()\n        MenuLabel:\n            text: 'Paste'\n        MenuLabel:\n            text: 'Ctrl+V'\n            type: 'shortcut'\n\n<CodeInputFind>:\n    size_hint: None,None\n    size: '230dp','40dp'\n    padding: '4dp'\n    canvas.before:\n        Color:\n            rgba: .2,.2,.2,1\n        RoundedRectangle:\n            size: self.size\n            pos: self.pos\n            radius: [dp(6),]\n            canvas.after:\n        Color:\n            rgba: .5,.5,.5,1\n        Line:\n            rounded_rectangle: [self.x,self.y,self.width,self.height,dp(6)]\n    SearchInput:\n        id: input\n        hint_text: 'search'\n        multiline: False\n        on_text_validate: root.find(input.text)\n    Label:\n        size_hint_x:None\n        width: self.texture_size[0]\n        id: found\n    IconLabelButton:\n        text: '%s' %icon('fa-arrow-left')\n        size_hint_x:None\n        width: '32dp'\n        on_release: root.find_prev(input.text)\n        color: 1,1,1\n    IconLabelButton:\n        text: '%s' %icon('fa-arrow-right')\n        size_hint_x: None\n        width: '32dp'\n        on_release: root.find_next(input.text)\n        color: 1,1,1\n    IconLabelButton:\n        text: '%s' %icon('fa-close')\n        width: '32dp'\n        size_hint_x:None\n        color: 1,1,1\n        on_release: root.dismiss()\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/codeinput.py",
    "content": "'''\nCode Input\n==========\n\n.. versionadded:: 1.5.0\n\n.. image:: images/codeinput.jpg\n\n.. note::\n\n    This widget requires ``pygments`` package to run. Install it with ``pip``.\n\nThe :class:`CodeInput` provides a box of editable highlighted text like the one\nshown in the image.\n\nIt supports all the features provided by the :class:`~kivy.uix.textinput` as\nwell as code highlighting for `languages supported by pygments\n<http://pygments.org/docs/lexers/>`_ along with `KivyLexer` for\n:mod:`kivy.lang` highlighting.\n\nUsage example\n-------------\n\nTo create a CodeInput with highlighting for `KV language`::\n\n    from kivy.uix.codeinput import CodeInput\n    from kivy.extras.highlight import KivyLexer\n    codeinput = CodeInput(lexer=KivyLexer())\n\nTo create a CodeInput with highlighting for `Cython`::\n\n    from kivy.uix.codeinput import CodeInput\n    from pygments.lexers import CythonLexer\n    codeinput = CodeInput(lexer=CythonLexer())\n\n'''\n\n__all__ = ('CodeInput', )\n\nfrom pygments import highlight\nfrom pygments import lexers\nfrom pygments import styles\nfrom pygments.formatters import BBCodeFormatter\nfrom pygments.token import String\n\nfrom kivy.uix.textinput import TextInput\nfrom kivy.core.text.markup import MarkupLabel as Label\nfrom kivy.cache import Cache\nfrom kivy.properties import ObjectProperty, OptionProperty\nfrom kivy.utils import get_hex_from_color, get_color_from_hex\nfrom kivy.uix.behaviors import CodeNavigationBehavior\n\nCache_get = Cache.get\nCache_append = Cache.append\n\n# TODO: color chooser for keywords/strings/...\n\n\nclass CodeInput(CodeNavigationBehavior, TextInput):\n    '''CodeInput class, used for displaying highlighted code.\n    '''\n\n    lexer = ObjectProperty(None)\n    '''This holds the selected Lexer used by pygments to highlight the code.\n\n\n    :attr:`lexer` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to `PythonLexer`.\n    '''\n\n    style_name = OptionProperty(\n        'default', options=list(styles.get_all_styles())\n    )\n    '''Name of the pygments style to use for formatting.\n\n    :attr:`style_name` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to ``'default'``.\n\n    '''\n\n    style = ObjectProperty(None)\n    '''The pygments style object to use for formatting.\n\n    When ``style_name`` is set, this will be changed to the\n    corresponding style object.\n\n    :attr:`style` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to ``None``\n\n    '''\n\n    def __init__(self, **kwargs):\n        stylename = kwargs.get('style_name', 'default')\n        style = kwargs['style'] if 'style' in kwargs \\\n            else styles.get_style_by_name(stylename)\n        self.formatter = BBCodeFormatter(style=style)\n        self.lexer = lexers.PythonLexer()\n        self.text_color = '#000000'\n        self._label_cached = Label()\n        self.use_text_color = True\n\n        super(CodeInput, self).__init__(**kwargs)\n\n        self._line_options = kw = self._get_line_options()\n        self._label_cached = Label(**kw)\n        # use text_color as foreground color\n        text_color = kwargs.get('foreground_color')\n        if text_color:\n            self.text_color = get_hex_from_color(text_color)\n        # set foreground to white to allow text colors to show\n        # use text_color as the default color in bbcodes\n        self.use_text_color = False\n        self.foreground_color = [1, 1, 1, .999]\n        if not kwargs.get('background_color'):\n            self.background_color = [.9, .92, .92, 1]\n\n    def on_style_name(self, *args):\n        self.style = styles.get_style_by_name(self.style_name)\n        self.background_color = get_color_from_hex(self.style.background_color)\n        self._trigger_refresh_text()\n\n    def on_style(self, *args):\n        self.formatter = BBCodeFormatter(style=self.style)\n        self._trigger_update_graphics()\n\n    def _create_line_label(self, text, hint=False):\n        # Create a label from a text, using line options\n        ntext = text.replace(u'\\n', u'').replace(u'\\t', u' ' * self.tab_width)\n        if self.password and not hint:  # Don't replace hint_text with *\n            ntext = u'*' * len(ntext)\n        ntext = self._get_bbcode(ntext)\n        kw = self._get_line_options()\n        cid = u'{}\\0{}\\0{}'.format(ntext, self.password, kw)\n        texture = Cache_get('textinput.label', cid)\n\n        if texture is None:\n            # FIXME right now, we can't render very long line...\n            # if we move on \"VBO\" version as fallback, we won't need to\n            # do this.\n            # try to find the maximum text we can handle\n            label = Label(text=ntext, **kw)\n            if text.find(u'\\n') > 0:\n                label.text = u''\n            else:\n                label.text = ntext\n            label.refresh()\n\n            # ok, we found it.\n            texture = label.texture\n            Cache_append('textinput.label', cid, texture)\n            label.text = ''\n        return texture\n\n    def _get_line_options(self):\n        kw = super(CodeInput, self)._get_line_options()\n        kw['markup'] = True\n        kw['valign'] = 'top'\n        kw['codeinput'] = repr(self.lexer)\n        return kw\n\n    def _check_doc_string(self):\n\n        text = self.text[:self.cursor_index()][::-1]\n        text = self.text\n        # print(self.text)\n\n        double = text.count('\"\"\"')\n        single = text.count(\"'''\")\n        found_double = False\n        found_single = False\n\n        if double > 0 and double % 2 != 0:\n            found_double = True\n            # print('found a previous double')\n        if single > 0 and single % 2 != 0:\n            found_single = True\n            # print('found a previous single')\n\n        if found_double and found_single:\n            _doc_string = True\n        elif not found_double and not found_single:\n            _doc_string = False\n        else:\n            _doc_string = True\n        \n        return _doc_string\n\n\n    def _get_text_width(self, text, tab_width, _label_cached):\n        # Return the width of a text, according to the current line options.\n        cid = u'{}\\0{}\\0{}'.format(text, self.password,\n                                   self._get_line_options())\n        width = Cache_get('textinput.width', cid)\n        if width is not None:\n            return width\n        lbl = self._create_line_label(text)\n        width = lbl.width\n        Cache_append('textinput.width', cid, width)\n        return width\n\n    def _get_bbcode(self, ntext):\n        # get bbcoded text for python\n        try:\n            ntext[0]\n            # replace brackets with special chars that aren't highlighted\n            # by pygment. can't use &bl; ... cause & is highlighted\n            ntext = ntext.replace(u'[', u'\\x01').replace(u']', u'\\x02')\n\n            ntext = highlight(ntext, self.lexer, self.formatter)\n\n            ntext = ntext.replace(u'\\x01', u'&bl;').replace(u'\\x02', u'&br;')\n            # replace special chars with &bl; and &br;\n            ntext = ''.join((u'[color=', str(self.text_color), u']',\n                             ntext, u'[/color]'))\n            ntext = ntext.replace(u'\\n', u'')\n\n            # # remove possible extra highlight options\n            # ntext = ntext.replace(u'[u]', '').replace(u'[/u]', '')\n            return ntext\n        except IndexError:\n            return ''\n\n    # overriden to prevent cursor position off screen\n    def _cursor_offset(self):\n        '''Get the cursor x offset on the current line\n        '''\n        offset = 0\n        try:\n            if self.cursor_col:\n                offset = self._get_text_width(\n                    self._lines[self.cursor_row][:self.cursor_col])\n                return offset\n        except:\n            pass\n        finally:\n            return offset\n\n    def on_lexer(self, instance, value):\n        self._trigger_refresh_text()\n\n    def on_foreground_color(self, instance, text_color):\n        if not self.use_text_color:\n            self.use_text_color = True\n            return\n        self.text_color = get_hex_from_color(text_color)\n        self.use_text_color = False\n        self.foreground_color = (1, 1, 1, .999)\n        self._trigger_refresh_text()\n\n\nif __name__ == '__main__':\n    from kivy.extras.highlight import KivyLexer\n    from kivy.app import App\n\n    class CodeInputTest(App):\n        def build(self):\n            return CodeInput(lexer=KivyLexer(),\n                             font_size=12,\n                             text='''\n#:kivy 1.0\n\n<YourWidget>:\n    canvas:\n        Color:\n            rgb: .5, .5, .5\n        Rectangle:\n            pos: self.pos\n            size: self.size''')\n\n    CodeInputTest().run()\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/styles/__init__.py",
    "content": "from .native_tweak import NativeTweakStyle"
  },
  {
    "path": "kivystudio/widgets/codeinput/styles/native_tweak.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\n    pygments.styles.native\n    ~~~~~~~~~~~~~~~~~~~~~~\n\n    pygments version of my \"native\" vim theme.\n\n    :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.\n    :license: BSD, see LICENSE for details.\n\"\"\"\n\nfrom pygments.style import Style\nfrom pygments.token import Keyword, Name, Comment, String, Error, \\\n     Number, Operator, Generic, Token, Whitespace, Punctuation\n\n\nclass NativeTweakStyle(Style):\n    \"\"\"\n    Pygments version of the \"native\" vim theme.\n    \"\"\"\n\n    background_color = '#202020'\n    highlight_color = '#404040'\n\n    styles = {\n        Token:              '#d0d0d0',\n        Whitespace:         '#666666',\n\n        Comment:            'italic #777777',\n        Comment.Preproc:    'noitalic bold #cd2828',\n        Comment.Special:    'noitalic bold #e50808 bg:#520000',\n\n        Keyword:            'bold #CC6600',\n        Keyword.Pseudo:     'nobold',\n        Operator.Word:      'bold #CC6600',\n        Operator:           '#CC6600',\n\n        String:             '#FFCC00',\n        String.Other:       '#ffa500',\n        \n        Number:             '#3677a9',\n\n        Name.Builtin:       '#24909d',\n        Name.Variable:      '#40ffff',\n        Name.Constant:      '#40ffff',\n        Name.Class:         'underline #447fcf',\n        Name.Function:      '#447fcf',\n        Name.Namespace:     'underline #447fcf',\n        Name.Exception:     '#33CCFF',\n        Name.Tag:           'bold #CC6600',\n        Name.Attribute:     '#bbbbbb',\n        Name.Decorator:     '#ffa500',\n        Name.Builtin.Pseudo:  '#33CCFF',\n\n\n        Generic.Heading:    'bold #ffffff',\n        Generic.Subheading: 'underline #ffffff',\n        Generic.Deleted:    '#d22323',\n        Generic.Inserted:   '#589819',\n        Generic.Error:      '#d22323',\n        Generic.Emph:       'italic',\n        Generic.Strong:     'bold',\n        Generic.Prompt:     '#aaaaaa',\n        Generic.Output:     '#cccccc',\n        Generic.Traceback:  '#d22323',\n\n        Error:              'bg:#FFFFFF #FFFFFF'\n    }\n"
  },
  {
    "path": "kivystudio/widgets/codeinput/tools.py",
    "content": "import re\n\ndef find_next(self, search, use_regex=False, case=False):\n    '''Find the next occurrence of the string according to the cursor\n    position\n    '''\n    text = self.text\n    if not case:\n        text = text.upper()\n        search = search.upper()\n    lines = text.splitlines()\n\n    col = self.cursor_col\n    row = self.cursor_row\n\n    found = -1\n    size = 0  # size of string before selection\n    line = None\n    search_size = len(search)\n\n    for i, line in enumerate(lines):\n        if i >= row:\n            if use_regex:\n                if i == row:\n                    line_find = line[col + 1:]\n                else:\n                    line_find = line[:]\n                found = re.search(search, line_find)\n                if found:\n                    search_size = len(found.group(0))\n                    found = found.start()\n                else:\n                    found = -1\n            else:\n                # if on current line, consider col\n                if i == row:\n                    found = line.find(search, col + 1)\n                else:\n                    found = line.find(search)\n            # has found the string. found variable indicates the initial po\n            if found != -1:\n                self.cursor = (found, i)\n                break\n        size += len(line)\n\n    if found != -1:\n        pos = text.find(line) + found\n        self.select_text(pos, pos + search_size)\n\ndef find_prev(self, search, use_regex=False, case=False):\n    '''Find the previous occurrence of the string according to the cursor\n    position\n    '''\n    text = self.text\n    if not case:\n        text = text.upper()\n        search = search.upper()\n    lines = text.splitlines()\n\n    col = self.cursor_col\n    row = self.cursor_row\n    lines = lines[:row + 1]\n    lines.reverse()\n    line_number = len(lines)\n\n    found = -1\n    line = None\n    search_size = len(search)\n\n    for i, line in enumerate(lines):\n        i = line_number - i - 1\n        if use_regex:\n            if i == row:\n                line_find = line[:col]\n            else:\n                line_find = line[:]\n            found = re.search(search, line_find)\n            if found:\n                search_size = len(found.group(0))\n                found = found.start()\n            else:\n                found = -1\n        else:\n            # if on current line, consider col\n            if i == row:\n                found = line[:col].find(search)\n            else:\n                found = line.find(search)\n        # has found the string. found variable indicates the initial po\n        if found != -1:\n            self.cursor = (found, i)\n            break\n\n    if found != -1:\n        pos = text.find(line) + found\n        self.select_text(pos, pos + search_size)\n"
  },
  {
    "path": "kivystudio/widgets/dropdown.py",
    "content": "from kivystudio.behaviors import HoverBehavior\nfrom kivy.uix.dropdown import DropDown\nfrom kivy.properties import ObjectProperty, BooleanProperty\nfrom kivy.lang import Builder\n\n\nBuilder.load_string('''\n<MenuDropDownBase>:\n    canvas.after:\n        Color:\n            rgba: 0,0,0,.6\n        Line:\n            rectangle: [self.x, self.y, self.width, self.height]\n    canvas.before:\n        BorderImage:\n            source: 'shadow32.png'\n            border: (26, 26, 26, 26)\n            size:(root.width + 68, root.height + 68)\n            pos: (root.x-36, root.y-36)\n''')\n\nclass DropDownBase(HoverBehavior, DropDown):\n    ''' Base widget for DropDown widget.\n        usually when mouse is right clicked'''\n    \n    is_open = ObjectProperty(False)\n    \n    auto_touch_dismiss = BooleanProperty(True)\n\n    def on_open(self):\n        self.is_open = True\n\n    def on_dismiss(self):\n        self.is_open = False\n\n    def on_touch_up(self, touch):\n        if self.collide_point(*touch.pos):\n            if self.auto_touch_dismiss:\n                self.dismiss()\n        \n        return super(DropDownBase,self).on_touch_up(touch)\n\n"
  },
  {
    "path": "kivystudio/widgets/filemanager/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2019 Mahart Studios <mahartstudio.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "kivystudio/widgets/filemanager/README.md",
    "content": "================\nFileManager\n================\n\nA comprehensive file chooser intensively designed for the for desktop platform\nThe widget was originaly design and used for **kivy Studios **but is now available on kivy garden\n\n#### KivyStudio\n<!-- ![KivyStudio](https://raw.githubusercontent.com/MichaelStott/KivMob/master/demo/assets/kivmob-title.png) -->\n\n[![Build Status](https://travis-ci.com/MichaelStott/KivMob.svg?branch=master)](https://travis-ci.com/MichaelStott/KivMob)\n[![PyPI version](https://badge.fury.io/py/kivmob.svg)](https://badge.fury.io/py/kivmob)\n[![Python](https://img.shields.io/badge/python-2.7-green.svg)](https://www.python.org/downloads/release/python-270/)\n[![Downloads](https://pepy.tech/badge/kivmob)](https://pepy.tech/project/kivmob)\n[![Maintainability](https://api.codeclimate.com/v1/badges/add8cd9bd9600d898b79/maintainability)](https://codeclimate.com/github/MichaelStott/KivMob/maintainability)\n\nSimple method\n\n```python\nfilemanager.open_file(path='.', callback=callback)\n\nfilemanager.save_file(path='.', callback=callback)\n\nfilemanager.choose_dir(path='.', callback=callback)\n```\n\n### Installation\n\n```\ngarden install garden.filemanager\n```\n\n\n### Quickstart\n\n\n```python\nfrom kivy.uix.button import Button\nfrom kivy.garden.filemanager import filemanager\n\ndef callback(path):\n  (path)\n\ndef open_file(*a):\n  filemanager.open_file(path='.', callback=callback)\n\nbtn = Button(text='Push Me')\nbtn.bind(on_release=open_file)\n\nif __name__ == '__main__':\n\tMyApp().run()\n```\n\n### FileManager being used in Kivy Studio\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/mahart-studio/kivystudio/master/resources/showcase/Screenshot(3).png\">\n</p>\n\n### FileManager Showcase\n\n_Please contact us via pull request or project issue if you would like your app featured in this README and the documentation._\n\n\n### Other\n\n<!-- Links pertinent to README -->\n[Kivy]: <https://kivy.org/>\n[KivyStudio]: <https://mahartstudio.com/kivystudio/>\n[Buildozer]: <https://github.com/kivy/buildozer>\n\n<!-- App showcase author links -->\n<p align=\"center\">\n    <a href='<https://mahartstudio.com>'> <b>Mahart Studio</b> </a>\n</p>\n\n[avour]: <https://github.com/avour>"
  },
  {
    "path": "kivystudio/widgets/filemanager/__init__.py",
    "content": "\nfrom .filechooserthumbview import StudioFileChooserThumbView\n\nfrom kivy.uix.modalview import ModalView\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.button import Button\n\nfrom kivy.properties import ObjectProperty, OptionProperty\nfrom kivy.factory import Factory\nfrom kivy.core.window import Window\nfrom kivy.utils import platform\nfrom kivy.lang import Builder\n\nimport os\nfrom functools import partial\n\nfrom kivystudio.behaviors import HighlightBehavior\nfrom kivystudio.widgets.splitter import StudioSplitter\n\nfile_path = os.path.dirname(__file__)\n\nfrom kivy.resources import resource_add_path\nresource_add_path(os.path.join(file_path, 'images'))\nresource_add_path(os.path.join(file_path, 'file_formats'))\n\nBuilder.load_file(os.path.join(file_path,'filemanager.kv'))\n\n# filepath_for_cool_icons ='/usr/share/icons/Vibrancy-Kali/apps/64'\n\n\nclass SideSelector_(HighlightBehavior, FocusBehavior, GridLayout):\n    pass\n\n\nclass SideButton_(Button):\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            self.parent.set_highlighted(self)\n\n        return super(SideButton_, self).on_touch_down(touch)\n\nclass FileManager(ModalView):\n\n    _dir_selector = ObjectProperty(None)\n    '''internal widget used to show and display the current dir path'''\n\n    _file_chooser = ObjectProperty(None)\n    ''' the internal file chooser a subclass of FileChooserController'''\n\n    mode = OptionProperty('open_file', options=['open_file', 'save_file', 'choose_dir'])\n\n    __events__ = ('on_finished', )\n\n    def __init__(self, **k):\n        super(FileManager, self).__init__(**k)\n        self.new_bub = Factory.NewFolderBub_()\n        self.new_bub.ids.input.bind(on_text_validate=self.create_new_folder)\n        self._file_chooser.path = self.get_defualt_user_dir()\n\n        # self.mode = 'save_file'\n\n    def get_defualt_user_dir(self):\n        default_dir = None\n        if platform == 'linux':\n            username = os.getlogin()\n            if username != 'root':\n                default_dir = r'/home/%s'%username\n            else:\n                default_dir = r'/root'\n\n        elif platform == 'win':\n            base = os.getcwd().split(\"\\\\\")[:3]\n            default_dir = \"\\\\\".join(base)\n\n        return default_dir\n\n    def set_side_panel_dir(self, name):\n        user_dir = self.get_defualt_user_dir()\n\n        self._file_chooser.path = os.path.join(user_dir, name)\n\n    def on_path(self, path):\n        path_list = path.split('/')\n\n        self._dir_selector.clear_widgets()\n        for i in path_list:\n            if i:\n                btn = Factory.DirButton_(size_hint=(None,1), text=str(i))\n\n                btn.bind(on_release=partial(self._go_dir_with_btn, btn))\n\n                if btn.width <= btn.texture_size[0]:\n                    btn.width = btn.texture_size[0]+10\n\n                self._dir_selector.add_widget(btn)\n        else:\n            if i:\n                self.ids.dir_scroll.scroll_to(btn)\n\n    def _go_dir_with_btn(self, btn, *args):\n        path_list = []\n        children = self._dir_selector.children[:]\n        children.reverse()\n        for child in children:\n            path_list.append(child.text)\n            if child == btn:\n                break\n\n        self._file_chooser.path = '/'+ '/'.join(path_list)\n\n    def on_open(self):\n        Window.bind(on_key_down=self.handle_key)\n\n    def on_dismiss(self):\n        Window.unbind(on_key_down=self.handle_key)\n        # remove bubble if open\n        if self.new_bub in Window.children:\n            Window.remove_widget(self.new_bub)\n\n    def handle_key(self, keyboard, key, codepoint, text, modifier, *args):\n        if key == 8:    # if user press the backspace reverse dir\n            if self.mode!='save_file' or (hasattr(self,'save_widget') \\\n                 and not(self.save_widget.ids.input.focus)):\n                self.reverse_dir()\n        elif key == 27:\n            self.handle_escape()\n        elif key == 13:     # enter\n            pass\n\n    def reverse_dir(self):\n        previous_path = os.path.dirname(self._file_chooser.path)\n\n        if os.path.exists(previous_path):\n            self._file_chooser.path = previous_path\n\n    def on_mode(self, *args):\n        if hasattr(self, 'save_widget') and \\\n                self.save_widget in self.ids.saving_container.children:\n               self.ids.saving_container.remove_widget(self.save_widget)\n        if hasattr(self, 'folder_btn') and \\\n            self.folder_btn in self.ids.saving_container.children:\n            self.ids.saving_container.remove_widget(self.folder_btn)\n\n        if self.mode == 'save_file':\n            self.ids.title.text = 'Save file'\n            if not hasattr(self, 'save_widget'):\n                self.save_widget = Factory.SaveWidget_()\n                self.save_widget.ids.input.bind(on_text_validate=self.handle_saving)\n                func = lambda *args: self.handle_saving(self.save_widget.ids.input)\n                self.save_widget.ids.save_btn.bind(on_release=func)\n            self.ids.saving_container.add_widget(self.save_widget)\n\n        else:\n            if self.mode == 'open_file':\n                self.ids.title.text = 'Open file'\n\n            elif self.mode == 'choose_dir':\n                self.ids.title.text = 'Open folder'\n\n                if not hasattr(self, 'folder_btn'):\n                    self.folder_btn = Factory.DirButton_(text='Select')\n                    self.folder_btn.bind(on_release=self.folder_selected)\n                self.ids.saving_container.add_widget(self.folder_btn)\n    \n    def folder_selected(self, *args):\n        path=self.ids.file_chooser.ids.stacklayout.current_highlighted_child.path\n        self.dispatch('on_finished', path)\n\n    def handle_escape(self):\n        if self.new_bub in Window.children:\n            Window.remove_widget(self.new_bub)\n        else:\n            self.dismiss()        \n\n    def handle_bubble(self, btn):\n        if self.new_bub in Window.children:\n            Window.remove_widget(self.new_bub)\n        else:\n            self.new_bub.pos = (btn.x - (self.new_bub.width-btn.width), btn.y - self.new_bub.height)\n            Window.add_widget(self.new_bub)\n\n    def create_new_folder(self, textinput):\n        path = os.path.join(self._file_chooser.path, textinput.text)\n        if not os.path.exists(path):\n            print('making folder ', path)\n            try:\n                os.mkdir(path)\n\n                # a simple trick to force the file chooser to recompute the files\n                former_path = self._file_chooser.path\n                self._file_chooser.path = 'eeraef7h98fwb38rh3f8h23yr8i'  # change to an invaid path\n                self._file_chooser.path = former_path       # then change back\n                Window.remove_widget(self.new_bub)\n\n            except OSError:\n                print('error making dir')\n        else:\n            print('already exists')\n\n    def handle_saving(self, textinput):\n        path = os.path.join(self._file_chooser.path, textinput.text)\n        if not os.path.exists(path):\n            self.dispatch('on_finished', path)\n        else:\n            print('file already exist')\n\n    def file_selected(self, obj, path):\n        if self.mode == 'open_file':\n            self.dispatch('on_finished', path)\n            self.dismiss()\n\n    def on_finished(self, path):\n        self.on_selection([path])\n        self.dismiss()\n\n    def open_file(self, path='', on_selection=None):\n        self.mode = 'open_file'\n        self.on_selection = on_selection\n        self.open()\n\n    def save_file(self, path='', on_selection=None):\n        self.mode = 'save_file'\n        self.on_selection = on_selection\n        self.open()\n        \n    def choose_dir(self, path='', on_selection=None):\n        self.mode = 'choose_dir'\n        self.on_selection = on_selection\n        self.open()\n\nfilemanager = FileManager()\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n\n    file_picker = FileManager()\n    btn = Button(text='push me')\n    btn.bind(on_release=lambda *args: file_picker.open())\n    runTouchApp(btn)\n"
  },
  {
    "path": "kivystudio/widgets/filemanager/filechooserthumbview/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-2014 Davide Depau <me AT davideddu DOR org>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "kivystudio/widgets/filemanager/filechooserthumbview/__init__.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"StudioFileChooserThumbView\n====================\n\nThe StudioFileChooserThumbView widget is similar to FileChooserIconView,\nbut if possible it shows a thumbnail instead of a normal icon.\n\nUsage\n-----\n\nYou can set some properties in order to control its performance:\n\n* **showthumbs:** Thumbnail limit. If set to a number > 0, it will show the\nthumbnails only if the directory doesn't contain more files or directories.\nIf set to 0 it won't show any thumbnail. If set to a number < 0 it will always\nshow the thumbnails, regardless of how many items the current directory\ncontains. By default it is set to -1, so it will show all the thumbnails.\n* **thumbdir:** Custom directory for the thumbnails. By default it uses\ntempfile to generate it randomly.\n* **thumbsize:** The size of the thumbnails. It defaults to 64d\n\"\"\"\n\n# Thanks to allan-simon for making the code more readable and less \"spaghetti\" :)\n\nimport os\nfrom os.path import abspath, dirname\nimport mimetypes\n\n#(enable for debugging)\nimport traceback\nimport shutil\nimport subprocess\nfrom threading import Thread\nfrom os.path import join, exists, dirname\nfrom tempfile import mktemp, mkdtemp\n\nfrom kivy.app import App\nfrom kivy.lang import Builder\nfrom kivy.metrics import dp\nfrom kivy.utils import QueryDict\nfrom kivy.properties import StringProperty\nfrom kivy.properties import DictProperty\nfrom kivy.properties import ObjectProperty\nfrom kivy.properties import BooleanProperty\nfrom kivy.properties import NumericProperty\nfrom kivy.uix.filechooser import FileChooserController\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.uix.stacklayout import StackLayout\nfrom kivy.uix.gridlayout import GridLayout\n\nfrom kivystudio.behaviors import HighlightBehavior\n\n\n# directory with this package\n_path = os.path.dirname(os.path.realpath(__file__))\nBuilder.load_string(\"\"\"\n#: import Clock kivy.clock.Clock\n\n<StudioFileChooserThumbView>:\n    stacklayout: stacklayout\n    on_entry_added: stacklayout.add_widget(args[1])\n    on_entries_cleared: stacklayout.clear_widgets()\n    scrollview: scrollview\n\n    ScrollView:\n        id: scrollview\n\n        FileStack_:\n            id: stacklayout\n            filechooser: root\n            width: scrollview.width\n            size_hint_y: None\n            height: self.minimum_height\n            spacing: '10dp'\n            padding: '10dp'\n            highlighted_shape: 'rounded_rectangle'\n            highlight_orientation: 'grid'\n            auto_scroll_to: True\n            on_size: Clock.schedule_once(lambda dt: setattr(self, 'grid_len', int(self.width/(self.children[0].width+10))), 1)\n\n[StudioFileThumbEntry@IconWidget_]:\n    image: image\n    locked: False\n    path: ctx.path\n    selected: self.path in ctx.controller().selection\n    size_hint: None, None\n    cols: 1\n    size: ctx.controller().thumbsize + dp(52), self.minimum_height\n    on_double_tap: ctx.controller().entry_released(self, args[1])\n    canvas:\n        Color:\n            rgba: 1, 1, 1, 1 if self.selected else 0\n        BorderImage:\n            border: 8, 8, 8, 8\n            pos: root.pos\n            size: root.size\n            source: 'atlas://data/images/defaulttheme/filechooser_selected'\n\n    AsyncImage:\n        id: image\n        size_hint: 1, None\n        size: ctx.controller().thumbsize, ctx.controller().thumbsize\n        # pos: root.x + dp(24), root.y + dp(40)\n    Label:\n        size_hint: 1, None\n        text: ctx.name\n        text_size: (ctx.controller().thumbsize + dp(20), None)\n        halign: 'center'\n        size: ctx.controller().thumbsize + dp(10), self.texture_size[1]\n        color: 0,0,0,1\n        valign: 'top'\n        shorten_from: 'right'\n\n\n<IconWidget_>:\n\n    \"\"\")\n\nDEFAULT_THEME = 'atlas://data/images/defaulttheme/'\nFILE_ICON = DEFAULT_THEME + 'filechooser_file'\nFOLDER_ICON = DEFAULT_THEME + 'filechooser_folder'\nUNKWON_ICON=DEFAULT_THEME + 'filechooser_file'\n\nICON_PATH = dirname(dirname(__file__)) + '/file_formats/'\nMP3_ICON = ICON_PATH + 'music.png'\nVIDEO_ICON = ICON_PATH + 'video.png'\nPYTHON_ICON = ICON_PATH + 'python.png'\nKV_ICON = ICON_PATH + 'kv.png'\nJAVA_ICON = ICON_PATH + 'java.png'\nPDF_ICON = ICON_PATH + 'pdf.png'\nARCHIVE_ICON = ICON_PATH + 'archive.png'\n# UNKWON_ICON = '.png'\n\n\n\nARCHIVES_MIME = ('application/zip', 'application/x-tar',)\nAPK_MIME = 'application/vnd.android.package-archive'\nEXE_MIME = 'application/x-msdos-program'\nPDF_MIME = 'application/pdf'\n##############################\nFLAC_MIME = \"audio/flac\"\nMP3_MIME = \"audio/mpeg\"\nPYTHON_MIME = \"text/x-python\"\nJAVA_MIME = \"text/x-java\"\n\nAVCONV_BIN = 'avconv'\nFFMPEG_BIN = 'ffmpeg'\nCONVERT_BIN = 'convert'\n\nclass IconWidget_(GridLayout):\n    'Internal widget used to display files'\n\n    def __init__(self, **kwargs):\n        super(IconWidget_, self).__init__(**kwargs)\n        self.register_event_type('on_double_tap')\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            if touch.is_double_tap:\n                self.dispatch('on_double_tap', touch)\n                return True\n            else:\n                self.parent.set_highlighted(self)\n                return True\n        \n        return super(IconWidget_, self).on_touch_down(touch)\n\n    def on_double_tap(self, touch):\n        if os.path.isfile(self.path):\n            self.parent.parent.parent.dispatch('on_file_select', self.path)\n            \n\nclass FileStack_(HighlightBehavior, FocusBehavior, StackLayout):\n    \n    # overiding enter from highlightbehavior\n    def do_enter(self):\n        new_path = self.current_highlighted_child.path\n        if os.path.isdir(new_path):\n            if new_path=='../': # move back\n                new_path = os.path.dirname(self.filechooser.path)\n            self.filechooser.path = new_path\n        elif os.path.isfile(new_path):\n            self.filechooser.dispatch('on_file_select', new_path)\n\nclass StudioFileChooserThumbView(FileChooserController):\n    '''Implementation of :class:`FileChooserController` using an icon view\n    with thumbnails.\n    '''\n    _ENTRY_TEMPLATE = 'StudioFileThumbEntry'\n\n    thumbdir = StringProperty(mkdtemp(prefix=\"kivy-\", suffix=\"-thumbs\"))\n    '''Custom directory for the thumbnails. By default it uses tempfile to\n    generate it randomly.\n    '''\n\n    showthumbs = NumericProperty(-1)\n    '''Thumbnail limit. If set to a number > 0, it will show the thumbnails\n    only if the directory doesn't contain more files or directories. If set\n    to 0 it won't show any thumbnail. If set to a number < 0 it will always\n    show the thumbnails, regardless of how many items the current directory\n    contains.\n    By default it is set to -1, so it will show all the thumbnails.\n    '''\n\n    thumbsize = NumericProperty(dp(64))\n    \"\"\"The size of the thumbnails. It defaults to 64dp.\n    \"\"\"\n\n    play_overlay = StringProperty(os.path.join(_path, 'play_overlay.png'))\n    \"\"\"Path to a PIL supported image file (e.g. png) that will be put over\n    videos thumbnail (e.g. a \"play\" button). If it's an empty string nothing\n    will happen.\n    Defaults to \"\".\n    \"\"\"\n\n    stacklayout = ObjectProperty(None)\n\n    filmstrip_left = StringProperty(\"\")\n\n    filmstrip_right = StringProperty(\"\")\n\n    _thumbs = DictProperty({})\n    scrollview = ObjectProperty(None)\n\n    def __init__(self, **kwargs):\n        super(StudioFileChooserThumbView, self).__init__(**kwargs)\n        self.register_event_type('on_file_select')\n        self.thumbnail_generator = ThreadedThumbnailGenerator()\n        if not exists(self.thumbdir):\n            os.mkdir(self.thumbdir)\n\n    def clear_cache(self, *args):\n        try:\n            shutil.rmtree(self.thumbdir, ignore_errors=True)\n        except:\n            traceback.print_exc()\n\n    def _dir_has_too_much_files(self, path):\n        if (self.showthumbs < 0):\n            return False\n\n        nbrFileInDir = len(\n            os.listdir(dirname(path))\n        )\n        return nbrFileInDir > self.showthumbs\n\n    def _create_entry_widget(self, ctx):\n        # instantiate the widget\n        widget = super(StudioFileChooserThumbView, self)._create_entry_widget(ctx)\n\n        kctx = QueryDict(ctx)\n        # default icon\n        widget.image.source = FOLDER_ICON if kctx.isdir else UNKWON_ICON\n        # schedule generation for later execution\n        self.thumbnail_generator.append(widget.image, kctx, self._get_image)\n        self.thumbnail_generator.run()\n        return widget\n\n    def _get_image(self, ctx):\n        try:\n            App.get_running_app().bind(on_stop=self.clear_cache)\n        except AttributeError:\n            pass\n        except:\n            traceback.print_exc()\n            \n        if ctx.isdir:\n            return FOLDER_ICON\n\n        # if the directory contains more files\n        # than what has been configurated\n        # we directly return a default file icon\n        if self._dir_has_too_much_files(ctx.path):\n            return FILE_ICON\n\n        try:\n            mime = get_mime(ctx.name)\n\n            # if we already have generated the thumb\n            # for this file, we get it directly from our\n            # cache\n            if ctx.path in self._thumbs.keys():\n                return self._thumbs[ctx.path]\n\n            # if it's a picture, we don't need to do\n            # any transormation\n            if is_picture(mime, ctx.name):\n                return ctx.path\n\n            # for mp3/flac an image can be embedded\n            # into the file, so we try to get it\n            if mime == MP3_MIME:\n                return self._generate_image_from_mp3(\n                    ctx.path\n                )\n\n            if mime == FLAC_MIME:\n                return self._generate_image_from_flac(\n                    ctx.path\n                )\n\n            if mime == PYTHON_MIME:\n                return PYTHON_ICON \n\n            if mime == JAVA_MIME:\n                return JAVA_ICON \n\n            if mime in ARCHIVES_MIME:\n                return ARCHIVE_ICON\n\n            if mime == PDF_MIME:\n                return PDF_ICON\n\n            # if it's a video we will extract a frame out of it\n            if \"video/\" in mime:\n                return self._generate_image_from_video(ctx.path)\n\n            extention = os.path.splitext(ctx.name)[1]\n            if extention  == '.kv':\n                return KV_ICON\n\n        except:\n            traceback.print_exc()\n            return FILE_ICON\n\n        return FILE_ICON\n\n    def _generate_image_from_flac(self, flacPath):\n        # if we don't have the python module to\n        # extract image from flac, we just return\n        # default file's icon\n        try:\n            from mutagen.flac import FLAC\n        except ImportError:\n            return FILE_ICON\n\n        try:\n            audio = FLAC(flacPath)\n            art = audio.pictures\n\n            return self._generate_image_from_art(\n                art,\n                flacPath\n            )\n        except(IndexError, TypeError):\n            return FILE_ICON\n\n    def _generate_image_from_mp3(self, mp3Path):\n        # if we don't have the python module to\n        # extract image from mp3, we just return\n        # default file's icon\n        try:\n            from mutagen.id3 import ID3\n        except ImportError:\n            return MP3_ICON\n\n        try:\n            audio = ID3(mp3Path)\n            art = audio.getall(\"APIC\")\n            return self._generate_image_from_art(\n                art,\n                mp3Path\n            )\n        except(IndexError, TypeError):\n            return MP3_ICON\n    def _generate_image_from_art(self, art, path):\n        pix = pix_from_art(art)\n        ext = mimetypes.guess_extension(pix.mime)\n        if ext == 'jpe':\n            ext = 'jpg'\n\n        image = self._generate_image_from_data(\n            path,\n            ext,\n            pix.data\n        )\n\n        self._thumbs[path] = image\n        return image\n\n    def _gen_temp_file_name(self, extension):\n        return join(self.thumbdir, mktemp()) + extension\n\n    def _generate_image_from_data(self, path, extension, data):\n        # data contains the raw bytes\n        # we save it inside a file, and return this file's temporary path\n\n        image = self._gen_temp_file_name(extension)\n        with open(image, \"w\") as img:\n            img.write(data)\n        return image\n\n    def _generate_image_from_video(self, videoPath):\n        # we try to use an external software (avconv or ffmpeg)\n        # to get a frame as an image, otherwise => default file icon\n        data = extract_image_from_video(videoPath, self.thumbsize, self.play_overlay)\n\n        try:\n            if data:\n                return self._generate_image_from_data(\n                    videoPath,\n                    \".png\",\n                    data)\n            else:\n                return VIDEO_ICON\n        except:\n            traceback.print_exc()\n            return VIDEO_ICON\n\n\n    def _gen_label(self, ctx):\n        size = ctx.get_nice_size()\n        temp = \"\"\n        try:\n            temp = os.path.splitext(ctx.name)[1][1:].upper()\n        except IndexError:\n            pass\n        if ctx.name.endswith(\".tar.gz\"):\n            temp = \"TAR.GZ\"\n        if ctx.name.endswith(\".tar.bz2\"):\n            temp = \"TAR.BZ2\"\n        if temp == \"\":\n            label = size\n        else:\n            label = size + \" - \" + temp\n        return label\n\n    def on_file_select(self, path):\n        pass\n\n\nclass ThreadedThumbnailGenerator(object):\n    \"\"\"\n    Class that runs thumbnail generators in a another thread and\n    asynchronously updates image widgets\n    \"\"\"\n    def __init__(self):\n        self.thumbnail_queue = []\n        self.thread = None\n\n    def append(self, widget, ctx, func):\n        self.thumbnail_queue.append([widget, ctx, func])\n\n    def run(self):\n        if self.thread is None or not self.thread.is_alive():\n            self.thread = Thread(target=self._loop)\n            self.thread.start()\n\n    def _loop(self):\n        while len(self.thumbnail_queue) != 0:\n            # call user function that generates the thumbnail\n            image, ctx, func = self.thumbnail_queue.pop(0)\n            image.source = func(ctx)\n\n\n# test if the file is a supported picture\n# file\ndef is_picture(mime, name):\n    if mime is None:\n        return False\n\n    return \"image/\" in mime and (\n            \"jpeg\" in mime or\n            \"jpg\" in mime or\n            \"gif\" in mime or\n            \"png\" in mime\n        ) and not name.endswith(\".jpe\")\n\n\ndef pix_from_art(art):\n    pix = None\n    if len(art) == 1:\n        pix = art[0]\n    elif len(art) > 1:\n        for pic in art:\n            if pic.type == 3:\n                pix = pic\n    if not pix:\n        # This would raise an exception if no image is present,\n        # and the default one would be returned\n        pix = art[0]\n    return pix\n\n\ndef get_mime(fileName):\n    try:\n        mime = mimetypes.guess_type(fileName)[0]\n        if mime is None:\n            return \"\"\n        return mime\n    except TypeError:\n        return \"\"\n\n    return \"\"\n\n\ndef extract_image_from_video(path, size, play_overlay):\n    data = None\n    if exec_exists(AVCONV_BIN):\n        data = get_png_from_video(AVCONV_BIN, path, int(size), play_overlay)\n    elif exec_exists(FFMPEG_BIN):\n        data = get_png_from_video(FFMPEG_BIN, path, int(size), play_overlay)\n    return data\n\n\n# generic function to call a software to extract a PNG\n# from an video file, it return the raw bytes, not an\n# image file\ndef get_png_from_video(software, video_path, size, play_overlay):\n    return subprocess.Popen(\n        [\n            software,\n            '-i',\n            video_path,\n            '-i',\n            play_overlay,\n            '-filter_complex',\n            '[0]scale=-1:' + str(size) + '[video],[1]scale=-1:' + str(size) + '[over],' +\n                '[video][over]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2',\n            '-an',\n            '-vcodec',\n            'png',\n            '-vframes',\n            '1',\n            '-ss',\n            '00:00:01',\n            '-y',\n            '-f',\n            'rawvideo',\n            '-'\n        ],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE\n    ).communicate()[0]\n\ndef stack_images(software, bg, fg, out):\n    # You need ImageMagick to stack one image onto another\n    p = subprocess.Popen([software, bg, \"-gravity\", \"Center\", fg, \"-compose\", \"Over\", \"-composite\", out])\n    p.wait()\n\ndef exec_exists(bin):\n    try:\n        subprocess.check_output([\"which\", bin])\n        return True\n    except subprocess.CalledProcessError:\n        return False\n    except OSError:\n        return False\n    except:\n        return False\n\ndef compute_size(maxs, imgw, imgh):\n    if imgw > imgh:\n        return maxs, maxs*imgh/imgw\n    else:\n        return maxs*imgw/imgh, maxs\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.uix.label import Label\n\n    box = BoxLayout(orientation=\"vertical\")\n    fileChooser = StudioFileChooserThumbView(thumbsize=128)\n    label = Label(markup=True, size_hint_y=None)\n    fileChooser.mylabel = label\n\n    box.add_widget(fileChooser)\n    box.add_widget(label)\n\n    def setlabel(instance, value):\n        instance.mylabel.text = \"[b]Selected:[/b] {0}\".format(value)\n\n    fileChooser.bind(selection=setlabel)\n\n    runTouchApp(box)\n"
  },
  {
    "path": "kivystudio/widgets/filemanager/filemanager.kv",
    "content": "#: import win kivy.core.window.Window\n#: import Clock kivy.clock.Clock\n\n\n<FileManager>:\n    _dir_selector: dir_selector\n    _file_chooser: file_chooser\n    background: 'invisible.png'\n    background_color: 0,0,0,0\n    size_hint: None, None\n    size: win.width * 0.65, win.height * 0.7\n    auto_dismiss: False\n    on_open: _side_selector.width = dp(130)\n    canvas.before:\n        BorderImage:\n            source: 'shadow32.png'\n            border: (26, 26, 26, 26)\n            size:(root.width + 68, root.height + 68)\n            pos: (root.x-36, root.y-36)\n\n    BoxLayout:\n        orientation: 'vertical'\n        BoxLayout:\n            size_hint_y: None\n            height: '40dp'\n            canvas.before:\n                Color:\n                    rgba: .8,.8,.8,1\n                RoundedRectangle:\n                    size: self.size\n                    pos: self.pos\n                    radius: [(10.0, 10.0), (10.0, 10.0), (0, 0), (0, 0)]\n\n            Label:\n                id: title\n                color: 0,0,0,1\n                bold: True\n            ImageButton_:\n                size: '32dp', '32dp'\n                size_hint: None,None\n                pos_hint: {'center_y': .5, 'center_x': .5}\n                source: 'window_cancel.png'\n                on_release: root.dismiss()\n\n        BoxLayout:\n            SideSelector_:\n                id: _side_selector\n                size_hint_x: None\n                width: '130dp'\n                cols: 1\n                canvas.before:\n                    Color:\n                        rgba: .9,.9,.9,1\n                    Rectangle:\n                        size: self.size\n                        pos: self.pos\n\n                SideButton_:\n                    text: 'Home'\n                    source: 'small_home.png'\n                    on_release: file_chooser.path = root.get_defualt_user_dir()\n                SideButton_:\n                    text: 'Documents'\n                    source: 'small_document.png'\n                    on_release: root.set_side_panel_dir(self.text)\n                SideButton_:\n                    text: 'Downloads'\n                    source: 'small_download.png'\n                    on_release: root.set_side_panel_dir(self.text)\n                SideButton_:\n                    text: 'Desktop'\n                    source: 'small_folder.png'\n                    on_release: root.set_side_panel_dir(self.text)\n                SideButton_:\n                    text: 'Pictures'\n                    source: 'small_picture.png'\n                    on_release: root.set_side_panel_dir(self.text)\n                SideButton_:\n                    text: 'Music'\n                    source: 'small_music.png'\n                    on_release: root.set_side_panel_dir(self.text)\n                SideButton_:\n                    text: 'Videos'\n                    source: 'small_video.png'\n                    on_release: root.set_side_panel_dir(self.text)\n\n            StudioSplitter:\n                min_size: self.parent.width*0.7\n                max_size: max(self.parent.width*0.8, dp(130))\n                on_right:\n                    self.right=self.parent.right;\n                    _side_selector.width = self.parent.width-self.width\n                BoxLayout:\n                    orientation: 'vertical'\n                    canvas.before:\n                        Color:\n                            rgba: 1,1,1,1\n                        Rectangle:\n                            size: self.size\n                            pos: self.pos\n                    BoxLayout:\n                        size_hint_y: None\n                        height: '48dp'\n\n                        ScrollView:\n                            id: dir_scroll\n                            canvas.after:\n                                Color:\n                                    rgba: .5,.5,.5,.5\n                                Line:\n                                    points: [self.x, self.y, self.right, self.y]\n                            BoxLayout:\n                                size_hint_x: None\n                                width: self.minimum_width\n                                padding: '6dp'\n                                spacing: '4dp'\n                                rows: 1\n                                id: dir_selector\n                        ImageButton_:\n                            source: 'new_folder.png'\n                            size: '40dp', '40dp'\n                            size_hint: None,None\n                            on_release: root.handle_bubble(self)\n\n\n                    BoxLayout:\n                        StudioFileChooserThumbView:\n                            id: file_chooser\n                            on_path: root.on_path(self.path)\n                            on_file_select: root.file_selected(*args)\n                            # progress_cls: 'Widget'\n\n        BoxLayout:\n            id: saving_container\n            size_hint_y: None\n            height: max(dp(10), self.minimum_height)\n            padding: '6dp'\n            canvas.before:\n                Color:\n                    rgba: 1,1,1,1\n                RoundedRectangle:\n                    size: self.size\n                    pos: self.pos\n                    radius: [(0, 0), (0, 0), (10.0, 10.0), (10.0, 10.0)]\n\n\n<SideButton_>:\n    background_normal: ''\n    background_color: .9,.9,.9,1\n    source: ''\n    color: .6,.6,.6,1\n    size_hint_y: None\n    height: '40dp'\n    BoxLayout:\n        size: root.size\n        pos: root.pos\n        Image:\n            size_hint_x: None\n            width: '40dp'\n            source: root.source\n\n\n<DirButton_@Button>:\n    background_normal: ''\n    background_color: .9,.9,.9,1\n    color: 0,0,0,1\n    size_hint: (None, None)\n    width: self.texture_size[0] + dp(20)\n    height: '40dp'\n    dir_path: ''\n\n<ImageButton_@Button>:\n    background_normal: ''\n    source: ''\n    background_color: 0,0,0,0\n    Image:\n        size: root.size\n        pos: root.pos\n        source: root.source\n\n\n<NewFolderBub_@Bubble>:\n    size_hint: None,None\n    size: '180dp','90dp'\n    arrow_pos: 'top_right'\n    background_color: .6,.6,1,.8\n    on_parent: input.focus =True\n    BoxLayout:\n        padding: '5dp'\n        orientation: 'vertical'\n        Label:\n            text: 'Folder Name'\n            bold: True\n        TextInput:\n            id: input\n            size_hint_y: None\n            height: '36dp'\n            cursor_color: .2,.2,.2,1\n            multiline: False\n\n<SaveWidget_@BoxLayout>:\n    size_hint_y: None\n    height: '60dp'\n    on_parent: input.focus =True\n    Label:\n        size_hint_x: None\n        width: self.texture_size[0] + dp(10)\n        text: 'Name'\n        bold: True\n        color: .3,.3,.3,1\n    TextInput:\n        id: input\n        size_hint_y: None\n        height: '36dp'\n        cursor_color: .2,.2,.2,1\n        multiline: False\n        pos_hint: {'center_y': .5}\n        text: 'Untitled-1'\n    Button:\n        id: save_btn\n        text: 'Save'\n        size_hint: None, None\n        background_normal: 'button.png'\n        background_color: .5,.5,.5,1\n        width: self.texture_size[0] + dp(16)\n        height: self.texture_size[1] + dp(10)\n        pos_hint: {'center_y': .5}\n"
  },
  {
    "path": "kivystudio/widgets/iconlabel.py",
    "content": "from kivy.uix.label import Label\nfrom kivy.uix.behaviors import ToggleButtonBehavior, ButtonBehavior\nfrom kivy import properties as prop\nfrom kivy.lang import Builder\n\nfrom kivystudio.behaviors import HoverBehavior, HoverInfoBehavior\n\nclass IconLabel(HoverInfoBehavior, Label):\n    icon = prop.StringProperty('')\n    icon_size = prop.NumericProperty(16)\n\n    def __init__(self, **k):\n        super(IconLabel, self).__init__(**k)\n        self.markup=True\n\n\nclass IconLabelButton(ButtonBehavior, IconLabel):\n    pass\n\nclass IconToggleLabel(ToggleButtonBehavior, IconLabel):\n    \n    icon_down = prop.StringProperty()\n    icon_normal = prop.StringProperty()\n    \n    def on_state(self, *args):\n        if self.state=='down':\n            self.icon = self.icon_down\n        else:\n            self.icon = self.icon_normal\n\nBuilder.load_string('''\n<IconLabel>:\n    text: '%s'%(icon(self.icon, self.icon_size)) if self.icon else ''\n\n''')"
  },
  {
    "path": "kivystudio/widgets/rightclick_drop.py",
    "content": "from kivy.uix.boxlayout import BoxLayout\nfrom kivy.core.window import Window\nfrom kivy.lang import Builder\n\nfrom kivystudio.tools import set_auto_mouse_position\n\nclass RightClickDrop(BoxLayout):\n\n    def __init__(self, **kwargs):\n        super(RightClickDrop, self).__init__(**kwargs)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):  # touch should not unfocus input\n            pass\n        else:\n            self.dismiss()\n\n        return super(RightClickDrop,self).on_touch_down(touch)\n\n    def on_parent(self, *a):\n        if self.parent:\n            Window.bind(on_keyboard=self._on_keyboard)\n        else:\n            Window.unbind(on_keyboard=self._on_keyboard)\n\n    def _on_keyboard(self, instance, keycode, *args):\n\n        if keycode == 27:     # on escape\n            self.dismiss()\n            return True\n\n        return True\n\n    def open(self):\n        if self not in Window.children:\n            set_auto_mouse_position(self)\n            Window.add_widget(self)\n\n    def dismiss(self):\n        if self in Window.children:\n            Window.remove_widget(self)\n\n\n\nBuilder.load_string('''\n<RightClickDrop>:\n    orientation: 'vertical'\n    size: '260dp',self.minimum_height\n    size_hint: None,None\n    canvas.before:\n        BorderImage:\n            source: 'shadow32.png'\n            border: (26, 26, 26, 26)\n            size:(root.width + 50, root.height + 50)\n            pos: (root.x-25, root.y-25)\n''')\n"
  },
  {
    "path": "kivystudio/widgets/searchinput.py",
    "content": "from kivy.uix.textinput import TextInput\nfrom kivy.lang import Builder\n\nclass SearchInput(TextInput):\n    pass\n\nBuilder.load_string('''\n<SearchInput>:\n    canvas.after:\n        Color:\n            rgba: self.line_color\n        Line:\n            rectangle: [self.x,self.y,self.width,self.height]\n    foreground_color: 1,1,1,1\n    background_color: .1,.1,.12,1\n    line_color: .8,.8,.8,0\n    hint_text_color: .6,.6,.6,1\n    cursor_color: 1,1,1,1\n    size_hint_y: None\n    height: self.minimum_height\n    on_focus:\n        if self.focus: self.line_color=.8,.8,.8,1\n        else: line_color=.8,.8,.8,0\n    \n''')"
  },
  {
    "path": "kivystudio/widgets/splitter.py",
    "content": "from kivy.uix.splitter import Splitter, SplitterStrip\nfrom kivy.lang import Builder\nfrom kivy.core.window import Window\nfrom kivy.properties import BooleanProperty\n\nfrom kivystudio.behaviors import HoverBehavior\n\nBuilder.load_string('''\n#: import Factory kivy.factory.Factory\n\n<StudioSplitter>:\n    strip_cls: Factory.StudioSplitterStrip\n    strip_size: '4dp'\n\n<StudioSplitterStrip>\n    background_down: ''\n    background_normal: ''\n    background_color: .12,.12,.12,1\n\n ''')\n\nclass StudioSplitter(Splitter):\n    pass\n\nclass StudioSplitterStrip(HoverBehavior, SplitterStrip):\n\n    moving = BooleanProperty(False)\n\n    def on_hover(self, *args):\n        if self.hover:\n            Window.set_system_cursor('size_we')\n        else:\n            if not self.moving:\n                Window.set_system_cursor('arrow')\n\n    def on_press(self):\n        self.moving = True\n\n    def on_touch_up(self, touch):\n        if self.moving:\n            Window.set_system_cursor('arrow')\n            self.moving = False\n        \n        return super(StudioSplitterStrip, self).on_touch_up(touch)\n\n\nif __name__ == \"__main__\":\n    root = Builder.load_string('''\n    BoxLayout:\n        Button:\n            id: w1\n            size_hint_x: None\n            width: 200\n        StudioSplitter:\n            min_size: self.parent.width-200\n            max_size: max(self.parent.width*0.8, dp(130))\n            on_right: self.right=root.right; w1.width = root.width-self.width\n            Button:\n                text: 'Spit'\n    ''')\n    from kivy.base import runTouchApp\n    runTouchApp(root)\n"
  },
  {
    "path": "kivystudio/widgets/tabbedpanel.py",
    "content": "from kivy.properties import ObjectProperty\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.tabbedpanel import (TabbedPanel,\n            TabbedPanelContent, TabbedPanelHeader)\n\n\nclass StudioPanelItem(TabbedPanelHeader):\n    ''' Kivy Studio Panel Item for easy use,\n    acts exactly like the defualt kivy panelitem\n    just just has a custom header class so you can \n    specify you costume header class \n    '''\n\n    header_cls = ObjectProperty(None)\n\n    content = ObjectProperty(FloatLayout())\n\n    def __init__(self, **kwargs):\n        super(StudioPanelItem, self).__init__(**kwargs)\n\n    def add_widget(self, widget):\n        self.content.add_widget(widget)\n\n    def remove_widget(self, widget):\n        self.content.remove_widget(widget)\n"
  },
  {
    "path": "project/prjtTest1.htm",
    "content": ""
  },
  {
    "path": "project/prjtTest1.js",
    "content": ""
  },
  {
    "path": "repoTest1.js",
    "content": ""
  },
  {
    "path": "repoTest2.htm",
    "content": ""
  },
  {
    "path": "setup.py",
    "content": "'''\nSetup.py\n========\n'''\n\nfrom os.path import dirname, join, abspath\nimport io,os\n\ntry:\n    from setuptools import setup, find_packages\nexcept ImportError:\n    from distutils.core import setup, find_packages\n\n\nCURDIR = abspath(dirname(__file__))\n\nwith io.open(join(CURDIR, \"README.md\"), encoding=\"utf8\") as fd:\n    README = fd.read()\nwith io.open(join(CURDIR, \"LICENSE\"), encoding=\"utf8\") as fd:\n    LICENSE = fd.read()\n\ndef get_all_kv_files():\n    kv_files = []\n    for path,dirs,files in os.walk(CURDIR):\n        for f in files:\n            if os.path.splitext(f)[1]=='.kv':\n                kv_files.append(join(path,f))\n                \n    return kv_files\n\n\nsetup(\n    name='kivystudio',\n    version='0.1.0',\n    description='A Software emulation tool for kivy applications',\n    long_description=README + u\"\\n\\n\" + LICENSE,\n    author='Mahart team and Contributors',\n    author_email='mahartstudio1@gmail.com',\n    # url='https://plyer.readthedocs.org/en/latest/',\n    install_requires=[\n      'kivy',\n      'pygments',\n    ],\n    packages=find_packages(),\n    package_data={'': ['LICENSE', 'README.md'],\n                  'kivystudio': [\n                        'resources/*',\n                        'widgets/filemanager/images/*',\n                        'libs/resizablebehavior/*',\n                        'components/screens/images/*']+get_all_kv_files()\n                },\n\n    package_dir={'kivystudio': 'kivystudio'},\n    include_package_data=True,\n    license=open(join(CURDIR, 'LICENSE')).read(),\n    zip_safe=False,\n    classifiers=[\n        'Development Status :: 1 - Beta',\n        'Intended Audience :: Developers',\n        'Natural Language :: English',\n        'License :: MIT License',\n        'Programming Language :: Python',\n        'Programming Language :: Python :: 2',\n        'Programming Language :: Python :: 3',\n    ],\n    entry_points={\n        'console_scripts': [\n            'kivystudio=kivystudio.main:main',\n        ]\n    }\n)\n"
  },
  {
    "path": "tests/test_codeplace.py",
    "content": "\nfrom kivy.tests.common import GraphicUnitTest\nfrom kivy.base import EventLoop\n\nimport sys\nfrom os.path import dirname\nsys.path.append(dirname(dirname(__file__)))\n\n\nclass CodePlaceTest(GraphicUnitTest):\n\n    def test_tabState(self):\n        from kivystudio.components.codeplace import CodePlace, get_tab_from_group\n\n        code_place = CodePlace()\n        filename1 = 'test_codeplace.py'\n        filename2 = 'test_codeplace1.py'\n        code_place.add_code_tab(filename=filename1)\n        code_place.add_code_tab(filename=filename2)\n        self.render(code_place)\n\n        # ensure widow safely\n        EventLoop.ensure_window()\n\n        tab1 = get_tab_from_group(filename1)\n        tab2 = get_tab_from_group(filename2)\n\n        self.assertEqual(tab1.state, 'normal')\n        self.assertEqual(tab2.state, 'down')\n\n\nif __name__ == \"__main__\":\n    import unittest\n    unittest.main()\n"
  },
  {
    "path": "tests/test_emulator.py",
    "content": "\nfrom kivy.tests.common import GraphicUnitTest\nfrom kivy.base import EventLoop\n\nimport sys\nfrom os.path import dirname\nsys.path.append(dirname(dirname(__file__)))\n\nclass EmulatorTest(GraphicUnitTest):\n\n    def setUp(self):\n        from kivystudio.parser import emulate_file\n        from kivystudio.components.emulator_area import emulator_area\n        EventLoop.ensure_window()\n        self.emulate_file = emulate_file\n        self.emulator_area = emulator_area\n\n    def test_emulation(self):\n        from kivy.uix.button import Button\n\n        self.emulate_file('/root/Pictures/test.py')\n        root_widget = self.emulator_area().screen_display.screen.root_widget\n        self.assertEqual(isinstance(root_widget, Button), True)\n\n    def test_changeScreen(self):\n        from kivy.uix.button import Button\n\n        self.emulate_file('/root/Pictures/test.py')\n        root_widget = self.emulator_area().screen_display.screen.root_widget\n        self.assertEqual(isinstance(root_widget, Button), True)\n\n        # then change screen\n        screen_display = self.emulator_area().screen_display\n        screen_display.screen_name = 'IpadScreen'\n        self.assertEqual(isinstance(root_widget, Button), True)\n\n        # change screen again\n        screen_display.screen_name = 'IphoneScreen'\n        self.assertEqual(isinstance(root_widget, Button), True)\n\n    def test_scaling(self):\n        self.emulate_file('/root/Pictures/test.py')\n        root_widget = self.emulator_area().screen_display.screen.root_widget\n\n\n\nif __name__ == \"__main__\":\n    import unittest\n    unittest.main()\n"
  },
  {
    "path": "to-do.txt",
    "content": "\nTo-Do List\n\n* FilExplorer\n* CodeInput Search\n* Auto Suggestion in CodeInput\n* Bottom Menu\n* Custom terminal (Command Line)\n* Splitter\n* General Project Search (on side bar)\n\n* When an image file is selected Show up an image tab\n\n\nBugs\nTextinput\n*tripple quote highlighting bug\n*multiple indent doesn't work well\n*Menus show the same thing and crashes\n\n# Later\n* Git Intergration\n* Theming\n"
  }
]