changeset 51:3f8599d9a766

core: menus first draft: - menus are handled. Global menus are shown above notification for the moment, but may be displayed differently depending on plateform (e.g. using a button on mobile plateforms) - menu are displayed after profile is connected - backends menus are displayed but not working yet - help/about menu has been added.
author Goffi <goffi@goffi.org>
date Sun, 11 Sep 2016 12:15:41 +0200
parents c45d6e9ec731
children 647f32d0a004
files src/cagou/core/cagou_main.py src/cagou/core/cagou_widget.py src/cagou/core/menu.py src/cagou/kv/menu.kv
diffstat 4 files changed, 227 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/cagou/core/cagou_main.py	Sat Sep 10 18:01:32 2016 +0200
+++ b/src/cagou/core/cagou_main.py	Sun Sep 11 12:15:41 2016 +0200
@@ -48,6 +48,7 @@
 from cagou_widget import CagouWidget
 from . import widgets_handler
 from .common import IconButton
+from .menu import MenusWidget
 from importlib import import_module
 import os.path
 import glob
@@ -138,10 +139,12 @@
 
     def __init__(self, main_widget):
         super(CagouRootWidget, self).__init__(orientation=("vertical"))
+        # general menus
+        self.menus_widget = MenusWidget()
+        self.add_widget(self.menus_widget)
         # header
         self._head_widget = RootHeadWidget()
         self.add_widget(self._head_widget)
-
         # body
         self._manager = ScreenManager()
         # main widgets
@@ -340,7 +343,6 @@
 
     ## widgets handling
 
-
     def newWidget(self, widget):
         log.debug(u"new widget created: {}".format(widget))
         if isinstance(widget, quick_chat.QuickChat) and widget.type == C.CHAT_GROUP:
@@ -413,10 +415,19 @@
             w.addTarget(t)
         return w
 
+    ## menus ##
+
+    def _getMenusCb(self, backend_menus):
+        main_menu = self.app.root.menus_widget
+        self.menus.addMenus(backend_menus)
+        self.menus.addMenu(C.MENU_GLOBAL, (_(u"Help"), _(u"About")), callback=main_menu.onAbout)
+        main_menu.update(C.MENU_GLOBAL)
+
     ## misc ##
 
     def plugging_profiles(self):
         self.app.root.changeWidget(WidgetsHandler())
+        self.bridge.getMenus("", C.NO_SECURITY_LIMIT, callback=self._getMenusCb)
 
     def setPresenceStatus(self, show='', status=None, profile=C.PROF_KEY_NONE):
         log.info(u"Profile presence status set to {show}/{status}".format(show=show, status=status))
--- a/src/cagou/core/cagou_widget.py	Sat Sep 10 18:01:32 2016 +0200
+++ b/src/cagou/core/cagou_widget.py	Sun Sep 11 12:15:41 2016 +0200
@@ -67,3 +67,9 @@
 
     def onHeaderInput(self):
         log.info(u"header input text entered")
