Merge pull request #533 from mwhudson/app-specific-uis

allow the application to have a widget in the bottom right
This commit is contained in:
Dimitri John Ledkov 2019-09-05 14:36:12 +01:00 committed by GitHub
commit 25ed1e281f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 87 additions and 19 deletions

View File

@ -21,7 +21,6 @@ from subiquitycore.log import setup_logger
from subiquitycore import __version__ as VERSION from subiquitycore import __version__ as VERSION
from console_conf.core import ConsoleConf from console_conf.core import ConsoleConf
from subiquitycore.core import ApplicationError from subiquitycore.core import ApplicationError
from subiquitycore.ui.frame import SubiquityUI
from subiquitycore.utils import environment_check from subiquitycore.utils import environment_check
@ -88,10 +87,8 @@ def main():
'Check {} for errors.'.format(LOGFILE)) 'Check {} for errors.'.format(LOGFILE))
return 1 return 1
ui = SubiquityUI()
try: try:
interface = ConsoleConf(ui, opts) interface = ConsoleConf(opts)
except ApplicationError as e: except ApplicationError as e:
logger.exception('Failed to load ConsoleConf interface') logger.exception('Failed to load ConsoleConf interface')
print(e) print(e)

View File

@ -23,7 +23,6 @@ import sys
from subiquitycore.log import setup_logger from subiquitycore.log import setup_logger
from subiquitycore import __version__ as VERSION from subiquitycore import __version__ as VERSION
from subiquitycore.core import ApplicationError from subiquitycore.core import ApplicationError
from subiquitycore.ui.frame import SubiquityUI
from subiquitycore.utils import environment_check from subiquitycore.utils import environment_check
from subiquity.core import Subiquity from subiquity.core import Subiquity
@ -145,10 +144,8 @@ def main():
opts.answers.close() opts.answers.close()
opts.answers = None opts.answers = None
ui = SubiquityUI()
try: try:
subiquity_interface = Subiquity(ui, opts, block_log_dir) subiquity_interface = Subiquity(opts, block_log_dir)
except ApplicationError as e: except ApplicationError as e:
logger.exception('Failed to load Subiquity interface') logger.exception('Failed to load Subiquity interface')
print(e) print(e)

View File

@ -24,6 +24,7 @@ from subiquity.snapd import (
FakeSnapdConnection, FakeSnapdConnection,
SnapdConnection, SnapdConnection,
) )
from subiquity.ui.frame import SubiquityUI
log = logging.getLogger('subiquity.core') log = logging.getLogger('subiquity.core')
@ -43,6 +44,9 @@ class Subiquity(Application):
root = os.path.abspath('.subiquity') root = os.path.abspath('.subiquity')
return SubiquityModel(root, self.opts.sources) return SubiquityModel(root, self.opts.sources)
def make_ui(self):
return SubiquityUI(self)
controllers = [ controllers = [
"Welcome", "Welcome",
"Refresh", "Refresh",
@ -59,11 +63,11 @@ class Subiquity(Application):
"InstallProgress", "InstallProgress",
] ]
def __init__(self, ui, opts, block_log_dir): def __init__(self, opts, block_log_dir):
if not opts.bootloader == 'none' and platform.machine() != 's390x': if not opts.bootloader == 'none' and platform.machine() != 's390x':
self.controllers.remove("Zdev") self.controllers.remove("Zdev")
super().__init__(ui, opts) super().__init__(opts)
self.ui.progress_completion += 1 self.ui.progress_completion += 1
self.block_log_dir = block_log_dir self.block_log_dir = block_log_dir
if opts.snaps_from_examples: if opts.snaps_from_examples:

27
subiquity/ui/frame.py Normal file
View File

@ -0,0 +1,27 @@
# Copyright 2019 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.ui.frame import SubiquityCoreUI
log = logging.getLogger('subiquity.ui.frame')
class SubiquityUI(SubiquityCoreUI):
def __init__(self, app):
super().__init__()

View File

