def _update_transactions_tab_summary(self) -> None: local_count = 0 local_value = 0 if self._account_id is not None: wallet = self._account.get_wallet() with wallet.get_transaction_delta_table() as table: _account_id, local_value, local_count = table.read_balance( self._account_id, mask=TxFlags.STATE_UNCLEARED_MASK) if local_count == 0: self._local_summary_label.setVisible(False) return value_text = app_state.format_amount( local_value) + " " + app_state.base_unit() if local_count == 1: text = _( "The Transactions tab has <b>1</b> transaction containing <b>{balance}</b> " "in allocated coins.").format(balance=value_text) else: text = _( "The Transactions tab has <b>{count}</b> transactions containing " "<b>{balance}</b> in allocated coins.").format( count=local_count, balance=value_text) self._local_summary_label.setText(text) self._local_summary_label.setVisible(True)
def set_content(self, address_text, amount, message, url): self.address_label.setText(address_text) if amount: amount_text = '{} {}'.format(self.win.format_amount(amount), app_state.base_unit()) else: amount_text = '' self.amount_label.setText(amount_text) self.msg_label.setText(message) self.qrw.setData(url)
def set_content(self, address_text, amount, message, url): self._address_edit.setPlainText(address_text) if amount: amount_text = '{} {}'.format(app_state.format_amount(amount), app_state.base_unit()) else: amount_text = '' self._amount_edit.setText(amount_text) self._message_edit.setPlainText(message) self.qrw.setData(url)
def _on_entry_changed(self) -> None: text = "" if self._not_enough_funds: amt_color = ColorScheme.RED text = _("Not enough funds") c, u, x = self._account.get_frozen_balance() if c + u + x: text += (' (' + app_state.format_amount(c + u + x).strip() + ' ' + app_state.base_unit() + ' ' + _("are frozen") + ')') if self.amount_e.isModified(): amt_color = ColorScheme.DEFAULT else: amt_color = ColorScheme.BLUE self._main_window.statusBar().showMessage(text) self.amount_e.setStyleSheet(amt_color.as_stylesheet())
def update(self): desc = self.desc base_unit = app_state.base_unit() format_amount = self.main_window.format_amount tx_info = self.wallet.get_tx_info(self.tx) tx_info_fee = tx_info.fee size = self.tx.estimated_size() self.broadcast_button.setEnabled(tx_info.can_broadcast) if self.main_window.network is None: self.broadcast_button.setEnabled(False) self.broadcast_button.setToolTip( _('You are using ElectrumSV in offline mode; restart ' 'ElectrumSV if you want to get connected')) can_sign = not self.tx.is_complete() and \ (self.wallet.can_sign(self.tx) or bool(self.main_window.tx_external_keypairs)) self.sign_button.setEnabled(can_sign) self._tx_hash = tx_info.hash self.tx_hash_e.setText(tx_info.hash or _('Unknown')) if tx_info_fee is None: try: # Try and compute fee. We don't always have 'value' in # all the inputs though. :/ tx_info_fee = self.tx.get_fee() except KeyError: # Value key missing from an input pass if desc is None: self.tx_desc.hide() else: self.tx_desc.setText(_("Description") + ': ' + desc) self.tx_desc.show() self.status_label.setText(_('Status:') + ' ' + tx_info.status) if tx_info.timestamp: time_str = datetime.datetime.fromtimestamp( tx_info.timestamp).isoformat(' ')[:-3] self.date_label.setText(_("Date: {}").format(time_str)) self.date_label.show() else: self.date_label.hide() if tx_info.amount is None: amount_str = _("Transaction unrelated to your wallet") elif tx_info.amount > 0: amount_str = '{} {} {}'.format(_("Amount received:"), format_amount(tx_info.amount), base_unit) else: amount_str = '{} {} {}'.format(_("Amount sent:"), format_amount(-tx_info.amount), base_unit) size_str = _("Size:") + ' %d bytes' % size if tx_info_fee is not None: fee_amount = '{} {}'.format(format_amount(tx_info_fee), base_unit) else: fee_amount = _('unknown') fee_str = '{}: {}'.format(_("Fee"), fee_amount) if tx_info_fee is not None: fee_str += ' ( {} ) '.format( self.main_window.format_fee_rate(tx_info_fee / size * 1000)) self.amount_label.setText(amount_str) self.fee_label.setText(fee_str) self.size_label.setText(size_str) # Cosigner button visible = app_state.app.cosigner_pool.show_button(self.wallet, self.tx) self.cosigner_button.setVisible(visible)
def update(self) -> None: base_unit = app_state.base_unit() format_amount = app_state.format_amount tx_info = self._get_tx_info(self.tx) tx_info_fee = tx_info.fee self.broadcast_button.setEnabled(tx_info.can_broadcast) if self._main_window.network is None: self.broadcast_button.setEnabled(False) self.broadcast_button.setToolTip( _('You are using ElectrumSV in offline mode; restart ' 'ElectrumSV if you want to get connected')) can_sign = not self.tx.is_complete() and self._account.can_sign( self.tx) self.sign_button.setEnabled(can_sign) self._tx_hash = tx_info.hash tx_id = hash_to_hex_str(tx_info.hash) self.tx_hash_e.setText(tx_id) if tx_info_fee is None: try: # Try and compute fee. We don't always have 'value' in all the inputs though. :/ tx_info_fee = self.tx.get_fee() except TypeError: # At least one of the XTxInputs does not have an attached value. pass else: if tx_info_fee < 0: tx_info_fee = None if self.tx.context.description is None: self.tx_desc.hide() else: self.tx_desc.setText(self.tx.context.description) self.tx_desc.show() self.status_label.setText(tx_info.status) time_str = "" if tx_info.date_mined: time_str = datetime.datetime.fromtimestamp( tx_info.date_mined).isoformat(' ')[:-3] time_str += "\n" if tx_info.date_created: time_str += (datetime.datetime.fromtimestamp( tx_info.date_created).isoformat(' ')[:-3] + " (" + _("added to account") + ")") self.date_label.setText(time_str) self.date_label.show() if tx_info.amount is None: amount_str = _("Unknown") elif math.isclose(tx_info.amount, 0, abs_tol=1e-9): amount_str = "No external payment" elif tx_info.amount > 0: amount_str = _("Received") + " " + format_amount( tx_info.amount) + " " + base_unit else: amount_str = _("Sent") + " " + format_amount( -tx_info.amount) + " " + base_unit self.amount_label.setText(amount_str) size = self.tx.size() self.size_label.setText('%d bytes' % size) if tx_info_fee is not None: fee_amount = '{} {}'.format(format_amount(tx_info_fee), base_unit) else: fee_amount = _('Unknown') fee_str = '{}'.format(fee_amount) if tx_info_fee is not None: fee_str += ' ({}) '.format( self._main_window.format_fee_rate(tx_info_fee / size * 1000)) self.fee_label.setText(fee_str) # Cosigner button visible = app_state.app.cosigner_pool.show_send_to_cosigner_button( self._main_window, self._account, self.tx) self.cosigner_button.setVisible(visible) # Copy options. self._copy_menu.clear() if self.tx.is_complete(): self._copy_hex_menu = self._copy_menu.addAction( _("Transaction (hex)"), partial(self._copy_transaction, TxSerialisationFormat.HEX)) if self._account: self._copy_extended_full_menu = self._copy_menu.addAction( _("Transaction with proofs (JSON)"), partial(self._copy_transaction, TxSerialisationFormat.JSON_WITH_PROOFS)) else: self._copy_extended_basic_menu = self._copy_menu.addAction( _("Incomplete transaction (JSON)"), partial(self._copy_transaction, TxSerialisationFormat.JSON)) if self._account: self._copy_extended_full_menu = self._copy_menu.addAction( _("Incomplete transaction with proofs (JSON)"), partial(self._copy_transaction, TxSerialisationFormat.JSON_WITH_PROOFS)) # Save options. self._save_menu.clear() if self.tx.is_complete(): self._save_raw_menu = self._save_menu.addAction( _("Transaction (raw)"), partial(self._save_transaction, TxSerialisationFormat.RAW)) self._save_hex_menu = self._save_menu.addAction( _("Transaction (hex)"), partial(self._save_transaction, TxSerialisationFormat.HEX)) if self._account: self._save_extended_full_menu = self._save_menu.addAction( _("Transaction with proofs (JSON)"), partial(self._save_transaction, TxSerialisationFormat.JSON_WITH_PROOFS)) else: self._save_extended_basic_menu = self._save_menu.addAction( _("Incomplete transaction (JSON)"), partial(self._save_transaction, TxSerialisationFormat.JSON)) if self._account: self._save_extended_full_menu = self._save_menu.addAction( _("Incomplete transaction with proofs (JSON)"), partial(self._save_transaction, TxSerialisationFormat.JSON_WITH_PROOFS))
def update_balances(self): wallet = self._main_window._wallet self.unfrozen_balance = self._account.get_balance( exclude_frozen_coins=True) self.frozen_balance = self._account.get_frozen_balance() unfrozen_confirmed, unfrozen_unconfirmed, _unfrozen_unmature = self.unfrozen_balance _frozen_confirmed, _frozen_unconfirmed, _frozen_unmature = self.frozen_balance splittable_amount = unfrozen_confirmed + unfrozen_unconfirmed # unsplittable_amount = unfrozen_unmature + frozen_confirmed + frozen_unconfirmed # + frozen_unmature splittable_amount_text = self._main_window.format_amount( splittable_amount) unit_text = app_state.base_unit() text = [ "<p>", _("As of the November 2018 hard-fork, Bitcoin Cash split into Bitcoin ABC " "and Bitcoin SV."), " ", _("This tab allows you to easily split the available coins in this account " "(approximately {} {}) on the Bitcoin SV chain.".format( splittable_amount_text, unit_text)), " ", _("This will involve the following steps if you choose to proceed:" ), "</p>", "<ol>", "<li>", _("Your browser will open to a faucet that can provide you with a small amount of SV " "coin. Once you have operated the faucet, and obtained it, ElectrumSV will " "detect it."), "</li>", "<li>", _("A transaction will be constructed including your entire spendable balance " "combined with the new known SV coin from the faucet, to be sent back into " "this account."), "</li>", ] text.extend([ "<li>", _("As this account is password protected, you will be prompted to " "enter your password to sign the transaction."), "</li>", ]) text.extend([ "<li>", _("The transaction will then be broadcast, and immediately added to your " "account history so you can see it confirmed. It will be labeled as splitting " "related, so you can easily identify it."), "</li>", "<li>", _("You can then open Electron Cash and move your ABC coins to a different address, " "in order to finalise the split."), "</li>", "</ol>", "<p>", _("<b>This will only split the coins currently available in this account.</b> " "While any further coins you send to your account are included in the overall " "balance, if they were unsplit before sending, they remain unsplit on arrival. " "It it your responsibility to ensure you know if you are sending unsplit coins " "and what the repercussions are. If in doubt, click split and be sure." ), "</p>", ]) self.intro_label.setText("".join(text))
def general_widgets(self): # language lang_modifiable = app_state.config.is_modifiable('language') lang_pairs = sorted( (code, language) for language, code in languages.items()) language_names, language_keys = zip(*lang_pairs) lang_label = HelpLabel( _('Language') + ':', _('Select which language is used in the GUI (after restart).')) lang_label.setEnabled(lang_modifiable) lang_combo = QComboBox() lang_combo.setEnabled(lang_modifiable) lang_combo.addItems(language_names) try: index = language_keys.index(app_state.config.get("language", '')) except ValueError: index = 0 lang_combo.setCurrentIndex(index) def on_lang(index): lang_request = language_keys[index] if lang_request != app_state.config.get('language'): app_state.config.set_key("language", lang_request, True) lang_combo.currentIndexChanged.connect(on_lang) nz_modifiable = app_state.config.is_modifiable('num_zeros') nz_label = HelpLabel( _('Zeros after decimal point') + ':', _('Number of zeros displayed after the decimal point. ' 'For example, if set to 2, "1." will be displayed as "1.00"')) nz_label.setEnabled(nz_modifiable) nz = QSpinBox() nz.setMinimum(0) nz.setMaximum(app_state.decimal_point) nz.setValue(app_state.num_zeros) nz.setEnabled(nz_modifiable) def on_nz(): value = nz.value() if app_state.num_zeros != value: app_state.num_zeros = value app_state.config.set_key('num_zeros', value, True) app_state.app.num_zeros_changed.emit() nz.valueChanged.connect(on_nz) unit_label = HelpLabel( _('Base unit') + ':', '\n'.join(( _('Base unit of display in the application.'), '1 BSV = 1,000 mBSV = 1,000,000 bits.', ))) unit_combo = QComboBox() unit_combo.addItems(app_state.base_units) unit_combo.setCurrentIndex( app_state.base_units.index(app_state.base_unit())) def on_unit(index): app_state.set_base_unit(app_state.base_units[index]) nz.setMaximum(app_state.decimal_point) unit_combo.currentIndexChanged.connect(on_unit) msg = _( 'Choose which online block explorer to use for functions that open a web browser' ) block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg) block_explorers = web.BE_sorted_list() block_ex_combo = QComboBox() block_ex_combo.addItems(block_explorers) block_ex_combo.setCurrentIndex( block_ex_combo.findText(web.BE_from_config(app_state.config))) def on_be(index): app_state.config.set_key('block_explorer', block_explorers[index], True) block_ex_combo.currentIndexChanged.connect(on_be) qr_label = HelpLabel( _('Video Device') + ':', _("Install the zbar package to enable this.")) qr_combo = QComboBox() qr_combo.addItem("Default", "default") system_cameras = qrscanner.find_system_cameras() for camera, device in system_cameras.items(): qr_combo.addItem(camera, device) qr_combo.setCurrentIndex( qr_combo.findData(app_state.config.get("video_device"))) qr_combo.setEnabled(qrscanner.libzbar is not None) def on_video_device(index): app_state.config.set_key("video_device", qr_combo.itemData(index), True) qr_combo.currentIndexChanged.connect(on_video_device) updatecheck_box = QGroupBox(_("Software Updates")) updatecheck_vbox = QVBoxLayout() updatecheck_box.setLayout(updatecheck_vbox) # The main checkbox, which turns update checking on or off completely. updatecheck_cb = QCheckBox( _("Automatically check for software updates")) updatecheck_cb.setChecked(app_state.config.get('check_updates', True)) def on_set_updatecheck(v): app_state.config.set_key('check_updates', v == Qt.Checked, save=True) updatecheck_cb.stateChanged.connect(on_set_updatecheck) updatecheck_vbox.addWidget(updatecheck_cb) # The secondary checkbox, which determines if unstable releases result in notifications. updatecheck_unstable_cb = QCheckBox(_("Ignore unstable releases")) updatecheck_unstable_cb.setChecked( app_state.config.get('check_updates_ignore_unstable', True)) def on_set_updatecheck_unstable(v): app_state.config.set_key('check_updates_ignore_unstable', v == Qt.Checked, save=True) updatecheck_unstable_cb.stateChanged.connect( on_set_updatecheck_unstable) updatecheck_vbox.addWidget(updatecheck_unstable_cb) return [ (lang_label, lang_combo), (nz_label, nz), (unit_label, unit_combo), (block_ex_label, block_ex_combo), (qr_label, qr_combo), (updatecheck_box, ), ]
def get_base_unit(self) -> str: return app_state.base_unit()
def update_balances(self): window = self.window() wallet = window.wallet self.unfrozen_balance = wallet.get_balance( exclude_frozen_coins=True, exclude_frozen_addresses=True) self.frozen_balance = wallet.get_frozen_balance() unfrozen_confirmed, unfrozen_unconfirmed, _unfrozen_unmature = self.unfrozen_balance _frozen_confirmed, _frozen_unconfirmed, _frozen_unmature = self.frozen_balance splittable_amount = unfrozen_confirmed + unfrozen_unconfirmed # unsplittable_amount = unfrozen_unmature + frozen_confirmed + frozen_unconfirmed # + frozen_unmature splittable_amount_text = window.format_amount(splittable_amount) unit_text = app_state.base_unit() text = [ "<p>", _("As of the November 2018 hard-fork, Bitcoin Cash split into Bitcoin ABC " "and Bitcoin SV."), " ", _("This tab allows you to easily split the available coins in this wallet " "(approximately {} {}) on the Bitcoin SV chain.".format( splittable_amount_text, unit_text)), " ", _("This will involve the following steps if you choose to proceed:" ), "</p>", "<ol>", "<li>", _("A small amount of SV coin will be obtained from a faucet."), "</li>", "<li>", _("A transaction will be constructed including your entire spendable balance " "combined with the new known SV coin from the faucet, to be sent back into " "this wallet."), "</li>", ] if wallet.has_password(): text.extend([ "<li>", _("As this wallet is password protected, you will be prompted to " "enter your password to sign the transaction."), "</li>", ]) text.extend([ "<li>", _("The transaction will then be broadcast, and immediately added to your " "wallet history so you can see it confirmed. It will be labeled as splitting " "related, so you can easily identify it."), "</li>", "<li>", _("You can then open Electron Cash and move your ABC coins to a different address, " "in order to finalise the split."), "</li>", "</ol>", ]) self.intro_label.setText("".join(text))
def update(self) -> None: base_unit = app_state.base_unit() format_amount = self._main_window.format_amount tx_info = self.get_tx_info(self.tx) tx_info_fee = tx_info.fee size = self.tx.size() self.broadcast_button.setEnabled(tx_info.can_broadcast) if self._main_window.network is None: self.broadcast_button.setEnabled(False) self.broadcast_button.setToolTip(_('You are using ElectrumSV in offline mode; restart ' 'ElectrumSV if you want to get connected')) can_sign = not self.tx.is_complete() and self._account.can_sign(self.tx) self.sign_button.setEnabled(can_sign) self._tx_hash = tx_info.hash tx_id = hash_to_hex_str(tx_info.hash) self.tx_hash_e.setText(tx_id) if tx_info_fee is None: try: # Try and compute fee. We don't always have 'value' in # all the inputs though. :/ tx_info_fee = self.tx.get_fee() except KeyError: # Value key missing from an input pass if tx_info_fee < 0: tx_info_fee = None if self.tx.description is None: self.tx_desc.hide() else: self.tx_desc.setText(self.tx.description) self.tx_desc.show() self.status_label.setText(tx_info.status) if tx_info.timestamp: time_str = datetime.datetime.fromtimestamp( tx_info.timestamp).isoformat(' ')[:-3] self.date_label.setText(time_str) self.date_label.show() else: self.date_label.hide() if tx_info.amount is None: amount_str = _("Transaction unrelated to your wallet") elif tx_info.amount > 0: amount_str = '{} {} {}'.format(_("Received") +" ", format_amount(tx_info.amount), base_unit) else: amount_str = '{} {} {}'.format(_("Sent") +" ", format_amount(-tx_info.amount), base_unit) size_str = '%d bytes'% size if tx_info_fee is not None: fee_amount = '{} {}'.format(format_amount(tx_info_fee), base_unit) else: fee_amount = _('unknown') fee_str = '{}'.format(fee_amount) if tx_info_fee is not None: fee_str += ' ({}) '.format(self._main_window.format_fee_rate( tx_info_fee / size * 1000)) self.amount_label.setText(amount_str) self.fee_label.setText(fee_str) self.size_label.setText(size_str) # Cosigner button visible = app_state.app.cosigner_pool.show_send_to_cosigner_button(self._main_window, self._account, self.tx) self.cosigner_button.setVisible(visible)
def __init__(self, main_window: 'ElectrumWindow', row: InvoiceRow) -> None: super().__init__(main_window, _("Invoice")) self.setMinimumWidth(400) self._main_window = weakref.proxy(main_window) self._pr = pr = PaymentRequest.from_json(row.invoice_data) state = row.flags & PaymentFlag.STATE_MASK if state & PaymentFlag.UNPAID and has_expired(row.date_expires): state = PaymentFlag.EXPIRED total_amount = 0 for output in pr.outputs: total_amount += output.amount vbox = QVBoxLayout(self) form = FormSectionWidget(minimum_label_width=120) form.add_row(_('Type'), QLabel(_("BIP270"))) form.add_row(_("State"), QLabel(pr_tooltips.get(state, _("Unknown")))) form.add_row( _('Amount'), QLabel( app_state.format_amount(output.amount) + " " + app_state.base_unit())) form.add_row(_('Memo'), QLabel(row.description)) form.add_row(_('Date Created'), QLabel(format_time(pr.creation_timestamp, _("Unknown")))) form.add_row(_('Date Received'), QLabel(format_time(row.date_created, _("Unknown")))) if row.date_expires: form.add_row(_('Date Expires'), QLabel(format_time(row.date_expires, _("Unknown")))) vbox.addWidget(form) self._table = table = ButtonsTableWidget() table.setSelectionBehavior(QAbstractItemView.SelectRows) table.setSelectionMode(QAbstractItemView.SingleSelection) vh = table.verticalHeader() vh.setSectionResizeMode(QHeaderView.ResizeToContents) vh.hide() table.setColumnCount(3) table.setContextMenuPolicy(Qt.CustomContextMenu) table.customContextMenuRequested.connect(self._on_table_menu) table.setHorizontalHeaderLabels(self._table_column_names) table.setRowCount(len(pr.outputs)) # table.addButton("icons8-copy-to-clipboard-32.png", f, # _("Copy all listed destinations to the clipboard")) # table.addButton("icons8-save-as-32-windows.png", f, # _("Save the listed destinations to a file")) hh = table.horizontalHeader() hh.setStretchLastSection(True) for row, output in enumerate(pr.outputs): label = QLabel( app_state.format_amount(output.amount) + " " + app_state.base_unit()) table.setCellWidget(row, 0, label) table.setCellWidget(row, 1, QLabel(output.description)) kind = classify_output_script(output.script, Net.COIN) text = script_to_display_text(output.script, kind) table.setCellWidget(row, 2, QLabel(text)) vbox.addWidget(table, 1) def do_export(): fn = self._main_window.getSaveFileName(_("Export invoice to file"), "*.bip270.json") if not fn: return with open(fn, 'w') as f: data = f.write(row.invoice_data) self._main_window.show_message(_('Invoice saved as' + ' ' + fn)) exportButton = EnterButton(_('Export'), do_export) def do_delete(): if self.question( _('Are you sure you want to delete this invoice?'), title=_("Delete invoice"), icon=QMessageBox.Warning): self._main_window._send_view._invoice_list._delete_invoice( row.invoice_id) self.close() deleteButton = EnterButton(_('Delete'), do_delete) vbox.addLayout(Buttons(exportButton, deleteButton, CloseButton(self)))
def update(self) -> None: base_unit = app_state.base_unit() format_amount = app_state.format_amount tx_info = self._get_tx_info(self.tx) tx_info_fee = tx_info.fee self.broadcast_button.setEnabled(tx_info.can_broadcast) if self._main_window.network is None: self.broadcast_button.setEnabled(False) self.broadcast_button.setToolTip( _('You are using ElectrumSV in offline mode; restart ' 'ElectrumSV if you want to get connected')) can_sign = not self.tx.is_complete() and self._account.can_sign( self.tx) self.sign_button.setEnabled(can_sign) self._tx_hash = tx_info.hash tx_id = hash_to_hex_str(tx_info.hash) self.tx_hash_e.setText(tx_id) if tx_info_fee is None: try: # Try and compute fee. We don't always have 'value' in all the inputs though. :/ tx_info_fee = self.tx.get_fee() except TypeError: # At least one of the XTxInputs does not have an attached value. pass else: if tx_info_fee < 0: tx_info_fee = None if self.tx.description is None: self.tx_desc.hide() else: self.tx_desc.setText(self.tx.description) self.tx_desc.show() self.status_label.setText(tx_info.status) if tx_info.timestamp: time_str = datetime.datetime.fromtimestamp( tx_info.timestamp).isoformat(' ')[:-3] self.date_label.setText(time_str) self.date_label.show() else: self.date_label.hide() if tx_info.amount is None: amount_str = _("Unknown") elif math.isclose(tx_info.amount, 0, abs_tol=1e-9): amount_str = "No external payment" elif tx_info.amount > 0: amount_str = _("Received") + " " + format_amount( tx_info.amount) + " " + base_unit else: amount_str = _("Sent") + " " + format_amount( -tx_info.amount) + " " + base_unit self.amount_label.setText(amount_str) size = self.tx.size() self.size_label.setText('%d bytes' % size) if tx_info_fee is not None: fee_amount = '{} {}'.format(format_amount(tx_info_fee), base_unit) else: fee_amount = _('Unknown') fee_str = '{}'.format(fee_amount) if tx_info_fee is not None: fee_str += ' ({}) '.format( self._main_window.format_fee_rate(tx_info_fee / size * 1000)) self.fee_label.setText(fee_str) # Cosigner button visible = app_state.app.cosigner_pool.show_send_to_cosigner_button( self._main_window, self._account, self.tx) self.cosigner_button.setVisible(visible)