+
+    def on_touch_down(self, touch):
+        if self.collide_point(*touch.pos):
+            G.host.selected_widget = self
+        super(CagouWidget, self).on_touch_down(touch)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cagou/core/menu.py	Sun Sep 11 12:15:41 2016 +0200
@@ -0,0 +1,165 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Cagou: desktop/mobile frontend for Salut à Toi XMPP client
+# Copyright (C) 2016 Jérôme Poisson (goffi@goffi.org)
+
+# 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/>.
+
+
+from sat.core.i18n import _
+from sat.core import log as logging
+log = logging.getLogger(__name__)
+from cagou.core.constants import Const as C
+from kivy.uix.scrollview import ScrollView
+from kivy.uix.gridlayout import GridLayout
+from kivy.uix.widget import Widget
+from kivy.uix.label import Label
+from kivy.uix.button import Button
+from kivy.uix.popup import Popup
+from kivy.uix.dropdown import DropDown
+from kivy import properties
+from sat_frontends.quick_frontend import quick_menus
+from cagou import G
+import webbrowser
+
+ABOUT_TITLE = _(u"About {}".format(C.APP_NAME))
+ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{}
+
+Cagou is a libre communication tool based on libre standard XMPP.
+
+Cagou is part of the "Salut à Toi" project
+more informations at [color=5500ff][ref=website]salut-a-toi.org[/ref][/color]
+""").format(C.APP_VERSION)
+
+
+class AboutContent(Label):
+
+    def on_ref_press(self, value):
+        if value == "website":
+            webbrowser.open("https://salut-a-toi.org")
+
+
+class AboutPopup(Popup):
+
+    def on_touch_down(self, touch):
+        if self.collide_point(*touch.pos):
+            self.dismiss()
+        return super(AboutPopup, self).on_touch_down(touch)
+
+
+class MenuItem(Button):
+    item = properties.ObjectProperty()
+
+    def on_item(self, instance, item):
+        self.text = item.name
+
+    def on_release(self):
+        try:
+            self.parent.parent.dismiss()
+        except AttributeError:
+            pass
+        selected = G.host.selected_widget
+        profile = None
+        if selected is not None:
+            try:
+                profile = selected.profile
+            except AttributeError:
+                pass
+
+        if profile is None:
+            try:
+                profile = list(selected.profiles)[0]
+            except (AttributeError, IndexError):
+                try:
+                    profile = list(G.host.profiles)[0]
+                except IndexError:
+                    log.warning(u"Can't find profile")
+
+        self.item.call(selected, profile)
+
+
+class MenuSeparator(Widget):
+    pass
+
+
+class MenuContainer(Button):
+
+    def __init__(self, **kwargs):
+        super(MenuContainer, self).__init__(**kwargs)
+        self.dropdown = DropDown(auto_width=False, size_hint_x=None, width=400)
+
+    def on_release(self):
+        self.dropdown.open(self)
+
+    def add_widget(self, widget):
+        widget.size_hint_y = None
+        self.dropdown.add_widget(widget)
+
+
+class MenusWidget(ScrollView):
+
+    def __init__(self, **kwargs):
+        super(MenusWidget, self).__init__(**kwargs)
+        self._grid = GridLayout(rows=1, size_hint=(None, 1))
+        self._grid.width = self._grid.minimum_width
+        super(MenusWidget, self).add_widget(self._grid)
+
+    def add_widget(self, widget):
+        self._grid.add_widget(widget)
+
+    def clear_widgets(self, children=None):
+        self._grid.clear_widgets(children)
+
+    def update(self, type_, caller=None):
+        """Method to call when menus have changed
+
+        @param type_(unicode): menu type like in sat.core.sat_main.importMenu
+        @param caller(Widget): instance linked to the menus
+        """
+        self.menus_container = G.host.menus.getMainContainer(type_)
+        self.createMenus(caller)
+
+    def _buildMenus(self, container, caller=None):
+        """Recursively build menus of the container
+
+        @param container(quick_menus.MenuContainer): menu container
+        @param caller(Widget): instance linked to the menus
+        """
+        if caller is None:
+            caller = self
+        for child in container.getActiveMenus():
+            if isinstance(child, quick_menus.MenuContainer):
+                menu_container = MenuContainer()
+                menu_container.text = child.name
+                caller.add_widget(menu_container)
+                self._buildMenus(child, caller=menu_container)
+            elif isinstance(child, quick_menus.MenuSeparator):
+                wid = MenuSeparator()
+                caller.add_widget(wid)
+            elif isinstance(child, quick_menus.MenuItem):
+                wid = MenuItem(item=child)
+                caller.add_widget(wid)
+            else:
+                log.error(u"Unknown child type: {}".format(child))
+
+    def createMenus(self, caller):
+        self.clear_widgets()
+        self._buildMenus(self.menus_container, caller)
+
+    def onAbout(self):
+        about = AboutPopup()
+        about.title = ABOUT_TITLE
+        about.content = AboutContent(text=ABOUT_CONTENT, markup=True)
+        about.open()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cagou/kv/menu.kv	Sun Sep 11 12:15:41 2016 +0200
@@ -0,0 +1,43 @@
+# Cagou: desktop/mobile frontend for Salut à Toi XMPP client
+# Copyright (C) 2016 Jérôme Poisson (goffi@goffi.org)
+
+# 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/>.
+
+<MenuItem>:
+    size_hint: None, 1
+    padding: 10, 0
+    width: self.texture_size[0]
+    height: 30
+
+<MenuSeparator>:
+    size_hint: None, None
+    width: 30
+
+<MenuContainer>:
+    size_hint: None, 1
+    width: self.texture_size[0] + dp(20)
+    background_color: 0, 0, 0, 1
+
+<MenusWidget>:
+    size_hint: 1, None
+    height: 30
+
+<AboutContent>:
+    text_size: self.size
+    halign: "center"
+    valign: "middle"
+
+<AboutPopup>:
+    title_align: "center"
+    size_hint: 0.8, 0.8