@ -29,6 +29,7 @@ import yaml
from subiquitycore.controller import RepeatedController from subiquitycore.controller import RepeatedController
from subiquitycore.signals import Signal from subiquitycore.signals import Signal
from subiquitycore.prober import Prober, ProberException from subiquitycore.prober import Prober, ProberException
from subiquitycore.ui.frame import SubiquityCoreUI
log = logging.getLogger('subiquitycore.core') log = logging.getLogger('subiquitycore.core')
@ -231,7 +232,9 @@ class Application:
# controllers in order, calling the default method on the controller # controllers in order, calling the default method on the controller
# instance. # instance.
def __init__(self, ui, opts): make_ui = SubiquityCoreUI
def __init__(self, opts):
try: try:
prober = Prober(opts) prober = Prober(opts)
except ProberException as e: except ProberException as e:
@ -239,7 +242,7 @@ class Application:
log.exception(err) log.exception(err)
raise ApplicationError(err) raise ApplicationError(err)
self.ui = ui self.ui = self.make_ui()
self.opts = opts self.opts = opts
opts.project = self.project opts.project = self.project
@ -274,7 +277,7 @@ class Application:
if c in opts.screens] if c in opts.screens]
else: else:
self.controllers = self.controllers[:] self.controllers = self.controllers[:]
ui.progress_completion = len(self.controllers) self.ui.progress_completion = len(self.controllers)
self.controller_instances = dict.fromkeys(self.controllers) self.controller_instances = dict.fromkeys(self.controllers)
self.controller_index = -1 self.controller_index = -1

View File

@ -13,15 +13,22 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from urwid import ( from urwid import (
Text, Text,
ProgressBar, ProgressBar,
) )
from subiquitycore.ui.container import ( from subiquitycore.ui.container import (
Columns,
Pile, Pile,
WidgetWrap, WidgetWrap,
) )
from subiquitycore.ui.utils import Padding, Color from subiquitycore.ui.utils import Padding, Color
from subiquitycore.ui.width import widget_width
log = logging.getLogger('subiquitycore.ui.anchors')
class Header(WidgetWrap): class Header(WidgetWrap):
@ -48,6 +55,36 @@ class StepsProgressBar(ProgressBar):
return "{} / {}".format(self.current, self.done) return "{} / {}".format(self.current, self.done)
class MyColumns(Columns):
# The idea is to render output like this:
#
# message [ help ]
# [ lpad ][ middle ][ rpad ][ right ]
#
# The constraints are:
#
# 1. lpad + rpad + right + message = maxcol
#
# 2. lpad and rpad are at least 1
#
# 3. right is fixed
#
# 4. if possible, lpad = rpad + right and middle is 79% of maxcol
# or 76, whichever is greater.
def column_widths(self, size, focus=False):
maxcol = size[0]
right = widget_width(self.contents[3][0])
center = max(79*maxcol//100, 76)
lpad = (maxcol - center)//2
rpad = lpad - right
if rpad < 1:
rpad = 1
middle = maxcol - (lpad + rpad + right)
return [lpad, middle, rpad, right]
class Footer(WidgetWrap): class Footer(WidgetWrap):
""" Footer widget """ Footer widget
@ -55,10 +92,9 @@ class Footer(WidgetWrap):
""" """
def __init__(self, message, current, complete): def __init__(self, message, right_icon, current, complete):
if isinstance(message, str): if isinstance(message, str):
message = Text(message) message = Text(message)
message = Padding.center_79(message, min_width=76)
progress_bar = Padding.center_60( progress_bar = Padding.center_60(
StepsProgressBar(normal='progress_incomplete', StepsProgressBar(normal='progress_incomplete',
complete='progress_complete', complete='progress_complete',
@ -66,6 +102,6 @@ class Footer(WidgetWrap):
status = [ status = [
progress_bar, progress_bar,
Padding.line_break(""), Padding.line_break(""),
message, MyColumns([Text(""), message, Text(""), right_icon]),
] ]
super().__init__(Color.frame_footer(Pile(status))) super().__init__(Color.frame_footer(Pile(status)))

View File

@ -32,11 +32,13 @@ from subiquitycore.ui.utils import Color
log = logging.getLogger('subiquitycore.ui.frame') log = logging.getLogger('subiquitycore.ui.frame')
class SubiquityUI(WidgetWrap): class SubiquityCoreUI(WidgetWrap):
right_icon = Text("")
def __init__(self): def __init__(self):
self.header = Header("") self.header = Header("")
self.footer = Footer("", 0, 1) self.footer = Footer("", self.right_icon, 0, 1)
self.progress_current = 0 self.progress_current = 0
self.progress_completion = 0 self.progress_completion = 0
# After the install starts, we want to stop setting the footer # After the install starts, we want to stop setting the footer
@ -58,7 +60,9 @@ class SubiquityUI(WidgetWrap):
def set_footer(self, message): def set_footer(self, message):
self._assign_contents( self._assign_contents(
2, 2,
Footer(message, self.progress_current, self.progress_completion)) Footer(
message, self.right_icon,
self.progress_current, self.progress_completion))
@property @property
def body(self): def body(self):