class ClockWidget(Widget): time = StringProperty() def update_time(self, dt): self.time = datetime.now().strftime( "[color=#ffffff]%H:%M:%S\n%m/%d/%Y[/color]")
class ShapeCutter35ScreenClass(Screen): info_button = ObjectProperty() vacuum_toggle = ObjectProperty() screen_number = StringProperty("[b]35[/b]") title_label = StringProperty("[b]Check spindle power[/b]") user_instructions = StringProperty("Press the button. The spindle should come on for 2 seconds.\n\n" \ "If not, check that it\'s connected and switched on, then retry by pressing the button again.") def __init__(self, **kwargs): super(ShapeCutter35ScreenClass, self).__init__(**kwargs) self.shapecutter_sm = kwargs['shapecutter'] self.m=kwargs['machine'] def on_pre_enter(self): self.info_button.opacity = 0 # Action buttons def get_info(self): pass def go_back(self): self.shapecutter_sm.previous_screen() def next_screen(self): self.shapecutter_sm.next_screen() # Tab functions def prepare(self): self.shapecutter_sm.prepare_tab() def load(self): self.shapecutter_sm.load_tab() def define(self): self.shapecutter_sm.define_tab() def position(self): self.shapecutter_sm.position_tab() def check(self): self.shapecutter_sm.check_tab() def exit(self): self.shapecutter_sm.exit_shapecutter() # Screen specific def set_spindle(self): if self.spindle_toggle.state == 'normal': self.next_button.disabled = False self.back_button.disabled = False self.spindle_image.source = "./asmcnc/skavaUI/img/spindle_off.png" self.m.spindle_off() else: self.spindle_image.source = "./asmcnc/skavaUI/img/spindle_on.png" self.next_button.disabled = True self.back_button.disabled = True self.m.spindle_on() Clock.schedule_once(self.reset_spindle, 2) def reset_spindle(self, dt): #self.m.vac_on() self.spindle_toggle.state = 'normal' self.set_spindle()
class NavigationDrawerIconButton(OneLineIconListItem): """An item in the :class:`MDNavigationDrawer`.""" _active = BooleanProperty(False) _active_color = ListProperty() _icon = ObjectProperty() divider = None active_color = ListProperty() """Custom active color. This option only takes effect when :attr:`active_color_type` = 'custom'. :attr:`active_color` is a :class:`~kivy.properties.ListProperty` and defaults to None. """ active_color_type = OptionProperty('primary', options=['primary', 'accent', 'custom']) """Decides which color should be used for the active color. This option only takes effect when :attr:`use_active` = True. Options: primary: Active color will be the primary theme color. accent: Active color will be the theme's accent color. custom: Active color will be taken from the :attr:`active_color` attribute. :attr:`active_color_type` is a :class:`~kivy.properties.OptionProperty` and defaults to 'primary'. """ icon = StringProperty('checkbox-blank-circle') """Icon that appears to the left of the widget. :attr:`icon` is a :class:`~kivy.properties.StringProperty` and defaults to 'checkbox-blank-circle'. """ badge_text = StringProperty('') """ Text that appears on the right side of the item, usually for displaying a count of sorts. :attr:`badge_text` is a :class:`~kivy.properties.StringProperty` and defaults to ''. """ use_active = BooleanProperty(True) """If the button should change to the active color when selected. :attr:`use_active` is a :class:`~kivy.properties.BooleanProperty` and defaults to True. See also: :attr:`active_color` :attr:`active_color_type` """ # active_color = get_color_from_hex(colors['Red']['500']) # active_color_type = 'custom' def __init__(self, **kwargs): super().__init__(**kwargs) self._set_active_color() self.theme_cls.bind(primary_color=self._set_active_color_primary, accent_color=self._set_active_color_accent) Clock.schedule_once(lambda x: self.on_icon(self, self.icon)) def _set_active(self, active, nav_drawer): if self.use_active: self._active = active if nav_drawer.active_item != self: if nav_drawer.active_item is not None: nav_drawer.active_item._active = False nav_drawer.active_item = self def _set_active_color(self, *args): if self.active_color_type == 'primary': self._set_active_color_primary() elif self.active_color_type == 'accent': self._set_active_color_accent() # Note to future developers/myself: These must be separate functions def _set_active_color_primary(self, *args): if self.active_color_type == 'primary': self._active_color = self.theme_cls.primary_color def _set_active_color_accent(self, *args): if self.active_color_type == 'accent': self._active_color = self.theme_cls.accent_color def on_icon(self, instance, value): super().__init__() self.ids._icon.text = u'{}'.format(md_icons[value]) def on_active_color_type(self, *args): self._set_active_color(args)
class ElectrumWindow(App): electrum_config = ObjectProperty(None) language = StringProperty('en') # properties might be updated by the network num_blocks = NumericProperty(0) num_nodes = NumericProperty(0) server_host = StringProperty('') server_port = StringProperty('') num_chains = NumericProperty(0) blockchain_name = StringProperty('') fee_status = StringProperty('Fee') balance = StringProperty('') fiat_balance = StringProperty('') is_fiat = BooleanProperty(False) blockchain_forkpoint = NumericProperty(0) auto_connect = BooleanProperty(False) def on_auto_connect(self, instance, x): net_params = self.network.get_parameters() net_params = net_params._replace(auto_connect=self.auto_connect) self.network.run_from_another_thread(self.network.set_parameters(net_params)) def toggle_auto_connect(self, x): self.auto_connect = not self.auto_connect oneserver = BooleanProperty(False) def on_oneserver(self, instance, x): net_params = self.network.get_parameters() net_params = net_params._replace(oneserver=self.oneserver) self.network.run_from_another_thread(self.network.set_parameters(net_params)) def toggle_oneserver(self, x): self.oneserver = not self.oneserver proxy_str = StringProperty('') def update_proxy_str(self, proxy: dict): mode = proxy.get('mode') host = proxy.get('host') port = proxy.get('port') self.proxy_str = (host + ':' + port) if mode else _('None') def choose_server_dialog(self, popup): from .uix.dialogs.choice_dialog import ChoiceDialog protocol = 's' def cb2(host): from electrum import constants pp = servers.get(host, constants.net.DEFAULT_PORTS) port = pp.get(protocol, '') popup.ids.host.text = host popup.ids.port.text = port servers = self.network.get_servers() ChoiceDialog(_('Choose a server'), sorted(servers), popup.ids.host.text, cb2).open() def choose_blockchain_dialog(self, dt): from .uix.dialogs.choice_dialog import ChoiceDialog chains = self.network.get_blockchains() def cb(name): with blockchain.blockchains_lock: blockchain_items = list(blockchain.blockchains.items()) for chain_id, b in blockchain_items: if name == b.get_name(): self.network.run_from_another_thread(self.network.follow_chain_given_id(chain_id)) chain_objects = [blockchain.blockchains.get(chain_id) for chain_id in chains] chain_objects = filter(lambda b: b is not None, chain_objects) names = [b.get_name() for b in chain_objects] if len(names) > 1: cur_chain = self.network.blockchain().get_name() ChoiceDialog(_('Choose your chain'), names, cur_chain, cb).open() use_rbf = BooleanProperty(False) def on_use_rbf(self, instance, x): self.electrum_config.set_key('use_rbf', self.use_rbf, True) use_change = BooleanProperty(False) def on_use_change(self, instance, x): self.electrum_config.set_key('use_change', self.use_change, True) use_unconfirmed = BooleanProperty(False) def on_use_unconfirmed(self, instance, x): self.electrum_config.set_key('confirmed_only', not self.use_unconfirmed, True) def set_URI(self, uri): self.switch_to('send') self.send_screen.set_URI(uri) def on_new_intent(self, intent): if intent.getScheme() != 'bitcoin': return uri = intent.getDataString() self.set_URI(uri) def on_language(self, instance, language): Logger.info('language: {}'.format(language)) _.switch_lang(language) def update_history(self, *dt): if self.history_screen: self.history_screen.update() def on_quotes(self, d): Logger.info("on_quotes") self._trigger_update_status() self._trigger_update_history() def on_history(self, d): Logger.info("on_history") if self.wallet: self.wallet.clear_coin_price_cache() self._trigger_update_history() def on_fee_histogram(self, *args): self._trigger_update_history() def _get_bu(self): decimal_point = self.electrum_config.get('decimal_point', DECIMAL_POINT_DEFAULT) try: return decimal_point_to_base_unit_name(decimal_point) except UnknownBaseUnit: return decimal_point_to_base_unit_name(DECIMAL_POINT_DEFAULT) def _set_bu(self, value): assert value in base_units.keys() decimal_point = base_unit_name_to_decimal_point(value) self.electrum_config.set_key('decimal_point', decimal_point, True) self._trigger_update_status() self._trigger_update_history() wallet_name = StringProperty(_('No Wallet')) base_unit = AliasProperty(_get_bu, _set_bu) fiat_unit = StringProperty('') def on_fiat_unit(self, a, b): self._trigger_update_history() def decimal_point(self): return base_units[self.base_unit] def btc_to_fiat(self, amount_str): if not amount_str: return '' if not self.fx.is_enabled(): return '' rate = self.fx.exchange_rate() if rate.is_nan(): return '' fiat_amount = self.get_amount(amount_str + ' ' + self.base_unit) * rate / pow(10, 8) return "{:.2f}".format(fiat_amount).rstrip('0').rstrip('.') def fiat_to_btc(self, fiat_amount): if not fiat_amount: return '' rate = self.fx.exchange_rate() if rate.is_nan(): return '' satoshis = int(pow(10,8) * Decimal(fiat_amount) / Decimal(rate)) return format_satoshis_plain(satoshis, self.decimal_point()) def get_amount(self, amount_str): a, u = amount_str.split() assert u == self.base_unit try: x = Decimal(a) except: return None p = pow(10, self.decimal_point()) return int(p * x) _orientation = OptionProperty('landscape', options=('landscape', 'portrait')) def _get_orientation(self): return self._orientation orientation = AliasProperty(_get_orientation, None, bind=('_orientation',)) '''Tries to ascertain the kind of device the app is running on. Cane be one of `tablet` or `phone`. :data:`orientation` is a read only `AliasProperty` Defaults to 'landscape' ''' _ui_mode = OptionProperty('phone', options=('tablet', 'phone')) def _get_ui_mode(self): return self._ui_mode ui_mode = AliasProperty(_get_ui_mode, None, bind=('_ui_mode',)) '''Defines tries to ascertain the kind of device the app is running on. Cane be one of `tablet` or `phone`. :data:`ui_mode` is a read only `AliasProperty` Defaults to 'phone' ''' def __init__(self, **kwargs): # initialize variables self._clipboard = Clipboard self.info_bubble = None self.nfcscanner = None self.tabs = None self.is_exit = False self.wallet = None self.pause_time = 0 self.asyncio_loop = asyncio.get_event_loop() App.__init__(self)#, **kwargs) title = _('Electrum App') self.electrum_config = config = kwargs.get('config', None) self.language = config.get('language', 'en') self.network = network = kwargs.get('network', None) # type: Network if self.network: self.num_blocks = self.network.get_local_height() self.num_nodes = len(self.network.get_interfaces()) net_params = self.network.get_parameters() self.server_host = net_params.host self.server_port = net_params.port self.auto_connect = net_params.auto_connect self.oneserver = net_params.oneserver self.proxy_config = net_params.proxy if net_params.proxy else {} self.update_proxy_str(self.proxy_config) self.plugins = kwargs.get('plugins', []) self.gui_object = kwargs.get('gui_object', None) self.daemon = self.gui_object.daemon self.fx = self.daemon.fx self.use_rbf = config.get('use_rbf', True) self.use_change = config.get('use_change', True) self.use_unconfirmed = not config.get('confirmed_only', False) # create triggers so as to minimize updating a max of 2 times a sec self._trigger_update_wallet = Clock.create_trigger(self.update_wallet, .5) self._trigger_update_status = Clock.create_trigger(self.update_status, .5) self._trigger_update_history = Clock.create_trigger(self.update_history, .5) self._trigger_update_interfaces = Clock.create_trigger(self.update_interfaces, .5) self._periodic_update_status_during_sync = Clock.schedule_interval(self.update_wallet_synchronizing_progress, .5) # cached dialogs self._settings_dialog = None self._password_dialog = None self.fee_status = self.electrum_config.get_fee_status() def on_pr(self, pr): if not self.wallet: self.show_error(_('No wallet loaded.')) return if pr.verify(self.wallet.contacts): key = self.wallet.invoices.add(pr) if self.invoices_screen: self.invoices_screen.update() status = self.wallet.invoices.get_status(key) if status == PR_PAID: self.show_error("invoice already paid") self.send_screen.do_clear() else: if pr.has_expired(): self.show_error(_('Payment request has expired')) else: self.switch_to('send') self.send_screen.set_request(pr) else: self.show_error("invoice error:" + pr.error) self.send_screen.do_clear() def on_qr(self, data): from electrum.bitcoin import base_decode, is_address data = data.strip() if is_address(data): self.set_URI(data) return if data.startswith('bitcoin:'): self.set_URI(data) return # try to decode transaction from electrum.transaction import Transaction from electrum.util import bh2u try: text = bh2u(base_decode(data, None, base=43)) tx = Transaction(text) tx.deserialize() except: tx = None if tx: self.tx_dialog(tx) return # show error self.show_error("Unable to decode QR data") def update_tab(self, name): s = getattr(self, name + '_screen', None) if s: s.update() @profiler def update_tabs(self): for tab in ['invoices', 'send', 'history', 'receive', 'address']: self.update_tab(tab) def switch_to(self, name): s = getattr(self, name + '_screen', None) if s is None: s = self.tabs.ids[name + '_screen'] s.load_screen() panel = self.tabs.ids.panel tab = self.tabs.ids[name + '_tab'] panel.switch_to(tab) def show_request(self, addr): self.switch_to('receive') self.receive_screen.screen.address = addr def show_pr_details(self, req, status, is_invoice): from electrum.util import format_time requestor = req.get('requestor') exp = req.get('exp') memo = req.get('memo') amount = req.get('amount') fund = req.get('fund') popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/invoice.kv') popup.is_invoice = is_invoice popup.amount = amount popup.requestor = requestor if is_invoice else req.get('address') popup.exp = format_time(exp) if exp else '' popup.description = memo if memo else '' popup.signature = req.get('signature', '') popup.status = status popup.fund = fund if fund else 0 txid = req.get('txid') popup.tx_hash = txid or '' popup.on_open = lambda: popup.ids.output_list.update(req.get('outputs', [])) popup.export = self.export_private_keys popup.open() def show_addr_details(self, req, status): from electrum.util import format_time fund = req.get('fund') isaddr = 'y' popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/invoice.kv') popup.isaddr = isaddr popup.is_invoice = False popup.status = status popup.requestor = req.get('address') popup.fund = fund if fund else 0 popup.export = self.export_private_keys popup.open() def qr_dialog(self, title, data, show_text=False, text_for_clipboard=None): from .uix.dialogs.qr_dialog import QRDialog def on_qr_failure(): popup.dismiss() msg = _('Failed to display QR code.') if text_for_clipboard: msg += '\n' + _('Text copied to clipboard.') self._clipboard.copy(text_for_clipboard) Clock.schedule_once(lambda dt: self.show_info(msg)) popup = QRDialog(title, data, show_text, failure_cb=on_qr_failure, text_for_clipboard=text_for_clipboard) popup.open() def scan_qr(self, on_complete): if platform != 'android': return from jnius import autoclass, cast from android import activity PythonActivity = autoclass('org.kivy.android.PythonActivity') SimpleScannerActivity = autoclass("org.electrum.qr.SimpleScannerActivity") Intent = autoclass('android.content.Intent') intent = Intent(PythonActivity.mActivity, SimpleScannerActivity) def on_qr_result(requestCode, resultCode, intent): try: if resultCode == -1: # RESULT_OK: # this doesn't work due to some bug in jnius: # contents = intent.getStringExtra("text") String = autoclass("java.lang.String") contents = intent.getStringExtra(String("text")) on_complete(contents) except Exception as e: # exc would otherwise get lost send_exception_to_crash_reporter(e) finally: activity.unbind(on_activity_result=on_qr_result) activity.bind(on_activity_result=on_qr_result) PythonActivity.mActivity.startActivityForResult(intent, 0) def do_share(self, data, title): if platform != 'android': return from jnius import autoclass, cast JS = autoclass('java.lang.String') Intent = autoclass('android.content.Intent') sendIntent = Intent() sendIntent.setAction(Intent.ACTION_SEND) sendIntent.setType("text/plain") sendIntent.putExtra(Intent.EXTRA_TEXT, JS(data)) PythonActivity = autoclass('org.kivy.android.PythonActivity') currentActivity = cast('android.app.Activity', PythonActivity.mActivity) it = Intent.createChooser(sendIntent, cast('java.lang.CharSequence', JS(title))) currentActivity.startActivity(it) def build(self): return Builder.load_file('electrum/gui/kivy/main.kv') def _pause(self): if platform == 'android': # move activity to back from jnius import autoclass python_act = autoclass('org.kivy.android.PythonActivity') mActivity = python_act.mActivity mActivity.moveTaskToBack(True) def on_start(self): ''' This is the start point of the kivy ui ''' import time Logger.info('Time to on_start: {} <<<<<<<<'.format(time.clock())) win = Window win.bind(size=self.on_size, on_keyboard=self.on_keyboard) win.bind(on_key_down=self.on_key_down) #win.softinput_mode = 'below_target' self.on_size(win, win.size) self.init_ui() crash_reporter.ExceptionHook(self) # init plugins run_hook('init_kivy', self) # fiat currency self.fiat_unit = self.fx.ccy if self.fx.is_enabled() else '' # default tab self.switch_to('history') # bind intent for bitcoin: URI scheme if platform == 'android': from android import activity from jnius import autoclass PythonActivity = autoclass('org.kivy.android.PythonActivity') mactivity = PythonActivity.mActivity self.on_new_intent(mactivity.getIntent()) activity.bind(on_new_intent=self.on_new_intent) # connect callbacks if self.network: interests = ['wallet_updated', 'network_updated', 'blockchain_updated', 'status', 'new_transaction', 'verified'] self.network.register_callback(self.on_network_event, interests) self.network.register_callback(self.on_fee, ['fee']) self.network.register_callback(self.on_fee_histogram, ['fee_histogram']) self.network.register_callback(self.on_quotes, ['on_quotes']) self.network.register_callback(self.on_history, ['on_history']) # load wallet self.load_wallet_by_name(self.electrum_config.get_wallet_path()) # URI passed in config uri = self.electrum_config.get('url') if uri: self.set_URI(uri) def get_wallet_path(self): if self.wallet: return self.wallet.storage.path else: return '' def on_wizard_complete(self, wizard, storage): if storage: wallet = Wallet(storage) wallet.start_network(self.daemon.network) self.daemon.add_wallet(wallet) self.load_wallet(wallet) elif not self.wallet: # wizard did not return a wallet; and there is no wallet open atm # try to open last saved wallet (potentially start wizard again) self.load_wallet_by_name(self.electrum_config.get_wallet_path(), ask_if_wizard=True) def load_wallet_by_name(self, path, ask_if_wizard=False): if not path: return if self.wallet and self.wallet.storage.path == path: return wallet = self.daemon.load_wallet(path, None) if wallet: if wallet.has_password(): self.password_dialog(wallet, _('Enter PIN code'), lambda x: self.load_wallet(wallet), self.stop) else: self.load_wallet(wallet) else: def launch_wizard(): wizard = Factory.InstallWizard(self.electrum_config, self.plugins) wizard.path = path wizard.bind(on_wizard_complete=self.on_wizard_complete) storage = WalletStorage(path, manual_upgrades=True) if not storage.file_exists(): wizard.run('new') elif storage.is_encrypted(): raise Exception("Kivy GUI does not support encrypted wallet files.") elif storage.requires_upgrade(): wizard.upgrade_storage(storage) else: raise Exception("unexpected storage file situation") if not ask_if_wizard: launch_wizard() else: from .uix.dialogs.question import Question def handle_answer(b: bool): if b: launch_wizard() else: try: os.unlink(path) except FileNotFoundError: pass self.stop() d = Question(_('Do you want to launch the wizard again?'), handle_answer) d.open() def on_stop(self): Logger.info('on_stop') if self.wallet: self.electrum_config.save_last_wallet(self.wallet) self.stop_wallet() def stop_wallet(self): if self.wallet: self.daemon.stop_wallet(self.wallet.storage.path) self.wallet = None def on_key_down(self, instance, key, keycode, codepoint, modifiers): if 'ctrl' in modifiers: # q=24 w=25 if keycode in (24, 25): self.stop() elif keycode == 27: # r=27 # force update wallet self.update_wallet() elif keycode == 112: # pageup #TODO move to next tab pass elif keycode == 117: # pagedown #TODO move to prev tab pass #TODO: alt+tab_number to activate the particular tab def on_keyboard(self, instance, key, keycode, codepoint, modifiers): if key == 27 and self.is_exit is False: self.is_exit = True self.show_info(_('Press again to exit')) return True # override settings button if key in (319, 282): #f1/settings button on android #self.gui.main_gui.toggle_settings(self) return True def settings_dialog(self): from .uix.dialogs.settings import SettingsDialog if self._settings_dialog is None: self._settings_dialog = SettingsDialog(self) self._settings_dialog.update() self._settings_dialog.open() def popup_dialog(self, name): if name == 'settings': self.settings_dialog() elif name == 'wallets': from .uix.dialogs.wallets import WalletDialog d = WalletDialog() d.open() elif name == 'status': popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/'+name+'.kv') master_public_keys_layout = popup.ids.master_public_keys for xpub in self.wallet.get_master_public_keys()[1:]: master_public_keys_layout.add_widget(TopLabel(text=_('Master Public Key'))) ref = RefLabel() ref.name = _('Master Public Key') ref.data = xpub master_public_keys_layout.add_widget(ref) popup.open() else: popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/'+name+'.kv') popup.open() @profiler def init_ui(self): ''' Initialize The Ux part of electrum. This function performs the basic tasks of setting up the ui. ''' #from weakref import ref self.funds_error = False # setup UX self.screens = {} #setup lazy imports for mainscreen Factory.register('AnimatedPopup', module='electrum.gui.kivy.uix.dialogs') Factory.register('QRCodeWidget', module='electrum.gui.kivy.uix.qrcodewidget') # preload widgets. Remove this if you want to load the widgets on demand #Cache.append('electrum_widgets', 'AnimatedPopup', Factory.AnimatedPopup()) #Cache.append('electrum_widgets', 'QRCodeWidget', Factory.QRCodeWidget()) # load and focus the ui self.root.manager = self.root.ids['manager'] self.history_screen = None self.contacts_screen = None self.send_screen = None self.invoices_screen = None self.receive_screen = None self.requests_screen = None self.address_screen = None self.icon = "electrum/gui/icons/electrum.png" self.tabs = self.root.ids['tabs'] def update_interfaces(self, dt): net_params = self.network.get_parameters() self.num_nodes = len(self.network.get_interfaces()) self.num_chains = len(self.network.get_blockchains()) chain = self.network.blockchain() self.blockchain_forkpoint = chain.get_max_forkpoint() self.blockchain_name = chain.get_name() interface = self.network.interface if interface: self.server_host = interface.host else: self.server_host = str(net_params.host) + ' (connecting...)' self.proxy_config = net_params.proxy or {} self.update_proxy_str(self.proxy_config) def on_network_event(self, event, *args): Logger.info('network event: '+ event) if event == 'network_updated': self._trigger_update_interfaces() self._trigger_update_status() elif event == 'wallet_updated': self._trigger_update_wallet() self._trigger_update_status() elif event == 'blockchain_updated': # to update number of confirmations in history self._trigger_update_wallet() elif event == 'status': self._trigger_update_status() elif event == 'new_transaction': self._trigger_update_wallet() elif event == 'verified': self._trigger_update_wallet() @profiler def load_wallet(self, wallet): if self.wallet: self.stop_wallet() self.wallet = wallet self.wallet_name = wallet.basename() self.update_wallet() # Once GUI has been initialized check if we want to announce something # since the callback has been called before the GUI was initialized if self.receive_screen: self.receive_screen.clear() self.update_tabs() run_hook('load_wallet', wallet, self) try: wallet.try_detecting_internal_addresses_corruption() except InternalAddressCorruption as e: self.show_error(str(e)) send_exception_to_crash_reporter(e) def update_status(self, *dt): if not self.wallet: return if self.network is None or not self.network.is_connected(): status = _("Offline") elif self.network.is_connected(): self.num_blocks = self.network.get_local_height() server_height = self.network.get_server_height() server_lag = self.num_blocks - server_height if not self.wallet.up_to_date or server_height == 0: num_sent, num_answered = self.wallet.get_history_sync_state_details() status = ("{} [size=18dp]({}/{})[/size]" .format(_("Synchronizing..."), num_answered, num_sent)) elif server_lag > 1: status = _("Server is lagging ({} blocks)").format(server_lag) else: status = '' else: status = _("Disconnected") if status: self.balance = status self.fiat_balance = status else: c, u, x = self.wallet.get_balance() text = self.format_amount(c+x+u) self.balance = str(text.strip()) + ' [size=22dp]%s[/size]'% self.base_unit self.fiat_balance = self.fx.format_amount(c+u+x) + ' [size=22dp]%s[/size]'% self.fx.ccy def update_wallet_synchronizing_progress(self, *dt): if not self.wallet: return if not self.wallet.up_to_date: self._trigger_update_status() def get_max_amount(self): from electrum.transaction import TxOutput if run_hook('abort_send', self): return '' inputs = self.wallet.get_spendable_coins(None, self.electrum_config) if not inputs: return '' addr = str(self.send_screen.screen.address) or self.wallet.dummy_address() outputs = [TxOutput(TYPE_ADDRESS, addr, '!')] try: tx = self.wallet.make_unsigned_transaction(inputs, outputs, self.electrum_config) except NoDynamicFeeEstimates as e: Clock.schedule_once(lambda dt, bound_e=e: self.show_error(str(bound_e))) return '' except NotEnoughFunds: return '' except InternalAddressCorruption as e: self.show_error(str(e)) send_exception_to_crash_reporter(e) return '' amount = tx.output_value() __, x_fee_amount = run_hook('get_tx_extra_fee', self.wallet, tx) or (None, 0) amount_after_all_fees = amount - x_fee_amount return format_satoshis_plain(amount_after_all_fees, self.decimal_point()) def format_amount(self, x, is_diff=False, whitespaces=False): return format_satoshis(x, 0, self.decimal_point(), is_diff=is_diff, whitespaces=whitespaces) def format_amount_and_units(self, x): return format_satoshis_plain(x, self.decimal_point()) + ' ' + self.base_unit def format_fee_rate(self, fee_rate): # fee_rate is in sat/kB return format_fee_satoshis(fee_rate/1000) + ' sat/byte' #@profiler def update_wallet(self, *dt): self._trigger_update_status() if self.wallet and (self.wallet.up_to_date or not self.network or not self.network.is_connected()): self.update_tabs() def notify(self, message): try: global notification, os if not notification: from plyer import notification icon = (os.path.dirname(os.path.realpath(__file__)) + '/../../' + self.icon) notification.notify('Electrum', message, app_icon=icon, app_name='Electrum') except ImportError: Logger.Error('Notification: needs plyer; `sudo python3 -m pip install plyer`') def on_pause(self): self.pause_time = time.time() # pause nfc if self.nfcscanner: self.nfcscanner.nfc_disable() return True def on_resume(self): now = time.time() if self.wallet and self.wallet.has_password() and now - self.pause_time > 60: self.password_dialog(self.wallet, _('Enter PIN'), None, self.stop) if self.nfcscanner: self.nfcscanner.nfc_enable() def on_size(self, instance, value): width, height = value self._orientation = 'landscape' if width > height else 'portrait' self._ui_mode = 'tablet' if min(width, height) > inch(3.51) else 'phone' def on_ref_label(self, label, touch): if label.touched: label.touched = False self.qr_dialog(label.name, label.data, True) else: label.touched = True self._clipboard.copy(label.data) Clock.schedule_once(lambda dt: self.show_info(_('Text copied to clipboard.\nTap again to display it as QR code.'))) def show_error(self, error, width='200dp', pos=None, arrow_pos=None, exit=False, icon='atlas://electrum/gui/kivy/theming/light/error', duration=0, modal=False): ''' Show an error Message Bubble. ''' self.show_info_bubble( text=error, icon=icon, width=width, pos=pos or Window.center, arrow_pos=arrow_pos, exit=exit, duration=duration, modal=modal) def show_info(self, error, width='200dp', pos=None, arrow_pos=None, exit=False, duration=0, modal=False): ''' Show an Info Message Bubble. ''' self.show_error(error, icon='atlas://electrum/gui/kivy/theming/light/important', duration=duration, modal=modal, exit=exit, pos=pos, arrow_pos=arrow_pos) def show_info_bubble(self, text=_('Hello World'), pos=None, duration=0, arrow_pos='bottom_mid', width=None, icon='', modal=False, exit=False): '''Method to show an Information Bubble .. parameters:: text: Message to be displayed pos: position for the bubble duration: duration the bubble remains on screen. 0 = click to hide width: width of the Bubble arrow_pos: arrow position for the bubble ''' info_bubble = self.info_bubble if not info_bubble: info_bubble = self.info_bubble = Factory.InfoBubble() win = Window if info_bubble.parent: win.remove_widget(info_bubble if not info_bubble.modal else info_bubble._modal_view) if not arrow_pos: info_bubble.show_arrow = False else: info_bubble.show_arrow = True info_bubble.arrow_pos = arrow_pos img = info_bubble.ids.img if text == 'texture': # icon holds a texture not a source image # display the texture in full screen text = '' img.texture = icon info_bubble.fs = True info_bubble.show_arrow = False img.allow_stretch = True info_bubble.dim_background = True info_bubble.background_image = 'atlas://electrum/gui/kivy/theming/light/card' else: info_bubble.fs = False info_bubble.icon = icon #if img.texture and img._coreimage: # img.reload() img.allow_stretch = False info_bubble.dim_background = False info_bubble.background_image = 'atlas://data/images/defaulttheme/bubble' info_bubble.message = text if not pos: pos = (win.center[0], win.center[1] - (info_bubble.height/2)) info_bubble.show(pos, duration, width, modal=modal, exit=exit) def tx_dialog(self, tx): from .uix.dialogs.tx_dialog import TxDialog d = TxDialog(self, tx) d.open() def sign_tx(self, *args): threading.Thread(target=self._sign_tx, args=args).start() def _sign_tx(self, tx, password, on_success, on_failure): try: self.wallet.sign_transaction(tx, password) except InvalidPassword: Clock.schedule_once(lambda dt: on_failure(_("Invalid PIN"))) return on_success = run_hook('tc_sign_wrapper', self.wallet, tx, on_success, on_failure) or on_success Clock.schedule_once(lambda dt: on_success(tx)) def _broadcast_thread(self, tx, on_complete): status = False try: self.network.run_from_another_thread(self.network.broadcast_transaction(tx)) except TxBroadcastError as e: msg = e.get_message_for_gui() except BestEffortRequestFailed as e: msg = repr(e) else: status, msg = True, tx.txid() Clock.schedule_once(lambda dt: on_complete(status, msg)) def broadcast(self, tx, pr=None): def on_complete(ok, msg): if ok: self.show_info(_('Payment sent.')) if self.send_screen: self.send_screen.do_clear() if pr: self.wallet.invoices.set_paid(pr, tx.txid()) self.wallet.invoices.save() self.update_tab('invoices') else: msg = msg or '' self.show_error(msg) if self.network and self.network.is_connected(): self.show_info(_('Sending')) threading.Thread(target=self._broadcast_thread, args=(tx, on_complete)).start() else: self.show_info(_('Cannot broadcast transaction') + ':\n' + _('Not connected')) def description_dialog(self, screen): from .uix.dialogs.label_dialog import LabelDialog text = screen.message def callback(text): screen.message = text d = LabelDialog(_('Enter description'), text, callback) d.open() def amount_dialog(self, screen, show_max): from .uix.dialogs.amount_dialog import AmountDialog amount = screen.amount if amount: amount, u = str(amount).split() assert u == self.base_unit def cb(amount): screen.amount = amount popup = AmountDialog(show_max, amount, cb) popup.open() def invoices_dialog(self, screen): from .uix.dialogs.invoices import InvoicesDialog if len(self.wallet.invoices.sorted_list()) == 0: self.show_info(' '.join([ _('No saved invoices.'), _('Signed invoices are saved automatically when you scan them.'), _('You may also save unsigned requests or contact addresses using the save button.') ])) return popup = InvoicesDialog(self, screen, None) popup.update() popup.open() def requests_dialog(self, screen): from .uix.dialogs.requests import RequestsDialog if len(self.wallet.get_sorted_requests(self.electrum_config)) == 0: self.show_info(_('No saved requests.')) return popup = RequestsDialog(self, screen, None) popup.update() popup.open() def addresses_dialog(self, screen): from .uix.dialogs.addresses import AddressesDialog popup = AddressesDialog(self, screen, None) popup.update() popup.open() def fee_dialog(self, label, dt): from .uix.dialogs.fee_dialog import FeeDialog def cb(): self.fee_status = self.electrum_config.get_fee_status() fee_dialog = FeeDialog(self, self.electrum_config, cb) fee_dialog.open() def on_fee(self, event, *arg): self.fee_status = self.electrum_config.get_fee_status() def protected(self, msg, f, args): if self.wallet.has_password(): on_success = lambda pw: f(*(args + (pw,))) self.password_dialog(self.wallet, msg, on_success, lambda: None) else: f(*(args + (None,))) def delete_wallet(self): from .uix.dialogs.question import Question basename = os.path.basename(self.wallet.storage.path) d = Question(_('Delete wallet?') + '\n' + basename, self._delete_wallet) d.open() def _delete_wallet(self, b): if b: basename = self.wallet.basename() self.protected(_("Enter your PIN code to confirm deletion of {}").format(basename), self.__delete_wallet, ()) def __delete_wallet(self, pw): wallet_path = self.get_wallet_path() dirname = os.path.dirname(wallet_path) basename = os.path.basename(wallet_path) if self.wallet.has_password(): try: self.wallet.check_password(pw) except: self.show_error("Invalid PIN") return self.stop_wallet() os.unlink(wallet_path) self.show_error(_("Wallet removed: {}").format(basename)) new_path = self.electrum_config.get_wallet_path() self.load_wallet_by_name(new_path) def show_seed(self, label): self.protected(_("Enter your PIN code in order to decrypt your seed"), self._show_seed, (label,)) def _show_seed(self, label, password): if self.wallet.has_password() and password is None: return keystore = self.wallet.keystore try: seed = keystore.get_seed(password) passphrase = keystore.get_passphrase(password) except: self.show_error("Invalid PIN") return label.text = _('Seed') + ':\n' + seed if passphrase: label.text += '\n\n' + _('Passphrase') + ': ' + passphrase def password_dialog(self, wallet, msg, on_success, on_failure): from .uix.dialogs.password_dialog import PasswordDialog if self._password_dialog is None: self._password_dialog = PasswordDialog() self._password_dialog.init(self, wallet, msg, on_success, on_failure) self._password_dialog.open() def change_password(self, cb): from .uix.dialogs.password_dialog import PasswordDialog if self._password_dialog is None: self._password_dialog = PasswordDialog() message = _("Changing PIN code.") + '\n' + _("Enter your current PIN:") def on_success(old_password, new_password): self.wallet.update_password(old_password, new_password) self.show_info(_("Your PIN code was updated")) on_failure = lambda: self.show_error(_("PIN codes do not match")) self._password_dialog.init(self, self.wallet, message, on_success, on_failure, is_change=1) self._password_dialog.open() def export_private_keys(self, pk_label, addr): if self.wallet.is_watching_only(): self.show_info(_('This is a watching-only wallet. It does not contain private keys.')) return def show_private_key(addr, pk_label, password): if self.wallet.has_password() and password is None: return if not self.wallet.can_export(): return try: key = str(self.wallet.export_private_key(addr, password)[0]) pk_label.data = key except InvalidPassword: self.show_error("Invalid PIN") return self.protected(_("Enter your PIN code in order to decrypt your private key"), show_private_key, (addr, pk_label))
class MDUserAnimationCard(ThemableBehavior, ModalView): user_name = StringProperty() path_to_avatar = StringProperty() box_content = ObjectProperty() callback = ObjectProperty() _anim_bottom = True def __init__(self, **kwargs): super().__init__(**kwargs) self._primary_color = self.theme_cls.primary_color self._primary_color[3] = 0 self.user_animation_card = UserAnimationCard( user_name=self.user_name, path_to_avatar=self.path_to_avatar, _callback_back=self._callback_back, _primary_color=self._primary_color, ) self.user_animation_card.ids.user_name.pos = ( dp(15), Window.height - self.user_animation_card.ids.image.height, ) self.box_content = self.user_animation_card.ids.box_content self.add_widget(self.user_animation_card) self._obj_avatar = self.user_animation_card.ids.image self._obj_user_name = self.user_animation_card.ids.user_name self._obj_toolbar = self.user_animation_card.ids.toolbar self._obj_scroll = self.user_animation_card.ids.scroll self._set_current_pos_objects() def _callback_back(self): self.dismiss() if self.callback: self.callback() def on_open(self): self._primary_color = self.theme_cls.primary_color self._primary_color[3] = 0 self.user_animation_card._primary_color = self._primary_color def _set_current_pos_objects(self): self._avatar_y = self._obj_avatar.y self._toolbar_y = self._obj_toolbar.y self._user_name_y = self._obj_user_name.y self._scroll_y = self._obj_scroll.y def on_touch_move(self, touch): if touch.ud["swipe_begin"] < touch.y: if self._anim_bottom: self._anim_bottom = False self.animation_to_top() else: if not self._anim_bottom: self._anim_bottom = True self.animation_to_bottom() def on_touch_down(self, touch): touch.ud["swipe_begin"] = touch.y return super().on_touch_down(touch) def on_touch_up(self, touch): touch.ud["swipe_begin"] = 0 def animation_to_bottom(self): Animation(y=self._scroll_y, d=0.4, t="in_out_cubic").start(self._obj_scroll) Animation(y=self._user_name_y, d=0.5, x=dp(15), t="in_out_cubic").start(self._obj_user_name) Animation(font_size=sp(36), d=0.3, t="in_out_cubic").start(self._obj_user_name) Animation(_primary_color=[0, 0, 0, 0], d=0.3, t="in_out_cubic").start(self.user_animation_card) Animation(y=self._avatar_y, d=0.4, t="in_out_cubic").start(self._obj_avatar) def animation_to_top(self): user_name_y = (Window.height - self._obj_toolbar.height + (self.theme_cls.standard_increment // 2 - dp(12))) user_name_x = self.theme_cls.horizontal_margins + dp(12) * 5 Animation(y=-self._obj_toolbar.height, d=0.4, t="in_out_cubic").start(self._obj_scroll) Animation(y=user_name_y, d=0.3, x=user_name_x, t="in_out_cubic").start(self._obj_user_name) Animation(font_size=sp(20), d=0.3, t="in_out_cubic").start(self._obj_user_name) Animation(_primary_color=self.theme_cls.primary_color, d=0.3, t="in_out_cubic").start(self.user_animation_card) Animation(y=self._obj_avatar.y + 30, d=0.4, t="in_out_cubic").start(self._obj_avatar)
class MDCardSwipe(RelativeLayout): """ :Events: :attr:`on_swipe_complete` Called when a swipe of card is completed. """ open_progress = NumericProperty(0.0) """ Percent of visible part of side panel. The percent is specified as a floating point number in the range 0-1. 0.0 if panel is closed and 1.0 if panel is opened. :attr:`open_progress` is a :class:`~kivy.properties.NumericProperty` and defaults to `0.0`. """ opening_transition = StringProperty("out_cubic") """ The name of the animation transition type to use when animating to the :attr:`state` `'opened'`. :attr:`opening_transition` is a :class:`~kivy.properties.StringProperty` and defaults to `'out_cubic'`. """ closing_transition = StringProperty("out_sine") """ The name of the animation transition type to use when animating to the :attr:`state` 'closed'. :attr:`closing_transition` is a :class:`~kivy.properties.StringProperty` and defaults to `'out_sine'`. """ anchor = OptionProperty("left", options=("left", "right")) """ Anchoring screen edge for card. Available options are: `'left'`, `'right'`. :attr:`anchor` is a :class:`~kivy.properties.OptionProperty` and defaults to `left`. """ swipe_distance = NumericProperty(50) """ The distance of the swipe with which the movement of navigation drawer begins. :attr:`swipe_distance` is a :class:`~kivy.properties.NumericProperty` and defaults to `50`. """ opening_time = NumericProperty(0.2) """ The time taken for the card to slide to the :attr:`state` `'open'`. :attr:`opening_time` is a :class:`~kivy.properties.NumericProperty` and defaults to `0.2`. """ state = OptionProperty("closed", options=("closed", "opened")) """ Detailed state. Sets before :attr:`state`. Bind to :attr:`state` instead of :attr:`status`. Available options are: `'closed'`, `'opened'`. :attr:`status` is a :class:`~kivy.properties.OptionProperty` and defaults to `'closed'`. """ max_swipe_x = NumericProperty(0.3) """ If, after the events of :attr:`~on_touch_up` card position exceeds this value - will automatically execute the method :attr:`~open_card`, and if not - will automatically be :attr:`~close_card` method. :attr:`max_swipe_x` is a :class:`~kivy.properties.NumericProperty` and defaults to `0.3`. """ max_opened_x = NumericProperty("100dp") """ The value of the position the card shifts to when :attr:`~type_swipe` s set to `'hand'`. :attr:`max_opened_x` is a :class:`~kivy.properties.NumericProperty` and defaults to `100dp`. """ type_swipe = OptionProperty("hand", options=("auto", "hand")) """ Type of card opening when swipe. Shift the card to the edge or to a set position :attr:`~max_opened_x`. Available options are: `'auto'`, `'hand'`. :attr:`type_swipe` is a :class:`~kivy.properties.OptionProperty` and defaults to `auto`. """ _opens_process = False _to_closed = True def __init__(self, **kw): self.register_event_type("on_swipe_complete") super().__init__(**kw) def _on_swipe_complete(self, *args): self.dispatch("on_swipe_complete") def add_widget(self, widget, index=0, canvas=None): if isinstance(widget, (MDCardSwipeFrontBox, MDCardSwipeLayerBox)): return super().add_widget(widget) def on_swipe_complete(self, *args): """Called when a swipe of card is completed.""" def on_anchor(self, instance, value): if value == "right": self.open_progress = 1.0 else: self.open_progress = 0.0 def on_open_progress(self, instance, value): if self.anchor == "left": self.children[0].x = self.width * value else: self.children[0].x = self.width * value - self.width def on_touch_move(self, touch): if self.collide_point(touch.x, touch.y): expr = ( touch.x < self.swipe_distance if self.anchor == "left" else touch.x > self.width - self.swipe_distance ) if expr and not self._opens_process: self._opens_process = True self._to_closed = False if self._opens_process: self.open_progress = max( min(self.open_progress + touch.dx / self.width, 2.5), 0 ) return super().on_touch_move(touch) def on_touch_up(self, touch): if self.collide_point(touch.x, touch.y): if not self._to_closed: self._opens_process = False self.complete_swipe() return super().on_touch_up(touch) def on_touch_down(self, touch): if self.collide_point(touch.x, touch.y): if self.state == "opened": self._to_closed = True self.close_card() return super().on_touch_down(touch) def complete_swipe(self): expr = ( self.open_progress <= self.max_swipe_x if self.anchor == "left" else self.open_progress >= self.max_swipe_x ) if expr: self.close_card() else: self.open_card() def open_card(self): if self.type_swipe == "hand": swipe_x = ( self.max_opened_x if self.anchor == "left" else -self.max_opened_x ) else: swipe_x = self.width if self.anchor == "left" else 0 anim = Animation( x=swipe_x, t=self.opening_transition, d=self.opening_time ) anim.bind(on_complete=self._on_swipe_complete) anim.start(self.children[0]) self.state = "opened" def close_card(self): anim = Animation(x=0, t=self.closing_transition, d=self.opening_time) anim.bind(on_complete=self._reset_open_progress) anim.start(self.children[0]) self.state = "closed" def _reset_open_progress(self, *args): self.open_progress = 0.0 if self.anchor == "left" else 1.0 self._to_closed = False self.dispatch("on_swipe_complete")
class Carousel(StencilView): '''Carousel class. See module documentation for more information. ''' slides = ListProperty([]) '''List of slides inside the Carousel. The slides are the widgets added to the Carousel using the :attr:`add_widget` method. :attr:`slides` is a :class:`~kivy.properties.ListProperty` and is read-only. ''' def _get_slides_container(self): return [x.parent for x in self.slides] slides_container = AliasProperty(_get_slides_container, None, bind=('slides', )) direction = OptionProperty('right', options=('right', 'left', 'top', 'bottom')) '''Specifies the direction in which the slides are ordered. This corresponds to the direction from which the user swipes to go from one slide to the next. It can be `right`, `left`, `top`, or `bottom`. For example, with the default value of `right`, the second slide is to the right of the first and the user would swipe from the right towards the left to get to the second slide. :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and defaults to 'right'. ''' min_move = NumericProperty(0.2) '''Defines the minimum distance to be covered before the touch is considered a swipe gesture and the Carousel content changed. This is a expressed as a fraction of the Carousel's width. If the movement doesn't reach this minimum value, the movement is cancelled and the content is restored to its original position. :attr:`min_move` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.2. ''' anim_move_duration = NumericProperty(0.5) '''Defines the duration of the Carousel animation between pages. :attr:`anim_move_duration` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.5. ''' anim_cancel_duration = NumericProperty(0.3) '''Defines the duration of the animation when a swipe movement is not accepted. This is generally when the user does not make a large enough swipe. See :attr:`min_move`. :attr:`anim_cancel_duration` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.3. ''' loop = BooleanProperty(False) '''Allow the Carousel to loop infinitely. If True, when the user tries to swipe beyond last page, it will return to the first. If False, it will remain on the last page. :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def _get_index(self): if self.slides: return self._index % len(self.slides) return None def _set_index(self, value): if self.slides: self._index = value % len(self.slides) else: self._index = None index = AliasProperty(_get_index, _set_index, bind=('_index', 'slides')) '''Get/Set the current slide based on the index. :attr:`index` is an :class:`~kivy.properties.AliasProperty` and defaults to 0 (the first item). ''' def _prev_slide(self): slides = self.slides len_slides = len(slides) index = self.index if len_slides < 2: # None, or 1 slide return None if len_slides == 2: if index == 0: return None if index == 1: return slides[0] if self.loop and index == 0: return slides[-1] if index > 0: return slides[index - 1] previous_slide = AliasProperty(_prev_slide, None, bind=('slides', 'index')) '''The previous slide in the Carousel. It is None if the current slide is the first slide in the Carousel. This ordering reflects the order in which the slides are added: their presentation varies according to the :attr:`direction` property. :attr:`previous_slide` is an :class:`~kivy.properties.AliasProperty`. .. versionchanged:: 1.5.0 This property no longer exposes the slides container. It returns the widget you have added. ''' def _curr_slide(self): if len(self.slides): return self.slides[self.index] current_slide = AliasProperty(_curr_slide, None, bind=('slides', 'index')) '''The currently shown slide. :attr:`current_slide` is an :class:`~kivy.properties.AliasProperty`. .. versionchanged:: 1.5.0 The property no longer exposes the slides container. It returns the widget you have added. ''' def _next_slide(self): if len(self.slides) < 2: # None, or 1 slide return None if len(self.slides) == 2: if self.index == 0: return self.slides[1] if self.index == 1: return None if self.loop and self.index == len(self.slides) - 1: return self.slides[0] if self.index < len(self.slides) - 1: return self.slides[self.index + 1] next_slide = AliasProperty(_next_slide, None, bind=('slides', 'index')) '''The next slide in the Carousel. It is None if the current slide is the last slide in the Carousel. This ordering reflects the order in which the slides are added: their presentation varies according to the :attr:`direction` property. :attr:`next_slide` is an :class:`~kivy.properties.AliasProperty`. .. versionchanged:: 1.5.0 The property no longer exposes the slides container. It returns the widget you have added. ''' scroll_timeout = NumericProperty(200) '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds. If the user has not moved :attr:`scroll_distance` within the timeout, no scrolling will occur and the touch event will go to the children. :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and defaults to 200 (milliseconds) .. versionadded:: 1.5.0 ''' scroll_distance = NumericProperty('20dp') '''Distance to move before scrolling the :class:`Carousel` in pixels. As soon as the distance has been traveled, the :class:`Carousel` will start to scroll, and no touch event will go to children. It is advisable that you base this value on the dpi of your target device's screen. :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and defaults to 20dp. .. versionadded:: 1.5.0 ''' anim_type = StringProperty('out_quad') '''Type of animation to use while animating to the next/previous slide. This should be the name of an :class:`~kivy.animation.AnimationTransition` function. :attr:`anim_type` is a :class:`~kivy.properties.StringProperty` and defaults to 'out_quad'. .. versionadded:: 1.8.0 ''' ignore_perpendicular_swipes = BooleanProperty(False) '''Ignore swipes on axis perpendicular to direction. :attr:`ignore_perpendicular_swipes` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. .. versionadded:: 1.10.0 ''' # private properties, for internal use only ### _index = NumericProperty(0, allownone=True) _prev = ObjectProperty(None, allownone=True) _current = ObjectProperty(None, allownone=True) _next = ObjectProperty(None, allownone=True) _offset = NumericProperty(0) _touch = ObjectProperty(None, allownone=True) _change_touch_mode_ev = None def __init__(self, **kwargs): self._trigger_position_visible_slides = Clock.create_trigger( self._position_visible_slides, -1) super(Carousel, self).__init__(**kwargs) self._skip_slide = None self.touch_mode_change = False def load_slide(self, slide): '''Animate to the slide that is passed as the argument. .. versionchanged:: 1.8.0 ''' slides = self.slides start, stop = slides.index(self.current_slide), slides.index(slide) if start == stop: return self._skip_slide = stop if stop > start: self._insert_visible_slides(_next_slide=slide) self.load_next() else: self._insert_visible_slides(_prev_slide=slide) self.load_previous() def load_previous(self): '''Animate to the previous slide. .. versionadded:: 1.7.0 ''' self.load_next(mode='prev') def load_next(self, mode='next'): '''Animate to the next slide. .. versionadded:: 1.7.0 ''' if self.index is not None: w, h = self.size _direction = { 'top': -h / 2, 'bottom': h / 2, 'left': w / 2, 'right': -w / 2 } _offset = _direction[self.direction] if mode == 'prev': _offset = -_offset self._start_animation(min_move=0, offset=_offset) def get_slide_container(self, slide): return slide.parent def _insert_visible_slides(self, _next_slide=None, _prev_slide=None): get_slide_container = self.get_slide_container previous_slide = _prev_slide if _prev_slide else self.previous_slide if previous_slide: self._prev = get_slide_container(previous_slide) else: self._prev = None current_slide = self.current_slide if current_slide: self._current = get_slide_container(current_slide) else: self._current = None next_slide = _next_slide if _next_slide else self.next_slide if next_slide: self._next = get_slide_container(next_slide) else: self._next = None super_remove = super(Carousel, self).remove_widget for container in self.slides_container: super_remove(container) if self._prev and self._prev.parent is not self: super(Carousel, self).add_widget(self._prev) if self._next and self._next.parent is not self: super(Carousel, self).add_widget(self._next) if self._current: super(Carousel, self).add_widget(self._current) def _position_visible_slides(self, *args): slides, index = self.slides, self.index no_of_slides = len(slides) - 1 if not slides: return x, y, width, height = self.x, self.y, self.width, self.height _offset, direction = self._offset, self.direction _prev, _next, _current = self._prev, self._next, self._current get_slide_container = self.get_slide_container last_slide = get_slide_container(slides[-1]) first_slide = get_slide_container(slides[0]) skip_next = False _loop = self.loop if direction[0] in ['r', 'l']: xoff = x + _offset x_prev = {'l': xoff + width, 'r': xoff - width} x_next = {'l': xoff - width, 'r': xoff + width} if _prev: _prev.pos = (x_prev[direction[0]], y) elif _loop and _next and index == 0: # if first slide is moving to right with direction set to right # or toward left with direction set to left if ((_offset > 0 and direction[0] == 'r') or (_offset < 0 and direction[0] == 'l')): # put last_slide before first slide last_slide.pos = (x_prev[direction[0]], y) skip_next = True if _current: _current.pos = (xoff, y) if skip_next: return if _next: _next.pos = (x_next[direction[0]], y) elif _loop and _prev and index == no_of_slides: if ((_offset < 0 and direction[0] == 'r') or (_offset > 0 and direction[0] == 'l')): first_slide.pos = (x_next[direction[0]], y) if direction[0] in ['t', 'b']: yoff = y + _offset y_prev = {'t': yoff - height, 'b': yoff + height} y_next = {'t': yoff + height, 'b': yoff - height} if _prev: _prev.pos = (x, y_prev[direction[0]]) elif _loop and _next and index == 0: if ((_offset > 0 and direction[0] == 't') or (_offset < 0 and direction[0] == 'b')): last_slide.pos = (x, y_prev[direction[0]]) skip_next = True if _current: _current.pos = (x, yoff) if skip_next: return if _next: _next.pos = (x, y_next[direction[0]]) elif _loop and _prev and index == no_of_slides: if ((_offset < 0 and direction[0] == 't') or (_offset > 0 and direction[0] == 'b')): first_slide.pos = (x, y_next[direction[0]]) def on_size(self, *args): size = self.size for slide in self.slides_container: slide.size = size self._trigger_position_visible_slides() def on_pos(self, *args): self._trigger_position_visible_slides() def on_index(self, *args): self._insert_visible_slides() self._trigger_position_visible_slides() self._offset = 0 def on_slides(self, *args): if self.slides: self.index = self.index % len(self.slides) self._insert_visible_slides() self._trigger_position_visible_slides() def on__offset(self, *args): self._trigger_position_visible_slides() # if reached full offset, switch index to next or prev direction = self.direction _offset = self._offset width = self.width height = self.height index = self.index if self._skip_slide is not None or index is None: return if direction[0] == 'r': if _offset <= -width: index += 1 if _offset >= width: index -= 1 if direction[0] == 'l': if _offset <= -width: index -= 1 if _offset >= width: index += 1 if direction[0] == 't': if _offset <= -height: index += 1 if _offset >= height: index -= 1 if direction[0] == 'b': if _offset <= -height: index -= 1 if _offset >= height: index += 1 self.index = index def _start_animation(self, *args, **kwargs): # compute target offset for ease back, next or prev new_offset = 0 direction = kwargs.get('direction', self.direction) is_horizontal = direction[0] in ['r', 'l'] extent = self.width if is_horizontal else self.height min_move = kwargs.get('min_move', self.min_move) _offset = kwargs.get('offset', self._offset) if _offset < min_move * -extent: new_offset = -extent elif _offset > min_move * extent: new_offset = extent # if new_offset is 0, it wasnt enough to go next/prev dur = self.anim_move_duration if new_offset == 0: dur = self.anim_cancel_duration # detect edge cases if not looping len_slides = len(self.slides) index = self.index if not self.loop or len_slides == 1: is_first = (index == 0) is_last = (index == len_slides - 1) if direction[0] in ['r', 't']: towards_prev = (new_offset > 0) towards_next = (new_offset < 0) else: towards_prev = (new_offset < 0) towards_next = (new_offset > 0) if (is_first and towards_prev) or (is_last and towards_next): new_offset = 0 anim = Animation(_offset=new_offset, d=dur, t=self.anim_type) anim.cancel_all(self) def _cmp(*l): if self._skip_slide is not None: self.index = self._skip_slide self._skip_slide = None anim.bind(on_complete=_cmp) anim.start(self) def _get_uid(self, prefix='sv'): return '{0}.{1}'.format(prefix, self.uid) def on_touch_down(self, touch): if not self.collide_point(*touch.pos): touch.ud[self._get_uid('cavoid')] = True return if self.disabled: return True if self._touch: return super(Carousel, self).on_touch_down(touch) Animation.cancel_all(self) self._touch = touch uid = self._get_uid() touch.grab(self) touch.ud[uid] = {'mode': 'unknown', 'time': touch.time_start} self._change_touch_mode_ev = Clock.schedule_once( self._change_touch_mode, self.scroll_timeout / 1000.) self.touch_mode_change = False return True def on_touch_move(self, touch): if not self.touch_mode_change: if self.ignore_perpendicular_swipes and \ self.direction in ('top', 'bottom'): if abs(touch.oy - touch.y) < self.scroll_distance: if abs(touch.ox - touch.x) > self.scroll_distance: self._change_touch_mode() self.touchModeChange = True elif self.ignore_perpendicular_swipes and \ self.direction in ('right', 'left'): if abs(touch.ox - touch.x) < self.scroll_distance: if abs(touch.oy - touch.y) > self.scroll_distance: self._change_touch_mode() self.touchModeChange = True if self._get_uid('cavoid') in touch.ud: return if self._touch is not touch: super(Carousel, self).on_touch_move(touch) return self._get_uid() in touch.ud if touch.grab_current is not self: return True ud = touch.ud[self._get_uid()] direction = self.direction if ud['mode'] == 'unknown': if direction[0] in ('r', 'l'): distance = abs(touch.ox - touch.x) else: distance = abs(touch.oy - touch.y) if distance > self.scroll_distance: ev = self._change_touch_mode_ev if ev is not None: ev.cancel() ud['mode'] = 'scroll' else: if direction[0] in ('r', 'l'): self._offset += touch.dx if direction[0] in ('t', 'b'): self._offset += touch.dy return True def on_touch_up(self, touch): if self._get_uid('cavoid') in touch.ud: return if self in [x() for x in touch.grab_list]: touch.ungrab(self) self._touch = None ud = touch.ud[self._get_uid()] if ud['mode'] == 'unknown': ev = self._change_touch_mode_ev if ev is not None: ev.cancel() super(Carousel, self).on_touch_down(touch) Clock.schedule_once(partial(self._do_touch_up, touch), .1) else: self._start_animation() else: if self._touch is not touch and self.uid not in touch.ud: super(Carousel, self).on_touch_up(touch) return self._get_uid() in touch.ud def _do_touch_up(self, touch, *largs): super(Carousel, self).on_touch_up(touch) # don't forget about grab event! for x in touch.grab_list[:]: touch.grab_list.remove(x) x = x() if not x: continue touch.grab_current = x super(Carousel, self).on_touch_up(touch) touch.grab_current = None def _change_touch_mode(self, *largs): if not self._touch: return self._start_animation() uid = self._get_uid() touch = self._touch ud = touch.ud[uid] if ud['mode'] == 'unknown': touch.ungrab(self) self._touch = None super(Carousel, self).on_touch_down(touch) return def add_widget(self, widget, index=0, canvas=None): slide = RelativeLayout(size=self.size, x=self.x - self.width, y=self.y) slide.add_widget(widget) super(Carousel, self).add_widget(slide, index, canvas) if index != 0: self.slides.insert(index - len(self.slides), widget) else: self.slides.append(widget) def remove_widget(self, widget, *args, **kwargs): # XXX be careful, the widget.parent refer to the RelativeLayout # added in add_widget(). But it will break if RelativeLayout # implementation change. # if we passed the real widget if widget in self.slides: slide = widget.parent self.slides.remove(widget) return slide.remove_widget(widget, *args, **kwargs) return super(Carousel, self).remove_widget(widget, *args, **kwargs) def clear_widgets(self): for slide in self.slides[:]: self.remove_widget(slide) super(Carousel, self).clear_widgets()
class LinkTree(TreeView): """ link to the favorites section of link bar """ _favs = ObjectProperty(None) _computer_node = None favorites_string = StringProperty('') libraries_string = StringProperty('') computer_string = StringProperty('') def fill_tree(self, fav_list): if platform == 'win': user_path = expanduser(u'~') if not isdir(user_path + sep + 'Desktop'): user_path = dirname(user_path) + sep else: user_path += sep else: user_path = expanduser(u'~') + sep self._favs = self.add_node( TreeLabel(text=self.favorites_string, is_open=True, no_selection=True)) self.reload_favs(fav_list) libs = self.add_node( TreeLabel(text=self.libraries_string, is_open=True, no_selection=True)) places = ('Documents', 'Music', 'Pictures', 'Videos') for place in places: if isdir(user_path + place): self.add_node(TreeLabel(text=place, path=user_path + place), libs) self._computer_node = self.add_node( TreeLabel(text=self.computer_string, is_open=True, no_selection=True)) self._computer_node.bind(on_touch_down=self._drives_touch) self.reload_drives() def _drives_touch(self, obj, touch): if obj.collide_point(*touch.pos): self.reload_drives() def reload_drives(self): nodes = [(node, node.text + node.path) for node in\ self._computer_node.nodes if isinstance(node, TreeLabel)] sigs = [s[1] for s in nodes] nodes_new = [] sig_new = [] for path, name in get_drives(): if platform == 'win': text = u'{}({})'.format((name + ' ') if name else '', path) else: text = name nodes_new.append((text, path)) sig_new.append(text + path + sep) for node, sig in nodes: if sig not in sig_new: self.remove_node(node) for text, path in nodes_new: if text + path + sep not in sigs: self.add_node(TreeLabel(text=text, path=path + sep), self._computer_node) def reload_favs(self, fav_list): if platform == 'win': user_path = expanduser(u'~') if not isdir(user_path + sep + 'Desktop'): user_path = dirname(user_path) + sep else: user_path += sep else: user_path = expanduser('~') + sep favs = self._favs remove = [] for node in self.iterate_all_nodes(favs): if node != favs: remove.append(node) for node in remove: self.remove_node(node) places = ('Desktop', 'Downloads') for place in places: if isdir(user_path + place): self.add_node(TreeLabel(text=place, path=user_path + place), favs) for path, name in fav_list: if isdir(path): self.add_node(TreeLabel(text=name, path=path), favs) def trigger_populate(self, node): if not node.path or node.nodes: return parent = node.path next = walk(parent).next() if next: for path in next[1]: self.add_node(TreeLabel(text=path, path=parent + sep + path), node)
class FileBrowser(BoxLayout): """FileBrowser class, see module documentation for more information. """ __events__ = ('on_canceled', 'on_success', 'on_submit') select_state = OptionProperty('normal', options=('normal', 'down')) '''State of the 'select' button, must be one of 'normal' or 'down'. The state is 'down' only when the button is currently touched/clicked, otherwise 'normal'. This button functions as the typical Ok/Select/Save button. :data:`select_state` is an :class:`~kivy.properties.OptionProperty`. ''' cancel_state = OptionProperty('normal', options=('normal', 'down')) '''State of the 'cancel' button, must be one of 'normal' or 'down'. The state is 'down' only when the button is currently touched/clicked, otherwise 'normal'. This button functions as the typical cancel button. :data:`cancel_state` is an :class:`~kivy.properties.OptionProperty`. ''' select_string = StringProperty('Ok') '''Label of the 'select' button. :data:`select_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Ok'. ''' cancel_string = StringProperty('Cancel') '''Label of the 'cancel' button. :data:`cancel_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Cancel'. ''' listview_string = StringProperty('List View') '''Label of the 'list view' button. :data:`listview_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'List View'. ''' iconview_string = StringProperty('Icon View') '''Label of the 'icon view' button. :data:`iconview_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Icon View'. ''' favorites_string = StringProperty('Favorites') '''Label of the 'Favorites' Section :data:`favorites_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Favorites'. ''' libraries_string = StringProperty('Libraries') '''Label of the 'Libraries' Section :data:`libraries_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Libraries'. ''' computer_string = StringProperty('Computer') '''Label of the 'Computer' Section :data:`computer_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Computer'. ''' location_string = StringProperty('Locations') '''Label of the 'Locations' Section :data:`Locations_string` is an :class:`~kivy.properties.StringProperty`, defaults to 'Locations'. ''' filename = StringProperty('') '''The current text in the filename field. Read only. When multiselect is True, the list of selected filenames is shortened. If shortened, filename will contain an ellipsis. :data:`filename` is an :class:`~kivy.properties.StringProperty`, defaults to ''. .. versionchanged:: 1.1 ''' selection = ListProperty([]) '''Read-only :class:`~kivy.properties.ListProperty`. Contains the list of files that are currently selected in the current tab. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.selection`. .. versionchanged:: 1.1 ''' path = StringProperty(u'/') ''' :class:`~kivy.properties.StringProperty`, defaults to the current working directory as a unicode string. It specifies the path on the filesystem that browser should refer to. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.path`. .. versionadded:: 1.1 ''' filters = ListProperty([]) ''':class:`~kivy.properties.ListProperty`, defaults to [] Specifies the filters to be applied to the files in the directory. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.filters`. Filering keywords that the user types into the filter field as a comma separated list will be reflected here. .. versionadded:: 1.1 ''' filter_dirs = BooleanProperty(False) ''' :class:`~kivy.properties.BooleanProperty`, defaults to False. Indicates whether filters should also apply to directories. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.filter_dirs`. .. versionadded:: 1.1 ''' show_hidden = BooleanProperty(False) ''' :class:`~kivy.properties.BooleanProperty`, defaults to False. Determines whether hidden files and folders should be shown. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.show_hidden`. .. versionadded:: 1.1 ''' show_fileinput = BooleanProperty(True) ''' :class:`~kivy.properties.BooleanProperty`, defaults to True. Determines whether the file name input field should be shown. .. versionadded:: 1.2 ''' show_filterinput = BooleanProperty(True) ''' :class:`~kivy.properties.BooleanProperty`, defaults to True. Determines whether the filter input filed should be shown. .. versionadded:: 1.2 ''' multiselect = BooleanProperty(False) ''' :class:`~kivy.properties.BooleanProperty`, defaults to False. Determines whether the user is able to select multiple files or not. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.multiselect`. .. versionadded:: 1.1 ''' dirselect = BooleanProperty(False) ''' :class:`~kivy.properties.BooleanProperty`, defaults to False. Determines whether directories are valid selections or not. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.dirselect`. .. versionadded:: 1.1 ''' rootpath = StringProperty(None, allownone=True) ''' Root path to use instead of the system root path. If set, it will not show a ".." directory to go up to the root path. For example, if you set rootpath to /users/foo, the user will be unable to go to /users or to any other directory not starting with /users/foo. :class:`~kivy.properties.StringProperty`, defaults to None. See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.rootpath`. .. versionadded:: 1.1 ''' favorites = ListProperty([]) '''A list of the paths added to the favorites link bar. Each element is a tuple where the first element is a string containing the full path to the location, while the second element is a string with the name of path to be displayed. :data:`favorites` is an :class:`~kivy.properties.ListProperty`, defaults to '[]'. ''' transition = ObjectProperty(None) ''' :class:`~kivy.propertiesObjectProperty`, defaults to False. sets the transition type between icon view and list view If not set, the screenmananager default transition is used (slide) .. versionadded:: 1.2 ''' def on_success(self): pass def on_canceled(self): pass def on_submit(self): pass def __init__(self, **kwargs): super(FileBrowser, self).__init__(**kwargs) Clock.schedule_once(self._post_init) def _post_init(self, *largs): self.ids.icon_view.bind(selection=partial(self._attr_callback, 'selection'), path=partial(self._attr_callback, 'path'), filters=partial(self._attr_callback, 'filters'), filter_dirs=partial(self._attr_callback, 'filter_dirs'), show_hidden=partial(self._attr_callback, 'show_hidden'), multiselect=partial(self._attr_callback, 'multiselect'), dirselect=partial(self._attr_callback, 'dirselect'), rootpath=partial(self._attr_callback, 'rootpath')) self.ids.list_view.bind(selection=partial(self._attr_callback, 'selection'), path=partial(self._attr_callback, 'path'), filters=partial(self._attr_callback, 'filters'), filter_dirs=partial(self._attr_callback, 'filter_dirs'), show_hidden=partial(self._attr_callback, 'show_hidden'), multiselect=partial(self._attr_callback, 'multiselect'), dirselect=partial(self._attr_callback, 'dirselect'), rootpath=partial(self._attr_callback, 'rootpath')) if not self.show_fileinput: self.ids.box_text.remove_widget(self.ids.file_text) if not self.show_filterinput: self.ids.box_text.remove_widget(self.ids.filt_text) if (not self.show_fileinput) and (not self.show_filterinput): self.remove_widget(self.ids.spacer1) self.remove_widget(self.ids.box_text) self.ids.link_tree.libraries_string = self.libraries_string self.ids.link_tree.favorites_string = self.favorites_string self.ids.link_tree.computer_string = self.computer_string self.ids.link_tree.fill_tree(self.favorites) self.ids.link_tree.root_options = { 'text': self.location_string, 'no_selection': True } if self.transition: self.ids.sm.transition = self.transition def _shorten_filenames(self, filenames): if not len(filenames): return '' elif len(filenames) == 1: return filenames[0] elif len(filenames) == 2: return filenames[0] + ', ' + filenames[1] else: return filenames[0] + ', _..._, ' + filenames[-1] def _attr_callback(self, attr, obj, value): setattr(self, attr, getattr(obj, attr))
class Data(EventDispatcher): ''' Data is a set of variables which are essentially global variables which hold information about the gcode file opened, the machine which is connected, and the user's settings. These variables are NOT thread-safe. The queue system should always be used for passing information between threads. ''' ''' Data available to all widgets ''' #Gcodes contains all of the lines of gcode in the opened file gcode = ObjectProperty([]) version = '1.23' #all of the available COM ports comPorts = [] #This defines which COM port is used comport = StringProperty("") #The index of the next unread line of Gcode gcodeIndex = NumericProperty(0) #Index of changes in z zMoves = ObjectProperty([]) #Holds the current value of the feed rate feedRate = 20 #holds the address of the g-code file so that the gcode can be refreshed gcodeFile = StringProperty("") #the current position of the cutting head currentpos = [0.0, 0.0, 0.0] target = [0.0, 0.0, 0.0] units = OptionProperty("MM", options=["MM", "INCHES"]) tolerance = NumericProperty(0.5) gcodeShift = ObjectProperty( [0.0, 0.0]) #the amount that the gcode has been shifted logger = Logger( ) #the module which records the machines behavior to review later # Background image stuff, persist but not saved backgroundFile = None backgroundTexture = None backgroundManualReg = [] backgroundRedraw = BooleanProperty(False) ''' Flags ''' #sets a flag if the gcode is being uploaded currently uploadFlag = BooleanProperty(0) #this is used to determine the first time the position is received from the machine firstTimePosFlag = 0 #report if the serial connection is open connectionStatus = BooleanProperty(0) #is the calibration process currently underway 0 -> false calibrationInProcess = False ''' Pointers to Objects ''' config = None #pointer to the program configuration object...used for writing to settings serialPort = None #this is a pointer to the program serial port object ''' Colors ''' fontColor = StringProperty('[color=7a7a7a]') drawingColor = ObjectProperty([.47, .47, .47]) iconPath = StringProperty('./Images/Icons/normal/') posIndicatorColor = ObjectProperty([0, 0, 0]) targetIndicatorColor = ObjectProperty([1, 0, 0]) ''' Misc UI bits that need to be saved between invocations (but not saved) ''' zPush = None zPushUnits = 'MM' zReadoutPos = 0.00 zPopupUnits = None zStepSizeVal = 0.1 ''' Queues ''' message_queue = LoggingQueue(logger) gcode_queue = Queue.Queue() quick_queue = Queue.Queue() def __init__(self): ''' Initializations. ''' self.logger.data = self
class TreeLabel(TreeViewLabel): """Full path to the location this node points to. :class:`~kivy.properties.StringProperty`, defaults to '' """ path = StringProperty('')
class MDTabs(ThemableBehavior, SpecificBackgroundColorBehavior, AnchorLayout): """ You can use this class to create your own tabbed panel.. :Events: `on_tab_switch` Called when switching tabs. """ default_tab = NumericProperty(0) """ Index of the default tab. :attr:`default_tab` is an :class:`~kivy.properties.NumericProperty` and defaults to `0`. """ tab_bar_height = NumericProperty("48dp") """ Height of the tab bar. :attr:`tab_bar_height` is an :class:`~kivy.properties.NumericProperty` and defaults to `'48dp'`. """ tab_indicator_anim = BooleanProperty(False) """ Tab indicator animation. If you want use animation set it to ``True``. :attr:`tab_indicator_anim` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ tab_indicator_height = NumericProperty("2dp") """ Height of the tab indicator. :attr:`tab_indicator_height` is an :class:`~kivy.properties.NumericProperty` and defaults to `'2dp'`. """ anim_duration = NumericProperty(0.2) """ Duration of the slide animation. :attr:`anim_duration` is an :class:`~kivy.properties.NumericProperty` and defaults to `0.2`. """ anim_threshold = BoundedNumericProperty(0.8, min=0.0, max=1.0, errorhandler=lambda x: 0.0 if x < 0.0 else 1.0) """ Animation threshold allow you to change the tab indicator animation effect. :attr:`anim_threshold` is an :class:`~kivy.properties.BoundedNumericProperty` and defaults to `0.8`. """ allow_stretch = BooleanProperty(True) """ If False - tabs will not stretch to full screen. :attr:`allow_stretch` is an :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ background_color = ListProperty() """ Background color of tabs in ``rgba`` format. :attr:`background_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ text_color_normal = ListProperty((1, 1, 1, 1)) """ Text color of the label when it is not selected. :attr:`text_color_normal` is an :class:`~kivy.properties.ListProperty` and defaults to `(1, 1, 1, 1)`. """ text_color_active = ListProperty((1, 1, 1, 1)) """ Text color of the label when it is selected. :attr:`text_color_active` is an :class:`~kivy.properties.ListProperty` and defaults to `(1, 1, 1, 1)`. """ elevation = NumericProperty(0) """ Tab value elevation. .. seealso:: `Behaviors/Elevation <https://kivymd.readthedocs.io/en/latest/behaviors/elevation/index.html>`_ :attr:`elevation` is an :class:`~kivy.properties.NumericProperty` and defaults to `0`. """ color_indicator = ListProperty() """ Color indicator in ``rgba`` format. :attr:`color_indicator` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ callback = ObjectProperty() """ User callback. The method will be called when the ``on_ref_press`` event occurs in the :class:`~MDTabsLabel` class. :attr:`callback` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ lock_swiping = BooleanProperty(False) """ If True - disable switching tabs by swipe. :attr:`lock_swiping` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ font_name = StringProperty("Roboto") def __init__(self, **kwargs): super().__init__(**kwargs) self.register_event_type("on_tab_switch") self.register_event_type("on_slide_progress") Clock.schedule_once(self._carousel_bind, 1) def _carousel_bind(self, i): self.carousel.bind(on_slide_progress=self._on_slide_progress) def on_slide_progress(self, *args): pass def on_tab_switch(self, *args): """Called when switching tabs.""" def _on_slide_progress(self, *args): self.dispatch("on_slide_progress", args) def get_tab_list(self): """Returns a list of tab objects.""" return self.tab_bar.layout.children def on_carousel_index(self, carousel, index): # when the index of the carousel change, update # tab indicator, select the current tab and reset threshold data. current_tab_label = carousel.current_slide.tab_label if current_tab_label.state == "normal": current_tab_label._do_press() self.tab_bar.update_indicator(current_tab_label.x, current_tab_label.width) def add_widget(self, widget, index=0, canvas=None): # You can add only subclass of MDTabsBase. if len(self.children) >= 2: try: widget.tab_label.group = str(self) widget.tab_label.callback = self.callback widget.tab_label.tab_bar = self.tab_bar widget.tab_label.text_color_normal = self.text_color_normal widget.tab_label.text_color_active = self.text_color_active self.bind(text_color_normal=widget.tab_label.setter( "text_color_normal")) self.bind(text_color_active=widget.tab_label.setter( "text_color_active")) self.bind(font_name=widget.tab_label.setter("font_name")) self.tab_bar.layout.add_widget(widget.tab_label) self.carousel.add_widget(widget) return except AttributeError: pass return super().add_widget(widget) def remove_widget(self, widget): # You can remove only subclass of MDTabsLabel. if not issubclass(widget.__class__, MDTabsLabel): raise MDTabsException( "MDTabs can remove only subclass of MDTabsLabel") self.tab_bar.layout.remove_widget(widget) for tab in self.carousel.slides: if tab.text == widget.text: self.carousel.slides.remove(tab) break
class MenuIconItem(BasedMenuItem, ThemableBehavior): icon = StringProperty("circle-outline") icon_color = ListProperty() icon_size = NumericProperty()
class MDFloatingLabel(MDCard): text = StringProperty()
class ScrolllabelLabel(ScrollView): game_log = StringProperty('') def __init__(self, **kwargs): super(ScrolllabelLabel, self).__init__(**kwargs)
class AnimatedButton(Label): state = OptionProperty('normal', options=('normal', 'down')) allow_stretch = BooleanProperty(True) keep_ratio = BooleanProperty(False) border = ObjectProperty(None) anim_delay = ObjectProperty(None) background_normal = StringProperty( 'atlas://data/images/defaulttheme/button') texture_background = ObjectProperty(None) background_down = StringProperty( 'atlas://data/images/defaulttheme/button_pressed') def __init__(self, **kwargs): super(AnimatedButton, self).__init__(**kwargs) self.register_event_type('on_press') self.register_event_type('on_release') #borderImage.border by default is ... self.border = (16, 16, 16, 16) #Image to display depending on state self.img = Image(source = self.background_normal, allow_stretch = self.allow_stretch, keep_ratio = self.keep_ratio, mipmap = True) #reset animation if anim_delay is changed def anim_reset(*l): self.img.anim_delay = self.anim_delay self.bind(anim_delay = anim_reset) self.anim_delay = .1 #update self.texture when image.texture changes self.img.bind(texture = self.on_tex_changed) self.on_tex_changed() #update image source when background image is changed def background_changed(*l): self.img.source = self.background_normal self.anim_delay = .1 self.bind(background_normal = background_changed) def on_tex_changed(self, *largs): self.texture_background = self.img.texture def _do_press(self): self.state = 'down' def _do_release(self): self.state = 'normal' def on_touch_down(self, touch): if not self.collide_point(touch.x, touch.y): return False if repr(self) in touch.ud: return False touch.grab(self) touch.ud[repr(self)] = True _animdelay = self.img.anim_delay self.img.source = self.background_down self.img.anim_delay = _animdelay self._do_press() self.dispatch('on_press') return True def on_touch_move(self, touch): return repr(self) in touch.ud def on_touch_up(self, touch): if touch.grab_current is not self: return assert(repr(self) in touch.ud) touch.ungrab(self) _animdelay = self.img._coreimage.anim_delay self.img.source = self.background_normal self.anim_delay = _animdelay self._do_release() self.dispatch('on_release') return True def on_press(self): pass def on_release(self): pass
class MDCard( ThemableBehavior, BackgroundColorBehavior, RectangularElevationBehavior, FocusBehavior, BoxLayout, RectangularRippleBehavior, ): background = StringProperty() """ Background image path. :attr:`background` is a :class:`~kivy.properties.StringProperty` and defaults to `''`. """ focus_behavior = BooleanProperty(False) """ Using focus when hovering over a card. :attr:`focus_behavior` is a :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ ripple_behavior = BooleanProperty(False) """ Use ripple effect for card. :attr:`ripple_behavior` is a :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ elevation = NumericProperty(None, allownone=True) """ Elevation value. :attr:`elevation` is an :class:`~kivy.properties.NumericProperty` and defaults to 1. """ _bg_color_map = ( get_color_from_hex(colors["Light"]["CardsDialogs"]), get_color_from_hex(colors["Dark"]["CardsDialogs"]), [1.0, 1.0, 1.0, 0.0], ) def __init__(self, **kwargs): super().__init__(**kwargs) self.theme_cls.bind(theme_style=self.update_md_bg_color) Clock.schedule_once(lambda x: self._on_elevation(self.elevation)) Clock.schedule_once( lambda x: self._on_ripple_behavior(self.ripple_behavior) ) self.update_md_bg_color(self, self.theme_cls.theme_style) def update_md_bg_color(self, instance, value): if self.md_bg_color in self._bg_color_map: self.md_bg_color = get_color_from_hex(colors[value]["CardsDialogs"]) def on_radius(self, instance, value): if self.radius != [0, 0, 0, 0]: self.background = f"{images_path}/transparent.png" def _on_elevation(self, value): if value is None: self.elevation = 6 else: self.elevation = value def _on_ripple_behavior(self, value): self._no_ripple_effect = False if value else True
class InfoBubble(Factory.Bubble): '''Bubble to be used to display short Help Information''' message = StringProperty(_('Nothing set !')) '''Message to be displayed; defaults to "nothing set"''' icon = StringProperty('') ''' Icon to be displayed along with the message defaults to '' :attr:`icon` is a `StringProperty` defaults to `''` ''' fs = BooleanProperty(False) ''' Show Bubble in half screen mode :attr:`fs` is a `BooleanProperty` defaults to `False` ''' modal = BooleanProperty(False) ''' Allow bubble to be hidden on touch. :attr:`modal` is a `BooleanProperty` defauult to `False`. ''' exit = BooleanProperty(False) '''Indicates whether to exit app after bubble is closed. :attr:`exit` is a `BooleanProperty` defaults to False. ''' dim_background = BooleanProperty(False) ''' Indicates Whether to draw a background on the windows behind the bubble. :attr:`dim` is a `BooleanProperty` defaults to `False`. ''' def on_touch_down(self, touch): if self.modal: return True self.hide() if self.collide_point(*touch.pos): return True def show(self, pos, duration, width=None, modal=False, exit=False): '''Animate the bubble into position''' self.modal, self.exit = modal, exit if width: self.width = width if self.modal: from kivy.uix.modalview import ModalView self._modal_view = m = ModalView(background_color=[.5, .5, .5, .2]) Window.add_widget(m) m.add_widget(self) else: Window.add_widget(self) # wait for the bubble to adjust it's size according to text then animate Clock.schedule_once(lambda dt: self._show(pos, duration)) def _show(self, pos, duration): def on_stop(*l): if duration: Clock.schedule_once(self.hide, duration + .5) self.opacity = 0 arrow_pos = self.arrow_pos if arrow_pos[0] in ('l', 'r'): pos = pos[0], pos[1] - (self.height / 2) else: pos = pos[0] - (self.width / 2), pos[1] self.limit_to = Window anim = Factory.Animation(opacity=1, pos=pos, d=.32) anim.bind(on_complete=on_stop) anim.cancel_all(self) anim.start(self) def hide(self, now=False): ''' Auto fade out the Bubble ''' def on_stop(*l): if self.modal: m = self._modal_view m.remove_widget(self) Window.remove_widget(m) Window.remove_widget(self) if self.exit: App.get_running_app().stop() import sys sys.exit() else: App.get_running_app().is_exit = False if now: return on_stop() anim = Factory.Animation(opacity=0, d=.25) anim.bind(on_complete=on_stop) anim.cancel_all(self) anim.start(self)
class SnakeGame(Widget): head = ObjectProperty(None) fruit = ObjectProperty(None) score = NumericProperty(0) player_size = NumericProperty(PLAYER_SIZE) game_over = StringProperty("") def __init__(self): super(SnakeGame, self).__init__() Window.size = (WINDOW_WIDTH, WINDOW_HEIGHT) Window.bind(on_key_down=self.key_action) if PLAYER_SIZE < 3: raise ValueError("Player size should be at least 3 px") if WINDOW_HEIGHT < 3 * PLAYER_SIZE or WINDOW_WIDTH < 3 * PLAYER_SIZE: raise ValueError( "Window size must be at least 3 times larger than player size") self.timer = Clock.schedule_interval(self.refresh, GAME_SPEED) self.tail = [] self.restart_game() def restart_game(self): """Resets the game to its initial state """ self.occupied = smartGrid() # resets the timer self.timer.cancel() self.timer = Clock.schedule_interval(self.refresh, GAME_SPEED) self.head.reset_pos() self.score = 0 for block in self.tail: self.remove_widget(block) # the tail is indexed in a way that the last block is idx 0 self.tail = [] # first two blocks added to the tail self.tail.append( SnakeTail(pos=(self.head.pos[0] - PLAYER_SIZE, self.head.pos[1]), size=(self.head.size))) self.add_widget(self.tail[-1]) self.occupied[self.tail[-1].pos] = True self.tail.append( SnakeTail(pos=(self.head.pos[0] - 2 * PLAYER_SIZE, self.head.pos[1]), size=(self.head.size))) self.add_widget(self.tail[-1]) self.occupied[self.tail[1].pos] = True self.spawn_fruit() def refresh(self, dt): """This block of code is executed every GAME_SPEED seconds 'dt' must be used to allow kivy.Clock objects to use this function """ # outside the boundaries of the game if not (0 <= self.head.pos[0] < WINDOW_WIDTH) or \ not (0 <= self.head.pos[1] < WINDOW_HEIGHT): self.restart_game() return # collides with its tail if self.occupied[self.head.pos] is True: self.restart_game() return # move the tail self.occupied[self.tail[-1].pos] = False self.tail[-1].move(self.tail[-2].pos) for i in range(2, len(self.tail)): self.tail[-i].move(new_pos=(self.tail[-(i + 1)].pos)) self.tail[0].move(new_pos=self.head.pos) self.occupied[self.tail[0].pos] = True # move the head self.head.move() # check if we found the fruit, if so, add another tail if self.head.pos == self.fruit.pos: self.score += 1 self.tail.append(SnakeTail(pos=self.head.pos, size=self.head.size)) self.add_widget(self.tail[-1]) self.spawn_fruit() def spawn_fruit(self): roll = self.fruit.pos found = False while not found: # roll new random positions until one is free roll = [ PLAYER_SIZE * randint(0, int(WINDOW_WIDTH / PLAYER_SIZE) - 1), PLAYER_SIZE * randint(0, int(WINDOW_HEIGHT / PLAYER_SIZE) - 1) ] if self.occupied[roll] is True or \ roll == self.head.pos: continue found = True self.fruit.move(roll) def key_action(self, *args): """This handles user input """ command = list(args)[3] if command == 'w' or command == 'up': self.head.orientation = (0, PLAYER_SIZE) elif command == 's' or command == 'down': self.head.orientation = (0, -PLAYER_SIZE) elif command == 'a' or command == 'left': self.head.orientation = (-PLAYER_SIZE, 0) elif command == 'd' or command == 'right': self.head.orientation = (PLAYER_SIZE, 0) elif command == 'r': self.restart_game()
class ImageChooserCell(Widget): image_location = StringProperty("None") image_chooser = ObjectProperty(None) def cell_press(self): self.image_chooser.select(self.image_location)
class ScrollableLabel(ScrollView): text = StringProperty( color_text("Hello. Ask me to create a reminder.\n\n"))
class ParticlePanel(Widget): particle_builder = ObjectProperty(None) texture_path = StringProperty("media/particle.png") max_num_particles = NumericProperty(200.) max_num_particles_min = NumericProperty(1.) max_num_particles_max = NumericProperty(500.) life_span = NumericProperty(2.) life_span_min = NumericProperty(.01) life_span_max = NumericProperty(10.) life_span_variance = NumericProperty(0.) life_span_variance_min = NumericProperty(0.) life_span_variance_max = NumericProperty(10.) start_size = NumericProperty(8.) start_size_min = NumericProperty(0.) start_size_max = NumericProperty(256.) start_size_variance = NumericProperty(0.) start_size_variance_min = NumericProperty(0.) start_size_variance_max = NumericProperty(256.) end_size = NumericProperty(8.) end_size_min = NumericProperty(0.) end_size_max = NumericProperty(256.) end_size_variance = NumericProperty(0.) end_size_variance_min = NumericProperty(0.) end_size_variance_max = NumericProperty(256.) emit_angle = NumericProperty(0.) emit_angle_min = NumericProperty(0.) emit_angle_max = NumericProperty(360.) emit_angle_variance = NumericProperty(0.) emit_angle_variance_min = NumericProperty(0.) emit_angle_variance_max = NumericProperty(360.) start_rotation = NumericProperty(0.) start_rotation_min = NumericProperty(0.) start_rotation_max = NumericProperty(360.) start_rotation_variance = NumericProperty(0.) start_rotation_variance_min = NumericProperty(0.) start_rotation_variance_max = NumericProperty(360.) end_rotation = NumericProperty(0.) end_rotation_min = NumericProperty(0.) end_rotation_max = NumericProperty(360.) end_rotation_variance = NumericProperty(0.) end_rotation_variance_min = NumericProperty(0.) end_rotation_variance_max = NumericProperty(360.) def __init__(self, pbuilder, **kwargs): super(ParticlePanel, self).__init__(**kwargs) self.particle_builder = pbuilder.parent def on_max_num_particles(self, instance, value): self.particle_builder.demo_particle.max_num_particles = value def on_life_span(self, instance, value): self.particle_builder.demo_particle.life_span = value def on_life_span_variance(self, instance, value): self.particle_builder.demo_particle.life_span_variance = value def on_start_size(self, instance, value): self.particle_builder.demo_particle.start_size = value def on_start_size_variance(self, instance, value): self.particle_builder.demo_particle.start_size_variance = value def on_end_size(self, instance, value): self.particle_builder.demo_particle.end_size = value def on_end_size_variance(self, instance, value): self.particle_builder.demo_particle.end_size_variance = value def on_emit_angle(self, instance, value): self.particle_builder.demo_particle.emit_angle = value * 0.0174532925 def on_emit_angle_variance(self, instance, value): self.particle_builder.demo_particle.emit_angle_variance = value * 0.0174532925 def on_start_rotation(self, instance, value): self.particle_builder.demo_particle.start_rotation = value def on_start_rotation_variance(self, instance, value): self.particle_builder.demo_particle.start_rotation_variance = value def on_end_rotation(self, instance, value): self.particle_builder.demo_particle.end_rotation = value def on_end_rotation_variance(self, instance, value): self.particle_builder.demo_particle.end_rotation_variance = value def on_texture_path(self,instance,value): self.particle_builder.demo_particle.texture_path = value self.particle_builder.demo_particle.texture = Image(value).texture def get_values_from_particle(self): properties = ['max_num_particles', 'life_span', 'life_span_variance', 'start_size', 'start_size_variance', 'end_size', 'end_size_variance', 'emit_angle', 'emit_angle_variance', 'start_rotation', 'start_rotation_variance', 'end_rotation', 'end_rotation_variance', 'texture_path'] for p in properties: if p in ['emit_angle', 'emit_angle_variance', ]: setattr(self,p,getattr(self.particle_builder.demo_particle,p) / 0.0174532925 ) else: setattr(self,p,getattr(self.particle_builder.demo_particle,p)) self.image_chooser_button.image_location = self.particle_builder.demo_particle.texture_path
class FrontPage(Screen, MakesmithInitFuncs): textconsole = ObjectProperty(None) connectmenu = ObjectProperty( None) #make ConnectMenu object accessible at this scope gcodecanvas = ObjectProperty(None) screenControls = ObjectProperty(None) target = [0, 0, 0] connectionStatus = StringProperty("Not Connected") xReadoutPos = StringProperty("0 mm") yReadoutPos = StringProperty("0 mm") zReadoutPos = StringProperty("0 mm") numericalPosX = 0.0 numericalPosY = 0.0 stepsizeval = 0 feedRate = 0 shiftX = 0 shiftY = 0 consoleText = StringProperty(" ") units = StringProperty("MM") gcodeLineNumber = StringProperty('0') def __init__(self, data, **kwargs): super(FrontPage, self).__init__(**kwargs) self.data = data def setPosReadout(self, xPos, yPos, zPos, units): self.xReadoutPos = str(xPos) + " " + units self.yReadoutPos = str(yPos) + " " + units self.zReadoutPos = str(zPos) + " " + units self.numericalPosX = xPos self.numericalPosY = yPos def setUpData(self, data): self.gcodecanvas.setUpData(data) self.screenControls.setUpData(data) self.data.bind(connectionStatus=self.updateConnectionStatus) self.data.bind(units=self.onUnitsSwitch) self.data.bind(gcodeIndex=self.onIndexMove) def updateConnectionStatus(self, callback, connected): if connected: self.connectionStatus = "Connected" else: self.connectionStatus = "Connection Lost" def switchUnits(self): if self.data.units == "INCHES": self.data.units = "MM" else: self.data.units = "INCHES" def onUnitsSwitch(self, callback, newUnits): self.units = newUnits #the behavior of notifying the machine doesn't really belong here #but I'm not really sure where else it does belong if newUnits == "INCHES": self.data.gcode_queue.put('G20 ') self.moveDistInput.text = str(float(self.moveDistInput.text) / 25) else: self.data.gcode_queue.put('G21 ') self.moveDistInput.text = str(float(self.moveDistInput.text) * 25) def onIndexMove(self, callback, newIndex): self.gcodeLineNumber = str(newIndex) def moveGcodeIndex(self, dist): self.data.gcodeIndex = self.data.gcodeIndex + dist gCodeLine = self.data.gcode[self.data.gcodeIndex] print gCodeLine xTarget = 0 yTarget = 0 x = re.search("X(?=.)([+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) if x: xTarget = float(x.groups()[0]) y = re.search("Y(?=.)([+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) if y: yTarget = float(y.groups()[0]) self.gcodecanvas.targetIndicator.setPos(xTarget, yTarget, self.data.units) def pause(self): self.data.uploadFlag = 0 self.data.quick_queue.put("STOP") with self.data.gcode_queue.mutex: self.data.gcode_queue.queue.clear() print("Run Paused") def jmpsize(self): try: self.stepsizeval = float(self.moveDistInput.text) except: pass try: self.feedRate = float(self.moveSpeedInput.text) except: pass def test(self): self.data.gcode_queue.put("B01") def upLeft(self): self.jmpsize() xtarget = -1 * self.target[0] - float(self.stepsizeval) ytarget = self.target[1] + float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(xtarget) + " Y" + str(ytarget) + " ") self.target[0] = self.target[0] + float(self.stepsizeval) self.target[1] = self.target[1] + float(self.stepsizeval) def upRight(self): self.jmpsize() xtarget = -1 * self.target[0] + float(self.stepsizeval) ytarget = self.target[1] + float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(xtarget) + " Y" + str(ytarget) + " ") self.target[0] = self.target[0] - float(self.stepsizeval) self.target[1] = self.target[1] + float(self.stepsizeval) def up(self): self.jmpsize() target = self.target[1] + float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Y" + str(target) + " ") self.target[1] = self.target[1] + float(self.stepsizeval) def left(self): self.jmpsize() target = -1 * self.target[0] - float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(target) + " ") self.target[0] = self.target[0] + float(self.stepsizeval) def right(self): self.jmpsize() target = -1 * self.target[0] + float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(target) + " ") self.target[0] = self.target[0] - float(self.stepsizeval) def downLeft(self): self.jmpsize() xtarget = -1 * self.target[0] - float(self.stepsizeval) ytarget = self.target[1] - float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(xtarget) + " Y" + str(ytarget) + " ") self.target[0] = self.target[0] + float(self.stepsizeval) self.target[1] = self.target[1] - float(self.stepsizeval) def down(self): self.jmpsize() target = self.target[1] - float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Y" + str(target) + " ") self.target[1] = self.target[1] - float(self.stepsizeval) def downRight(self): self.jmpsize() xtarget = -1 * self.target[0] + float(self.stepsizeval) ytarget = self.target[1] - float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X" + str(xtarget) + " Y" + str(ytarget) + " ") self.target[0] = self.target[0] - float(self.stepsizeval) self.target[1] = self.target[1] - float(self.stepsizeval) def zUp(self): self.jmpsize() target = self.target[2] + 0.10 * float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Z" + str(target) + " ") self.target[2] = self.target[2] + 0.10 * float(self.stepsizeval) def zDown(self): self.jmpsize() target = self.target[2] - 0.10 * float(self.stepsizeval) self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Z" + str(target) + " ") self.target[2] = self.target[2] - 0.10 * float(self.stepsizeval) def home(self): if self.target[2] < 0: self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Z0 ") self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X0 Y0 Z0 ") if self.target[2] >= 0: self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " X0 Y0 ") self.data.gcode_queue.put("G00 F" + str(float(self.feedRate)) + " Z0 ") self.target[0] = 0.0 self.target[1] = 0.0 self.target[2] = 0.0 def reZero(self): self.target = [0, 0, 0] self.data.gcode_queue.put("G10 X0 Y0 Z0 ") def moveLine(self, gcodeLine, moveXBy, moveYBy): originalLine = gcodeLine try: gcodeLine = gcodeLine.upper() + " " x = gcodeLine.find('X') if x != -1: space = gcodeLine.find(' ', x) number = float(gcodeLine[x + 1:space]) + moveXBy gcodeLine = gcodeLine[0:x + 1] + str(number) + gcodeLine[space:] y = gcodeLine.find('Y') if y != -1: space = gcodeLine.find(' ', y) number = float(gcodeLine[y + 1:space]) + moveYBy gcodeLine = gcodeLine[0:y + 1] + str(number) + gcodeLine[space:] return gcodeLine except ValueError: print "line could not be moved:" print originalLine return originalLine def moveOrigin(self): if self.data.units == "INCHES": amtToShiftX = self.numericalPosX - self.shiftX amtToShiftY = self.numericalPosY - self.shiftY self.shiftX = self.shiftX + amtToShiftX self.shiftY = self.shiftY + amtToShiftY else: amtToShiftX = self.numericalPosX - self.shiftX amtToShiftY = self.numericalPosY - self.shiftY self.shiftX = self.shiftX + amtToShiftX self.shiftY = self.shiftY + amtToShiftY shiftedGcode = [] for line in self.data.gcode: shiftedGcode.append(self.moveLine(line, amtToShiftX, amtToShiftY)) self.data.gcode = shiftedGcode def startRun(self): self.data.uploadFlag = 1 self.sendLine() def sendLine(self): try: self.data.gcode_queue.put(self.data.gcode[self.data.gcodeIndex]) self.data.gcodeIndex = self.data.gcodeIndex + 1 except: print "gcode run complete" self.gcodecanvas.uploadFlag = 0 self.data.gcodeIndex = 0 def stopRun(self): self.data.uploadFlag = 0 self.data.gcodeIndex = 0 self.data.quick_queue.put("STOP") with self.data.gcode_queue.mutex: self.data.gcode_queue.queue.clear() print("Gode Stopped") def textInputPopup(self, target): self.targetWidget = target self.popupContent = TouchNumberInput(done=self.dismiss_popup) self._popup = Popup(title="Load file", content=self.popupContent, size_hint=(0.9, 0.9)) self._popup.open() def dismiss_popup(self): ''' Close The Pop-up ''' self.targetWidget.text = self.popupContent.textInput.text self._popup.dismiss()
class WorkingFile(Widget): filename = StringProperty(None)
class UserAnimationCard(ThemableBehavior, FloatLayout): user_name = StringProperty() path_to_avatar = StringProperty() _callback_back = ObjectProperty() _primary_color = ListProperty()
class AndroidApp(App): #have a reference toscreen manager called mang navbar_label = StringProperty() logged_in = False login_text = StringProperty() patent_matches = NumericProperty() welcome = StringProperty() search_term = StringProperty() search_sentiment = StringProperty() my_token = StringProperty() response = StringProperty() search0 = StringProperty() search1 = StringProperty() search2 = StringProperty() search3 = StringProperty() search4 = StringProperty() search_titl0 = StringProperty() search_titl1 = StringProperty() search_titl2 = StringProperty() search_titl3 = StringProperty() search_titl4 = StringProperty() s_confidence = StringProperty() s1_confidence = StringProperty() s2_confidence = StringProperty() local_result = ListProperty() local_search_term = ListProperty() confidence = NumericProperty() litigation_count0 = StringProperty() litigation_count1 = StringProperty() litigation_count2 = StringProperty() litigation_count3 = StringProperty() litigation_count4 = StringProperty() own_name0 = StringProperty() own_name1 = StringProperty() own_name2 = StringProperty() own_name3 = StringProperty() own_name4 = StringProperty() own_num0 = StringProperty() own_num1 = StringProperty() own_num2 = StringProperty() own_num3 = StringProperty() own_num4 = StringProperty() def analyquery(title, artist, idea): global titles global spotifys global distances global tit_dic num = tit_dic[title] index = 0 mindex = 0 least = 100 for val in distances: if val < least: least = val mindex = index index += 1 return (titles[mindex], spotifys[mindex]) sorted(distances) def mail(self, ID): fromaddr = '*****@*****.**' toaddr = '*****@*****.**' msg = "\r\n".join([ "Subject: Your Saved Patent", "", "Hello Oski! \n\n", "You saved a patent using the Patent Fox app.\n", "Here is the link: \n", "https://drive.google.com/viewerng/viewer?url=patentimages.storage.googleapis.com/pdfs/US6477117.pdf" "https://www.google.com/patents/US" + ID ]) username = '******' password = '******' send_mail(username, password, fromaddr, toaddr, msg) def login(self, email, password): time.sleep(.75) auth_token = "" #payload = urllib.urlencode({'email': email, 'password': password}) endpoint = "http://calwatson.herokuapp.com/users/sign_in" headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain' } #r = UrlRequest(endpoint, req_body=payload, req_headers=headers,debug=True) #r.wait() if True: self.navbar_label = "Logged in as " + email self.login_text = 'Welcome!' self.my_token = "tokentoek" #r.result['auth_token'] self.logged_in = True self.manager.current = 'analysis' #change Screen! else: print "Should never get here" return auth_token def signup(self, email, password): payload = urllib.urlencode({'email': email, 'password': password}) #endpoint = "http://calwatson.herokuapp.com/users/sign_up" headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain' } #r = UrlRequest(endpoint, req_body=payload, req_headers=headers,debug=True) r.wait() if r.result == "Successful sign up": self.login_text = 'Welcome!' self.login(email, password) elif r.result == "That email is already taken.": self.login_text = r.result pass else: print "Should never get here" return def get_last_five_queries(self, token): payload = urllib.urlencode({'token': token}) endpoint = "http://calwatson.herokuapp.com/users/last_requests" headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain' } r = UrlRequest(endpoint, req_body=payload, req_headers=headers, debug=True) r.wait() try: last_queries = r.result['answers'] except: # not able to find auth token pass return last_queries def getAbstract(self, data): try: return data[0] except: return "No abstract found." def getPatentNumber(self, data): try: return data[1] except: return "19283" def getInventor(self, data): try: return data[2] except: return "Vishnay Kuram" def getPhoneNumber(self, data): try: return data[3] except: return "938-374-3948" def getLitigations(self, data): try: return data[4] except: exit() return "0" def local_query(self, term): #set confidence interval time.sleep(.5) amount_found = 0 results = [ documents[word] for word in self.patent_traits if word in term ] self.patent_matches = len(results) if self.patent_matches < 6: #extremely precise patent measure based on machine learning and big-data self.confidence = 75 + random.randint(0, 16) else: self.confidence = 0.73 i = 5 - self.patent_matches if i > 0: while i > 0: rando = random.choice(list(documents.values())) if rando not in results: results.append(rando) i -= 1 self.search_titl0 = "US" + self.getPatentNumber(results[0]) self.search_titl1 = "US" + self.getPatentNumber(results[1]) self.search_titl2 = "US" + self.getPatentNumber(results[2]) self.search_titl3 = "US" + self.getPatentNumber(results[3]) self.search_titl4 = "US" + self.getPatentNumber(results[4]) self.search0 = self.getAbstract(results[0]) self.search1 = self.getAbstract(results[1]) self.search2 = self.getAbstract(results[2]) self.search3 = self.getAbstract(results[3]) self.search4 = self.getAbstract(results[4]) self.litigation_count0 = self.getLitigations(results[0]) self.litigation_count1 = self.getLitigations(results[1]) self.litigation_count2 = self.getLitigations(results[2]) self.litigation_count3 = self.getLitigations(results[3]) self.litigation_count4 = self.getLitigations(results[4]) self.own_name0 = self.getInventor(results[0]) self.own_name1 = self.getInventor(results[1]) self.own_name2 = self.getInventor(results[2]) self.own_name3 = self.getInventor(results[3]) self.own_name4 = self.getInventor(results[4]) self.own_num0 = self.getPhoneNumber(results[0]) self.own_num1 = self.getPhoneNumber(results[1]) self.own_num2 = self.getPhoneNumber(results[2]) self.own_num3 = self.getPhoneNumber(results[3]) self.own_num4 = self.getPhoneNumber(results[4]) return results def query(self, term): payload = urllib.urlencode({ 'question': "{0}".format(term), 'token': self.my_token }) headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain' } r = UrlRequest(endpoint, req_body=payload, req_headers=headers, debug=True) r.wait() print r.result try: d = r.result search0 = d['question']['evidencelist'][0]['text'] self.s_confidence = d['question']['evidencelist'][0]['value'] search1 = d['question']['evidencelist'][1]['text'] self.s1_confidence = d['question']['evidencelist'][1]['value'] search2 = d['question']['evidencelist'][2]['text'] self.s2_confidence = d['question']['evidencelist'][2]['value'] except: search0 = 'Not found' search1 = 'Not found' search2 = 'Not found' self.s_confidence = '' self.s2_confidence = '' self.s3_confidence = '' self.search0 = '' self.search1 = '' self.search2 = '' j = 0 chars_per_line = 8 for i in search0.split(): if j == 40: break if j % chars_per_line == 0: self.search0 += '\n' pass self.search0 += i + ' ' j += 1 j = 0 for i in search1.split(): if j == 40: break if j % chars_per_line == 0: self.search1 += '\n' self.search1 += i + ' ' j += 1 j = 0 for i in search2.split(): if j == 40: break if j % chars_per_line == 0: self.search2 += '\n' self.search2 += i + ' ' j += 1 return self.response def build(self): global RootApp RootApp = self # NavigationDrawer self.navigationdrawer = NavDrawer() #self.navigationdrawer.side_panel_width = .2 # SidePanel side_panel = SidePanel() self.navigationdrawer.add_widget(side_panel) self.navigationdrawer.logged_in = False # MainPanel self.main_panel = MainPanel() self.navigationdrawer.anim_type = 'slide_above_anim' self.navigationdrawer.add_widget(self.main_panel) self.navbar_label = 'Tent' return self.navigationdrawer def toggle_sidepanel(self): self.navigationdrawer.toggle_state() def on_saved(self): self.navigationdrawer.close_sidepanel() if self.logged_in != True: self.login_text = 'Please login before continuing.' else: self.manager.current = 'saved_searches' #switch to saved def on_history(self): self.navigationdrawer.close_sidepanel() if self.logged_in != True: self.login_text = 'Please login before continuing.' else: self.manager.current = 'search_history' def on_settings(self): self.navigationdrawer.close_sidepanel() if self.logged_in != True: self.login_text = 'Please login before continuing.' else: self.manager.current = 'settings' def on_search(self): print('why??') self.navigationdrawer.close_sidepanel() print('why!?') if self.logged_in != True: self.login_text = 'Please login before continuing.' else: self.manager.current = 'analysis' def _switch_main_page(self, key, panel): self.navigationdrawer.close_sidepanel() if not SidePanel_AppMenu[key][id_AppMenu_PANEL]: SidePanel_AppMenu[key][id_AppMenu_PANEL] = panel() main_panel = SidePanel_AppMenu[key][id_AppMenu_PANEL] self.navigationdrawer.remove_widget( self.main_panel) # FACCIO REMOVE ED ADD perchè la set_main_panel self.navigationdrawer.add_widget( main_panel) # dà un'eccezione e non ho capito perchè self.main_panel = main_panel
class DiscordToolbar(CustomToolbar, DiscordTheme): text_color = ListProperty() title = StringProperty() font_size = NumericProperty("20dp")
class RulesWindow(Screen): rules = StringProperty('') def __init__(self, **kwargs): super(RulesWindow, self).__init__(**kwargs) self.rules = rules_string
class NavigationLayout(VendorNavigationDrawer, ThemableBehavior): """The container layout that manages the :class:`MDNavigationDrawer`.""" opening_transition = StringProperty('out_sine') closing_transition = StringProperty('out_sine') min_dist_to_open = NumericProperty(.2) min_dist_to_close = NumericProperty(.8) anim_time = NumericProperty(.2) separator_image = StringProperty('{}'.format(images_path + '/transparent.png')) side_panel_positioning = 'left' side_panel_width = (dp(320) * 80) // 100\ if dp(320) >= Window.width else dp(320) max_shadow_opacity = NumericProperty(.5) anim_type = StringProperty('slide_above_simple') def __init__(self, **kwargs): super().__init__(**kwargs) self.on_anim_type() def _anim_relax(self): if self.state == 'open': if self._anim_progress < self.min_dist_to_close: self.anim_to_state('closed') else: self.anim_to_state('open') else: if self._anim_progress > self.min_dist_to_open: self.anim_to_state('open') else: self.anim_to_state('closed') def on__anim_progress(self, *args): self.side_panel.shadow_color = [ 0, 0, 0, self.max_shadow_opacity * self._anim_progress ] self.side_panel.elevation = 1 * self._anim_progress if self._anim_progress > 1: self._anim_progress = 1 elif self._anim_progress < 0: self._anim_progress = 0 if self._anim_progress >= 1: self.state = 'open' elif self._anim_progress <= 0: self.state = 'closed' def add_widget(self, widget, **kwargs): """ First widget added must be the content for the side/sliding panel. The next widget must be the main content. This layout only accepts two widgets, any more than two widgets will raise a ValueError """ # Internal default BoxLayouts if len(self.children) == 0: super().add_widget(widget, **kwargs) self._side_panel = widget elif len(self.children) == 1: super().add_widget(widget, **kwargs) self._main_panel = widget elif len(self.children) == 2: super().add_widget(widget, **kwargs) self._join_image = widget # Adding of user widgets elif self.side_panel is None: self.set_side_panel(widget) widget.panel = self elif self.main_panel is None: self.set_main_panel(widget) else: raise ValueError( 'Can\'t add more than two widgets directly to NavigationLayout' ) def toggle_nav_drawer(self): self.toggle_state(True)
class CustomOneLineIconListItem(OneLineIconListItem): icon = StringProperty()