commit 541257be34af2c8f55cd99eaf9f25e48dc0d41ca
parent ed4db10943caaa2e4197ed5f823a7c05043dd05c
Author: ThomasV <thomasv@electrum.org>
Date: Thu, 28 Jan 2016 13:28:11 +0100
Merge pull request #1647 from akshayaurora/test_startup
kivy:Improve startup speed
Diffstat:
16 files changed, 817 insertions(+), 64 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -14,3 +14,5 @@ locale/
packages
env/
.tox/
+.buildozer/
+bin/
diff --git a/electrum b/electrum
@@ -31,31 +31,32 @@ if is_local or is_android:
elif is_bundle and sys.platform=='darwin':
sys.path.insert(0, os.getcwd() + "/lib/python2.7/packages")
-# pure-python dependencies need to be imported here for pyinstaller
-try:
- import dns
- import aes
- import ecdsa
- import requests
- import six
- import qrcode
- import pbkdf2
- import google.protobuf
-except ImportError as e:
- sys.exit("Error: %s. Try 'sudo pip install <module-name>'"%e.message)
-
-# the following imports are for pyinstaller
-from google.protobuf import descriptor
-from google.protobuf import message
-from google.protobuf import reflection
-from google.protobuf import descriptor_pb2
-
-
-# check that we have the correct version of ecdsa
-try:
- from ecdsa.ecdsa import curve_secp256k1, generator_secp256k1
-except Exception:
- sys.exit("cannot import ecdsa.curve_secp256k1. You probably need to upgrade ecdsa.\nTry: sudo pip install --upgrade ecdsa")
+if not is_android:
+ # pure-python dependencies need to be imported here for pyinstaller
+ try:
+ import dns
+ import aes
+ import ecdsa
+ import requests
+ import six
+ import qrcode
+ import pbkdf2
+ import google.protobuf
+ except ImportError as e:
+ sys.exit("Error: %s. Try 'sudo pip install <module-name>'"%e.message)
+
+ # the following imports are for pyinstaller
+ from google.protobuf import descriptor
+ from google.protobuf import message
+ from google.protobuf import reflection
+ from google.protobuf import descriptor_pb2
+
+
+ # check that we have the correct version of ecdsa
+ try:
+ from ecdsa.ecdsa import curve_secp256k1, generator_secp256k1
+ except Exception:
+ sys.exit("cannot import ecdsa.curve_secp256k1. You probably need to upgrade ecdsa.\nTry: sudo pip install --upgrade ecdsa")
# load local module as electrum
diff --git a/electrum-env b/electrum-env
@@ -10,11 +10,11 @@
# your package manager.
if [ -e ./env/bin/activate ]; then
- source ./env/bin/activate
+ source ./env/bin/activate
else
- virtualenv env
- source ./env/bin/activate
- python setup.py install
+ virtualenv env
+ source ./env/bin/activate
+ python setup.py install
fi
export PYTHONPATH="/usr/local/lib/python2.7/site-packages:$PYTHONPATH"
diff --git a/gui/kivy/__init__.py b/gui/kivy/__init__.py
@@ -19,6 +19,9 @@
# Kivy GUI
import sys
+import os
+os.environ['KIVY_DATA_DIR'] = os.path.abspath(os.path.dirname(__file__)) + '/data/'
+
try:
sys.argv = ['']
import kivy
diff --git a/gui/kivy/data/glsl/default.fs b/gui/kivy/data/glsl/default.fs
@@ -0,0 +1,4 @@
+$HEADER$
+void main (void){
+ gl_FragColor = frag_color * texture2D(texture0, tex_coord0);
+}
diff --git a/gui/kivy/data/glsl/default.png b/gui/kivy/data/glsl/default.png
Binary files differ.
diff --git a/gui/kivy/data/glsl/default.vs b/gui/kivy/data/glsl/default.vs
@@ -0,0 +1,6 @@
+$HEADER$
+void main (void) {
+ frag_color = color * vec4(1.0, 1.0, 1.0, opacity);
+ tex_coord0 = vTexCoords0;
+ gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0);
+}
diff --git a/gui/kivy/data/glsl/header.fs b/gui/kivy/data/glsl/header.fs
@@ -0,0 +1,10 @@
+#ifdef GL_ES
+ precision highp float;
+#endif
+
+/* Outputs from the vertex shader */
+varying vec4 frag_color;
+varying vec2 tex_coord0;
+
+/* uniform texture samplers */
+uniform sampler2D texture0;
diff --git a/gui/kivy/data/glsl/header.vs b/gui/kivy/data/glsl/header.vs
@@ -0,0 +1,17 @@
+#ifdef GL_ES
+ precision highp float;
+#endif
+
+/* Outputs to the fragment shader */
+varying vec4 frag_color;
+varying vec2 tex_coord0;
+
+/* vertex attributes */
+attribute vec2 vPosition;
+attribute vec2 vTexCoords0;
+
+/* uniform variables */
+uniform mat4 modelview_mat;
+uniform mat4 projection_mat;
+uniform vec4 color;
+uniform float opacity;
diff --git a/gui/kivy/data/images/defaulttheme-0.png b/gui/kivy/data/images/defaulttheme-0.png
Binary files differ.
diff --git a/gui/kivy/data/images/defaulttheme.atlas b/gui/kivy/data/images/defaulttheme.atlas
@@ -0,0 +1 @@
+{"defaulttheme-0.png": {"progressbar_background": [391, 227, 24, 24], "tab_btn_disabled": [264, 137, 32, 32], "tab_btn_pressed": [366, 137, 32, 32], "image-missing": [152, 171, 48, 48], "splitter_h": [174, 123, 32, 7], "splitter_down": [501, 253, 7, 32], "splitter_disabled_down": [503, 291, 7, 32], "vkeyboard_key_down": [468, 137, 32, 32], "vkeyboard_disabled_key_down": [400, 137, 32, 32], "selector_right": [248, 223, 55, 62], "player-background": [2, 287, 103, 103], "selector_middle": [191, 223, 55, 62], "spinner": [235, 82, 29, 37], "tab_btn_disabled_pressed": [298, 137, 32, 32], "switch-button_disabled": [277, 291, 43, 32], "textinput_disabled_active": [372, 326, 64, 64], "splitter_grip": [36, 50, 12, 26], "vkeyboard_key_normal": [2, 44, 32, 32], "button_disabled": [80, 82, 29, 37], "media-playback-stop": [302, 171, 48, 48], "splitter": [501, 87, 7, 32], "splitter_down_h": [140, 123, 32, 7], "sliderh_background_disabled": [72, 132, 41, 37], "modalview-background": [464, 456, 45, 54], "button": [142, 82, 29, 37], "splitter_disabled": [502, 137, 7, 32], "checkbox_radio_disabled_on": [433, 87, 32, 32], "slider_cursor": [402, 171, 48, 48], "vkeyboard_disabled_background": [68, 221, 64, 64], "checkbox_disabled_on": [297, 87, 32, 32], "sliderv_background_disabled": [2, 78, 37, 41], "button_disabled_pressed": [111, 82, 29, 37], "audio-volume-muted": [102, 171, 48, 48], "close": [417, 231, 20, 20], "action_group_disabled": [452, 171, 33, 48], "vkeyboard_background": [2, 221, 64, 64], "checkbox_off": [331, 87, 32, 32], "tab_disabled": [305, 253, 96, 32], "sliderh_background": [115, 132, 41, 37], "switch-button": [322, 291, 43, 32], "tree_closed": [439, 231, 20, 20], "bubble_btn_pressed": [435, 291, 32, 32], "selector_left": [134, 223, 55, 62], "filechooser_file": [174, 326, 64, 64], "checkbox_radio_disabled_off": [399, 87, 32, 32], "checkbox_radio_on": [196, 137, 32, 32], "checkbox_on": [365, 87, 32, 32], "button_pressed": [173, 82, 29, 37], "audio-volume-high": [464, 406, 48, 48], "audio-volume-low": [2, 171, 48, 48], "progressbar": [305, 227, 32, 24], "previous_normal": [487, 187, 19, 32], "separator": [504, 342, 5, 48], "filechooser_folder": [240, 326, 64, 64], "checkbox_radio_off": [467, 87, 32, 32], "textinput_active": [306, 326, 64, 64], "textinput": [438, 326, 64, 64], "player-play-overlay": [122, 395, 117, 115], "media-playback-pause": [202, 171, 48, 48], "sliderv_background": [41, 78, 37, 41], "ring": [354, 402, 108, 108], "bubble_arrow": [487, 175, 16, 10], "slider_cursor_disabled": [352, 171, 48, 48], "checkbox_disabled_off": [469, 291, 32, 32], "action_group_down": [2, 121, 33, 48], "spinner_disabled": [204, 82, 29, 37], "splitter_disabled_h": [106, 123, 32, 7], "bubble": [107, 325, 65, 65], "media-playback-start": [252, 171, 48, 48], "vkeyboard_disabled_key_normal": [434, 137, 32, 32], "overflow": [230, 137, 32, 32], "tree_opened": [461, 231, 20, 20], "action_item": [339, 227, 24, 24], "bubble_btn": [401, 291, 32, 32], "audio-volume-medium": [52, 171, 48, 48], "action_group": [37, 121, 33, 48], "spinner_pressed": [266, 82, 29, 37], "filechooser_selected": [2, 392, 118, 118], "tab": [403, 253, 96, 32], "action_bar": [158, 133, 36, 36], "action_view": [365, 227, 24, 24], "tab_btn": [332, 137, 32, 32], "switch-background": [192, 291, 83, 32], "splitter_disabled_down_h": [72, 123, 32, 7], "action_item_down": [367, 291, 32, 32], "switch-background_disabled": [107, 291, 83, 32], "textinput_disabled": [241, 399, 111, 111], "splitter_grip_h": [483, 239, 26, 12]}}+
\ No newline at end of file
diff --git a/gui/kivy/data/logo/kivy-icon-32.png b/gui/kivy/data/logo/kivy-icon-32.png
Binary files differ.
diff --git a/gui/kivy/data/style.kv b/gui/kivy/data/style.kv
@@ -0,0 +1,736 @@
+#:kivy 1.0
+
+<Label>:
+ canvas:
+ Color:
+ rgba: self.disabled_color if self.disabled else (self.color if not self.markup else (1, 1, 1, 1))
+ Rectangle:
+ texture: self.texture
+ size: self.texture_size
+ pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)
+
+<-Button,-ToggleButton>:
+ state_image: self.background_normal if self.state == 'normal' else self.background_down
+ disabled_image: self.background_disabled_normal if self.state == 'normal' else self.background_disabled_down
+ canvas:
+ Color:
+ rgba: self.background_color
+ BorderImage:
+ border: self.border
+ pos: self.pos
+ size: self.size
+ source: self.disabled_image if self.disabled else self.state_image
+ Color:
+ rgba: self.disabled_color if self.disabled else self.color
+ Rectangle:
+ texture: self.texture
+ size: self.texture_size
+ pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)
+
+<BubbleContent>
+ opacity: .7 if self.disabled else 1
+ rows: 1
+ canvas:
+ Color:
+ rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)
+ BorderImage:
+ border: self.parent.border if self.parent else (16, 16, 16, 16)
+ texture: root.parent._bk_img.texture if root.parent else None
+ size: self.size
+ pos: self.pos
+
+<BubbleButton>:
+ background_normal: 'atlas://data/images/defaulttheme/bubble_btn'
+ background_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'
+ background_disabled_normal: 'atlas://data/images/defaulttheme/bubble_btn'
+ background_disabled_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'
+ border: (0, 0, 0, 0)
+
+<RelativeLayout>:
+ canvas.before:
+ PushMatrix
+ Translate:
+ xy: self.pos
+ canvas.after:
+ PopMatrix
+
+<Image,AsyncImage>:
+ canvas:
+ Color:
+ rgba: self.color
+ Rectangle:
+ texture: self.texture
+ size: self.norm_image_size
+ pos: self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2.
+
+<TabbedPanelContent>
+ rows: 1
+ padding: 3
+ canvas:
+ Color:
+ rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)
+ BorderImage:
+ border: self.parent.border if self.parent else (16, 16, 16, 16)
+ source: (root.parent.background_disabled_image if self.disabled else root.parent.background_image) if root.parent else None
+ size: self.size
+ pos: self.pos
+
+<TabbedPanelStrip>
+ rows: 1
+
+<StripLayout>
+ padding: '2dp', '2dp', '2dp', '2dp'
+ canvas.before:
+ BorderImage:
+ pos: self.pos
+ size: self.size
+ border: root.border
+ source: root.background_image
+
+<TabbedPanelHeader>:
+ halign: 'center'
+ valign: 'middle'
+ background_normal: 'atlas://data/images/defaulttheme/tab_btn'
+ background_disabled_normal: 'atlas://data/images/defaulttheme/tab_btn_disabled'
+ background_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'
+ background_disabled_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'
+ border: (8, 8, 8, 8)
+ font_size: '15sp'
+
+<Selector>
+ allow_stretch: True
+
+<TextInput>:
+ canvas.before:
+ Color:
+ rgba: self.background_color
+ BorderImage:
+ border: self.border
+ pos: self.pos
+ size: self.size
+ source: (self.background_disabled_active if self.disabled else self.background_active) if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
+ Color:
+ rgba: (self.cursor_color if self.focus and not self.cursor_blink else (0, 0, 0, 0))
+ Rectangle:
+ pos: [int(x) for x in self.cursor_pos]
+ size: 1, -self.line_height
+ Color:
+ rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text and not self.focus else self.foreground_color)
+
+<TextInputCutCopyPaste>:
+ but_cut: cut.__self__
+ but_copy: copy.__self__
+ but_paste: paste.__self__
+ but_selectall: selectall.__self__
+
+ size_hint: None, None
+ size: '150sp', '50sp'
+ BubbleButton:
+ id: cut
+ text: 'Cut'
+ on_release: root.do('cut')
+ BubbleButton:
+ id: copy
+ text: 'Copy'
+ on_release: root.do('copy')
+ BubbleButton:
+ id: paste
+ text: 'Paste'
+ on_release: root.do('paste')
+ BubbleButton:
+ id: selectall
+ text: 'Select All'
+ on_release: root.do('selectall')
+
+<CodeInput>:
+ font_name: 'data/fonts/RobotoMono-Regular.ttf'
+
+
+<TreeViewNode>:
+ canvas.before:
+ Color:
+ rgba: self.color_selected if self.is_selected else self.odd_color if self.odd else self.even_color
+ Rectangle:
+ pos: [self.parent.x, self.y] if self.parent else [0, 0]
+ size: [self.parent.width, self.height] if self.parent else [1, 1]
+ Color:
+ rgba: 1, 1, 1, int(not self.is_leaf)
+ Rectangle:
+ source: 'atlas://data/images/defaulttheme/tree_%s' % ('opened' if self.is_open else 'closed')
+ size: 16, 16
+ pos: self.x - 20, self.center_y - 8
+ canvas.after:
+ Color:
+ rgba: .5, .5, .5, .2
+ Line:
+ points: [self.parent.x, self.y, self.parent.right, self.y] if self.parent else []
+
+
+<TreeViewLabel>:
+ width: self.texture_size[0]
+ height: max(self.texture_size[1] + dp(10), dp(24))
+ text_size: self.width, None
+
+
+<StencilView>:
+ canvas.before:
+ StencilPush
+ Rectangle:
+ pos: self.pos
+ size: self.size
+ StencilUse
+
+ canvas.after:
+ StencilUnUse
+ Rectangle:
+ pos: self.pos
+ size: self.size
+ StencilPop
+
+
+<FileChooserListLayout>:
+ on_entry_added: treeview.add_node(args[1])
+ on_entries_cleared: treeview.root.nodes = []
+ on_subentry_to_entry: not args[2].locked and treeview.add_node(args[1], args[2])
+ on_remove_subentry: args[2].nodes = []
+ BoxLayout:
+ pos: root.pos
+ size: root.size
+ size_hint: None, None
+ orientation: 'vertical'
+ BoxLayout:
+ size_hint_y: None
+ height: 30
+ orientation: 'horizontal'
+ Widget:
+ # Just for spacing
+ width: 10
+ size_hint_x: None
+ Label:
+ text: 'Name'
+ text_size: self.size
+ halign: 'left'
+ bold: True
+ Label:
+ text: 'Size'
+ text_size: self.size
+ size_hint_x: None
+ halign: 'right'
+ bold: True
+ Widget:
+ # Just for spacing
+ width: 10
+ size_hint_x: None
+ ScrollView:
+ id: scrollview
+ do_scroll_x: False
+ Scatter:
+ do_rotation: False
+ do_scale: False
+ do_translation: False
+ size: treeview.size
+ size_hint_y: None
+ TreeView:
+ id: treeview
+ hide_root: True
+ size_hint_y: None
+ width: scrollview.width
+ height: self.minimum_height
+ on_node_expand: root.controller.entry_subselect(args[1])
+ on_node_collapse: root.controller.close_subselection(args[1])
+
+<FileChooserListView>:
+ layout: layout
+ FileChooserListLayout:
+ id: layout
+ controller: root
+
+[FileListEntry@FloatLayout+TreeViewNode]:
+ locked: False
+ entries: []
+ path: ctx.path
+ # FIXME: is_selected is actually a read_only treeview property. In this
+ # case, however, we're doing this because treeview only has single-selection
+ # hardcoded in it. The fix to this would be to update treeview to allow
+ # multiple selection.
+ is_selected: self.path in ctx.controller().selection
+
+ orientation: 'horizontal'
+ size_hint_y: None
+ height: '48dp' if dp(1) > 1 else '24dp'
+ # Don't allow expansion of the ../ node
+ is_leaf: not ctx.isdir or ctx.name.endswith('..' + ctx.sep) or self.locked
+ on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])
+ on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])
+ BoxLayout:
+ pos: root.pos
+ Label:
+ id: filename
+ text_size: self.width, None
+ halign: 'left'
+ shorten: True
+ text: ctx.name
+ Label:
+ text_size: self.width, None
+ size_hint_x: None
+ halign: 'right'
+ text: '{}'.format(ctx.get_nice_size())
+
+
+<FileChooserIconLayout>:
+ on_entry_added: stacklayout.add_widget(args[1])
+ on_entries_cleared: stacklayout.clear_widgets()
+ ScrollView:
+ id: scrollview
+ pos: root.pos
+ size: root.size
+ size_hint: None, None
+ do_scroll_x: False
+ Scatter:
+ do_rotation: False
+ do_scale: False
+ do_translation: False
+ size_hint_y: None
+ height: stacklayout.height
+ StackLayout:
+ id: stacklayout
+ width: scrollview.width
+ size_hint_y: None
+ height: self.minimum_height
+ spacing: '10dp'
+ padding: '10dp'
+
+<FileChooserIconView>:
+ layout: layout
+ FileChooserIconLayout:
+ id: layout
+ controller: root
+
+[FileIconEntry@Widget]:
+ locked: False
+ path: ctx.path
+ selected: self.path in ctx.controller().selection
+ size_hint: None, None
+
+ on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])
+ on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])
+ size: '100dp', '100dp'
+
+ canvas:
+ Color:
+ rgba: 1, 1, 1, 1 if self.selected else 0
+ BorderImage:
+ border: 8, 8, 8, 8
+ pos: root.pos
+ size: root.size
+ source: 'atlas://data/images/defaulttheme/filechooser_selected'
+
+ Image:
+ size: '48dp', '48dp'
+ source: 'atlas://data/images/defaulttheme/filechooser_%s' % ('folder' if ctx.isdir else 'file')
+ pos: root.x + dp(24), root.y + dp(40)
+ Label:
+ text: ctx.name
+ text_size: (root.width, self.height)
+ halign: 'center'
+ shorten: True
+ size: '100dp', '16dp'
+ pos: root.x, root.y + dp(16)
+
+ Label:
+ text: '{}'.format(ctx.get_nice_size())
+ font_size: '11sp'
+ color: .8, .8, .8, 1
+ size: '100dp', '16sp'
+ pos: root.pos
+ halign: 'center'
+
+<FileChooserProgress>:
+ pos_hint: {'x': 0, 'y': 0}
+ canvas:
+ Color:
+ rgba: 0, 0, 0, .8
+ Rectangle:
+ pos: self.pos
+ size: self.size
+ Label:
+ pos_hint: {'x': .2, 'y': .6}
+ size_hint: .6, .2
+ text: 'Opening %s' % root.path
+ FloatLayout:
+ pos_hint: {'x': .2, 'y': .4}
+ size_hint: .6, .2
+ ProgressBar:
+ id: pb
+ pos_hint: {'x': 0, 'center_y': .5}
+ max: root.total
+ value: root.index
+ Label:
+ pos_hint: {'x': 0}
+ text: '%d / %d' % (root.index, root.total)
+ size_hint_y: None
+ height: self.texture_size[1]
+ y: pb.center_y - self.height - 8
+ font_size: '13sp'
+ color: (.8, .8, .8, .8)
+
+ AnchorLayout:
+ pos_hint: {'x': .2, 'y': .2}
+ size_hint: .6, .2
+
+ Button:
+ text: 'Cancel'
+ size_hint: None, None
+ size: 150, 44
+ on_release: root.cancel()
+
+
+
+# Switch widget
+<Switch>:
+ active_norm_pos: max(0., min(1., (int(self.active) + self.touch_distance / sp(41))))
+ canvas:
+ Color:
+ rgb: 1, 1, 1
+ Rectangle:
+ source: 'atlas://data/images/defaulttheme/switch-background{}'.format('_disabled' if self.disabled else '')
+ size: sp(83), sp(32)
+ pos: int(self.center_x - sp(41)), int(self.center_y - sp(16))
+ Rectangle:
+ source: 'atlas://data/images/defaulttheme/switch-button{}'.format('_disabled' if self.disabled else '')
+ size: sp(43), sp(32)
+ pos: int(self.center_x - sp(41) + self.active_norm_pos * sp(41)), int(self.center_y - sp(16))
+
+
+# ModalView widget
+<ModalView>:
+ canvas:
+ Color:
+ rgba: root.background_color[:3] + [root.background_color[-1] * self._anim_alpha]
+ Rectangle:
+ size: self._window.size if self._window else (0, 0)
+
+ Color:
+ rgb: 1, 1, 1
+ BorderImage:
+ source: root.background
+ border: root.border
+ pos: self.pos
+ size: self.size
+
+
+# Popup widget
+<Popup>:
+ _container: container
+ GridLayout:
+ padding: '12dp'
+ cols: 1
+ size_hint: None, None
+ pos: root.pos
+ size: root.size
+
+ Label:
+ text: root.title
+ color: root.title_color
+ size_hint_y: None
+ height: self.texture_size[1] + dp(16)
+ text_size: self.width - dp(16), None
+ font_size: root.title_size
+ font_name: root.title_font
+ halign: root.title_align
+
+ Widget:
+ size_hint_y: None
+ height: dp(4)
+ canvas:
+ Color:
+ rgba: root.separator_color
+ Rectangle:
+ pos: self.x, self.y + root.separator_height / 2.
+ size: self.width, root.separator_height
+
+ BoxLayout:
+ id: container
+
+# =============================================================================
+# Spinner widget
+# =============================================================================
+
+<SpinnerOption>:
+ size_hint_y: None
+ height: '48dp'
+
+<Spinner>:
+ background_normal: 'atlas://data/images/defaulttheme/spinner'
+ background_disabled_normal: 'atlas://data/images/defaulttheme/spinner_disabled'
+ background_down: 'atlas://data/images/defaulttheme/spinner_pressed'
+
+# =============================================================================
+# ActionBar widget
+# =============================================================================
+
+<ActionBar>:
+ height: '48dp'
+ size_hint_y: None
+ spacing: '4dp'
+ canvas:
+ Color:
+ rgba: self.background_color
+ BorderImage:
+ border: root.border
+ pos: self.pos
+ size: self.size
+ source: self.background_image
+
+<ActionView>:
+ orientation: 'horizontal'
+ canvas:
+ Color:
+ rgba: self.background_color
+ BorderImage:
+ pos: self.pos
+ size: self.size
+ source: self.background_image
+
+<ActionSeparator>:
+ size_hint_x: None
+ minimum_width: '2sp'
+ width: self.minimum_width
+ canvas:
+ Rectangle:
+ pos: self.x, self.y + sp(4)
+ size: self.width, self.height - sp(8)
+ source: self.background_image
+
+<ActionButton,ActionToggleButton>:
+ background_normal: 'atlas://data/images/defaulttheme/' + ('action_bar' if self.inside_group else 'action_item')
+ background_down: 'atlas://data/images/defaulttheme/action_item_down'
+ size_hint_x: None if not root.inside_group else 1
+ width: [dp(48) if (root.icon and not root.inside_group) else max(dp(48), (self.texture_size[0] + dp(32))), self.size_hint_x][0]
+ color: self.color[:3] + [0 if (root.icon and not root.inside_group) else 1]
+
+ Image:
+ allow_stretch: True
+ opacity: 1 if (root.icon and not root.inside_group) else 0
+ source: root.icon
+ mipmap: root.mipmap
+ pos: root.x + dp(4), root.y + dp(4)
+ size: root.width - dp(8), root.height - sp(8)
+
+<ActionLabel>:
+ size_hint_x: None if not root.inside_group else 1
+ width: self.texture_size[0] + dp(32)
+
+<ActionGroup>:
+ size_hint_x: None
+ width: self.texture_size[0] + dp(32)
+
+<ActionCheck>:
+ background_normal: 'atlas://data/images/defaulttheme/action_bar' if self.inside_group else 'atlas://data/images/defaulttheme/action_item'
+
+<ActionPreviousImage@Image>:
+ temp_width: 0
+ temp_height: 0
+
+<ActionPreviousButton@Button>:
+ background_normal: 'atlas://data/images/defaulttheme/action_item'
+ background_down: 'atlas://data/images/defaulttheme/action_item_down'
+
+<ActionPrevious>:
+ size_hint_x: 1
+ minimum_width: layout.minimum_width + min(sp(100), title.width)
+ important: True
+ GridLayout:
+ id: layout
+ rows: 1
+ pos: root.pos
+ size_hint_x: None
+ width: self.minimum_width
+ ActionPreviousButton:
+ on_press: root.dispatch('on_press')
+ on_release: root.dispatch('on_release')
+ size_hint_x: None
+ width: prevlayout.width
+ GridLayout:
+ id: prevlayout
+ rows: 1
+ width: self.minimum_width
+ height: self.parent.height
+ pos: self.parent.pos
+ ActionPreviousImage:
+ id: prev_icon_image
+ source: root.previous_image
+ opacity: 1 if root.with_previous else 0
+ allow_stretch: True
+ size_hint_x: None
+ temp_width: root.previous_image_width or dp(prev_icon_image.texture_size[0])
+ temp_height: root.previous_image_height or dp(prev_icon_image.texture_size[1])
+ width:
+ (self.temp_width if self.temp_height <= self.height else \
+ self.temp_width * (self.height / self.temp_height)) \
+ if self.texture else dp(8)
+ mipmap: root.mipmap
+ ActionPreviousImage:
+ id: app_icon_image
+ source: root.app_icon
+ allow_stretch: True
+ size_hint_x: None
+ temp_width: root.app_icon_width or dp(app_icon_image.texture_size[0])
+ temp_height: root.app_icon_height or dp(app_icon_image.texture_size[1])
+ width:
+ (self.temp_width if self.temp_height <= self.height else \
+ self.temp_width * (self.height / self.temp_height)) \
+ if self.texture else dp(8)
+ mipmap: root.mipmap
+ Widget:
+ size_hint_x: None
+ width: '5sp'
+ Label:
+ id: title
+ text: root.title
+ text_size: self.size
+ color: root.color
+ shorten: True
+ shorten_from: 'right'
+ halign: 'left'
+ valign: 'middle'
+
+<ActionGroup>:
+ background_normal: 'atlas://data/images/defaulttheme/action_group'
+ background_down: 'atlas://data/images/defaulttheme/action_group_down'
+ background_disabled_normal: 'atlas://data/images/defaulttheme/action_group_disabled'
+ border: 30, 30, 3, 3
+ ActionSeparator:
+ pos: root.pos
+ size: root.separator_width, root.height
+ opacity: 1 if root.use_separator else 0
+ background_image: root.separator_image if root.use_separator else 'action_view'
+
+<ActionOverflow>:
+ border: 3, 3, 3, 3
+ background_normal: 'atlas://data/images/defaulttheme/action_item'
+ background_down: 'atlas://data/images/defaulttheme/action_item_down'
+ background_disabled_normal: 'atlas://data/images/defaulttheme/button_disabled'
+ size_hint_x: None
+ minimum_width: '48sp'
+ width: self.texture_size[0] if self.texture else self.minimum_width
+ canvas.after:
+ Color:
+ rgb: 1, 1, 1
+ Rectangle:
+ pos: root.center_x - sp(16), root.center_y - sp(16)
+ size: sp(32), sp(32)
+ source: root.overflow_image
+
+<ActionDropDown>:
+ auto_width: False
+
+
+# =============================================================================
+# Accordion widget
+# =============================================================================
+
+[AccordionItemTitle@Label]:
+ text: ctx.title
+ normal_background: ctx.item.background_normal if ctx.item.collapse else ctx.item.background_selected
+ disabled_background: ctx.item.background_disabled_normal if ctx.item.collapse else ctx.item.background_disabled_selected
+ canvas.before:
+ Color:
+ rgba: self.disabled_color if self.disabled else self.color
+ BorderImage:
+ source: self.disabled_background if self.disabled else self.normal_background
+ pos: self.pos
+ size: self.size
+ PushMatrix
+ Translate:
+ xy: self.center_x, self.center_y
+ Rotate:
+ angle: 90 if ctx.item.orientation == 'horizontal' else 0
+ axis: 0, 0, 1
+ Translate:
+ xy: -self.center_x, -self.center_y
+ canvas.after:
+ PopMatrix
+
+
+<AccordionItem>:
+ container: container
+ container_title: container_title
+
+ BoxLayout:
+ orientation: root.orientation
+ pos: root.pos
+ BoxLayout:
+ size_hint_x: None if root.orientation == 'horizontal' else 1
+ size_hint_y: None if root.orientation == 'vertical' else 1
+ width: root.min_space if root.orientation == 'horizontal' else 100
+ height: root.min_space if root.orientation == 'vertical' else 100
+ id: container_title
+
+ StencilView:
+ id: sv
+
+ BoxLayout:
+ id: container
+ pos: sv.pos
+ size: root.content_size
+
+
+<ScrollView>:
+ canvas.after:
+ Color:
+ rgba: self._bar_color if (self.do_scroll_y and self.viewport_size[1] > self.height) else [0, 0, 0, 0]
+ Rectangle:
+ pos: (self.right - self.bar_width - self.bar_margin) if self.bar_pos_y == 'right' else (self.x + self.bar_margin), self.y + self.height * self.vbar[0]
+ size: min(self.bar_width, self.width), self.height * self.vbar[1]
+ Color:
+ rgba: self._bar_color if (self.do_scroll_x and self.viewport_size[0] > self.width) else [0, 0, 0, 0]
+ Rectangle:
+ pos: self.x + self.width * self.hbar[0], (self.y + self.bar_margin) if self.bar_pos_x == 'bottom' else (self.top - self.bar_margin - self.bar_width)
+ size: self.width * self.hbar[1], min(self.bar_width, self.height)
+
+
+<CheckBox>:
+ _checkbox_state_image:
+ self.background_checkbox_down \
+ if self.active else self.background_checkbox_normal
+ _checkbox_disabled_image:
+ self.background_checkbox_disabled_down \
+ if self.active else self.background_checkbox_disabled_normal
+ _radio_state_image:
+ self.background_radio_down \
+ if self.active else self.background_radio_normal
+ _radio_disabled_image:
+ self.background_radio_disabled_down \
+ if self.active else self.background_radio_disabled_normal
+ _checkbox_image:
+ self._checkbox_disabled_image \
+ if self.disabled else self._checkbox_state_image
+ _radio_image:
+ self._radio_disabled_image \
+ if self.disabled else self._radio_state_image
+ canvas:
+ Color:
+ rgb: 1, 1, 1
+ Rectangle:
+ source: self._radio_image if self.group else self._checkbox_image
+ size: sp(32), sp(32)
+ pos: int(self.center_x - sp(16)), int(self.center_y - sp(16))
+
+# =============================================================================
+# Screen Manager
+# =============================================================================
+
+<ScreenManager>:
+ canvas.before:
+ StencilPush
+ Rectangle:
+ pos: self.pos
+ size: self.size
+ StencilUse
+ canvas.after:
+ StencilUnUse
+ Rectangle:
+ pos: self.pos
+ size: self.size
+ StencilPop
diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
@@ -193,7 +193,6 @@
<CleanHeader@TabbedPanelHeader>
- #border: 0, 0, 16, 0
border: 0, 0, 16, 0
markup: False
text_size: self.size
@@ -203,13 +202,6 @@
font_size: '12.5sp'
background_normal: 'atlas://gui/kivy/theming/light/tab_btn'
background_down: 'atlas://gui/kivy/theming/light/tab_btn_pressed'
- #canvas.before:
- # Color:
- # rgba: .6, .6, .6, .7
- # Rectangle:
- # size: self.size
- # pos: self.x + 1, self.y - 1
- # texture: self.texture
<ColoredLabel@Label>:
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -285,6 +285,7 @@ class ElectrumWindow(App):
def on_start(self):
''' This is the start point of the kivy ui
'''
+ import time; print 'python time to on_start:', time.clock(), '<<<<<<<<<'
Logger.info("dpi: {} {}".format(metrics.dpi, metrics.dpi_rounded))
win = Window
win.bind(size=self.on_size,
@@ -300,10 +301,7 @@ class ElectrumWindow(App):
'data/fonts/Roboto-Bold.ttf',
'data/fonts/Roboto-Bold.ttf')
- if platform == 'android':
- # bind to keyboard height so we can get the window contents to
- # behave the way we want when the keyboard appears.
- win.bind(keyboard_height=self.on_keyboard_height)
+ win.softinput_mode = 'below_target'
self.on_size(win, win.size)
self.init_ui()
@@ -338,22 +336,6 @@ class ElectrumWindow(App):
if self.wallet:
self.wallet.stop_threads()
- def on_keyboard_height(self, window, height):
- win = window
- active_widg = win.children[0]
- if not issubclass(active_widg.__class__, Factory.Popup):
- try:
- active_widg = self.root.children[0]
- except IndexError:
- return
- try:
- fw = self._focused_widget
- except AttributeError:
- return
- if height > 0 and fw.to_window(*fw.pos)[1] > height:
- return
- Factory.Animation(y=win.keyboard_height, d=.1).start(active_widg)
-
def on_key_down(self, instance, key, keycode, codepoint, modifiers):
if 'ctrl' in modifiers:
# q=24 w=25
diff --git a/gui/kivy/tools/buildozer.spec b/gui/kivy/tools/buildozer.spec
@@ -4,7 +4,7 @@
title = Electrum
# (str) Package name
-package.name = kivy
+package.name = Electrum
# (str) Package domain (needed for android/ios packaging)
package.domain = org.electrum
@@ -13,17 +13,15 @@ package.domain = org.electrum
source.dir = .
# (list) Source files to include (let empty to include all the files)
-source.include_exts = py,png,jpg,kv,atlas,ttf,txt, gif, pem, mo
+source.include_exts = py,png,jpg,kv,atlas,ttf,txt,gif,pem,mo,vs,fs
# (list) Source files to exclude (let empty to not exclude anything)
source.exclude_exts = spec
# (list) List of directory to exclude (let empty to not exclude anything)
-source.exclude_dirs = bin, build, contrib, gui/android, gui/gtk, gui/qt, gui/kivy/tools
-
-
+source.exclude_dirs = bin, build, dist, contrib, gui/android, gui/qt, gui/kivy/tools
# (list) List of exclusions using pattern matching
-#source.exclude_patterns = license,images/*/*.jpg
+source.exclude_patterns = Makefile,setup*
# (str) Application versioning (method 1)
version.regex = ELECTRUM_VERSION = '(.*)'
@@ -85,7 +83,7 @@ android.private_storage = True
# down the build process. Allows wildcards matching, for example:
# OUYA-ODK/libs/*.jar
#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
-android.add_jars = lib/android/zbar.jar
+#android.add_jars = lib/android/zbar.jar
# (list) List of Java files to add to the android project (can be java or a
# directory containing the files)