From a38ff54e4294b2b4245bace9c1d97193ce77e52a Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:26:18 +0300 Subject: [PATCH 01/22] Icons implementation in the backend for winforms --- src/core/toga/resources/tiberius.ico | Bin 0 -> 370070 bytes src/core/toga/widgets/icon.py | 5 +-- src/winforms/toga_winforms/app.py | 7 +++-- src/winforms/toga_winforms/libs.py | 3 +- src/winforms/toga_winforms/widgets/icon.py | 34 +++++++++++++++++++-- 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 src/core/toga/resources/tiberius.ico diff --git a/src/core/toga/resources/tiberius.ico b/src/core/toga/resources/tiberius.ico new file mode 100644 index 0000000000000000000000000000000000000000..aa3492f61b5063462784871c9cc41803a8e3d3b0 GIT binary patch literal 370070 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 literal 0 HcmV?d00001 diff --git a/src/core/toga/widgets/icon.py b/src/core/toga/widgets/icon.py index 81de7af6b2..72c63dfa16 100644 --- a/src/core/toga/widgets/icon.py +++ b/src/core/toga/widgets/icon.py @@ -26,10 +26,7 @@ class Icon: """ def __init__(self, path, system=False): - if os.path.splitext(path)[1] in ('.png', '.icns', '.bmp'): - self.path = path - else: - self.path = path + '.icns' + self.path = path self.system = system diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index d8663659de..502ee46fff 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -17,14 +17,17 @@ def __init__(self, interface): def create(self): self.native = WinForms.Application - # self.native.setApplicationIconImage_(self.icon.native) - # Set the menu for the app. # self.native.setMainMenu_(self.menu) # Call user code to populate the main window self.interface.startup() + self.interface.main_window._impl.native.Icon = \ + self.interface.icon.bind(self.interface.factory).native + + + def open_document(self, fileURL): '''Add a new document to this app.''' print("STUB: If you want to handle opening documents, implement App.open_document(fileURL)") diff --git a/src/winforms/toga_winforms/libs.py b/src/winforms/toga_winforms/libs.py index f1bdd2721d..bf1878b8be 100644 --- a/src/winforms/toga_winforms/libs.py +++ b/src/winforms/toga_winforms/libs.py @@ -8,7 +8,8 @@ from System import Convert from System import Threading from System import Uri -from System.Drawing import Size, Point, Color, ContentAlignment +from System.Drawing import Size, Point, Color, ContentAlignment, Bitmap +from System.Drawing import Icon as WinIcon def TextAlignment(value): diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index bce10585bf..6197a80f6b 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -1,8 +1,36 @@ -# from ..libs import NSImage +import os +from toga_winforms.libs import Bitmap, WinIcon class Icon: def __init__(self, interface): + + def create_icon_from_file(filename): + icon_bitmap = Bitmap(self.interface.filename) + icon_handle = icon_bitmap.GetHicon() + return WinIcon.FromHandle(icon_handle) + self.interface = interface - interface._impl = self - # self.native = NSImage.alloc().initWithContentsOfFile(interface.filename) + self.interface._impl = self + + valid_icon_extensions = ('.png', '.bmp', '.ico') + file_path, file_extension = os.path.splitext(self.interface.filename) + + if file_extension == '.ico': + self.native = WinIcon(self.interface.filename) + + elif os.path.isfile(file_path + '.ico'): + self.native = WinIcon(file_path + '.ico') + + elif file_extension in valid_icon_extensions: + self.native = create_icon_from_file(self.interface.filename) + + elif os.path.isfile(file_path + '.png'): + self.native = create_icon_from_file(file_path + '.png') + + elif os.path.isfile(file_path + '.bmp'): + self.native = create_icon_from_file(file_path + '.bmp') + + else: + # Return tiberius? + raise AttributeError("No valid icon format for winforms") From 22af9586b2c175276617b98555466b11fb0774d6 Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:47:00 +0300 Subject: [PATCH 02/22] Icons implementation in the backend for cocoa, tests adjusted --- src/cocoa/toga_cocoa/widgets/icon.py | 13 ++++++++++--- src/core/tests/test_app.py | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index 0cf222373a..d42440b77a 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -1,8 +1,15 @@ from toga_cocoa.libs import NSImage - +import os class Icon: def __init__(self, interface): self.interface = interface - interface.__impl = self - self.native = NSImage.alloc().initWithContentsOfFile(interface.filename) + interface._impl = self + valid_icon_extensions = ('.png', '.bmp', '.icns') + file_path, file_extension = os.path.splitext(self.interface.filename) + + if file_extension in valid_icon_extensions: + self.native = NSImage.alloc().initWithContentsOfFile(interface.filename) + else: + # Return tiberius? + raise AttributeError("No valid icon format for cocoa") diff --git a/src/core/tests/test_app.py b/src/core/tests/test_app.py index 8fa72c84df..9a97871537 100644 --- a/src/core/tests/test_app.py +++ b/src/core/tests/test_app.py @@ -34,7 +34,7 @@ def test_app_icon(self): self.assertEqual(self.app.icon, self.app.default_icon) # Set the icon to a different resource - self.app.icon = "other" + self.app.icon = "other.icns" self.assertEqual(self.app.icon.path, "other.icns") def test_app_app_id(self): From 487249b241193e31c9290ede7fc08f150c80d140 Mon Sep 17 00:00:00 2001 From: obulat Date: Sun, 11 Mar 2018 08:47:06 +0300 Subject: [PATCH 03/22] Added icon resolution and fallback to winforms and cocoa; updated command icons for winforms --- src/cocoa/toga_cocoa/widgets/icon.py | 29 ++++++++++++++----- src/winforms/toga_winforms/command.py | 16 ++++++---- src/winforms/toga_winforms/widgets/icon.py | 11 +++++-- src/winforms/toga_winforms/widgets/webview.py | 2 +- src/winforms/toga_winforms/window.py | 23 +++++++++++++-- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index d42440b77a..d7ef5985e3 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -1,15 +1,30 @@ -from toga_cocoa.libs import NSImage import os +from toga import Icon as toga_Icon +from toga_cocoa.libs import NSImage + + class Icon: def __init__(self, interface): self.interface = interface - interface._impl = self - valid_icon_extensions = ('.png', '.bmp', '.icns') + self.interface._impl = self file_path, file_extension = os.path.splitext(self.interface.filename) + valid_icon_extensions = ('.png', '.bmp', '.ico') - if file_extension in valid_icon_extensions: - self.native = NSImage.alloc().initWithContentsOfFile(interface.filename) + if file_extension == '.icns': + self.native = NSImage.alloc().initWithContentsOfFile(self.interface.filename) + elif os.path.isfile(file_path + '.icns'): + self.native = NSImage.alloc().initWithContentsOfFile(file_path + '.icns') + elif file_extension in valid_icon_extensions: + self.native = NSImage.alloc().initWithContentsOfFile(self.interface.filename) + elif os.path.isfile(file_path + '.png'): + self.native = NSImage.alloc().initWithContentsOfFile(file_path + '.png') + elif os.path.isfile(file_path + '.bmp'): + self.native = NSImage.alloc().initWithContentsOfFile(file_path + '.bmp') else: - # Return tiberius? - raise AttributeError("No valid icon format for cocoa") + print("[Cocoa] No valid icon format available for {}; " + "fall back on Tiberius instead".format( + self.interface.filename)) + tiberius_file = toga_Icon.TIBERIUS_ICON.filename + '.icns' + self.interface.icon = toga_Icon.TIBERIUS_ICON + self.native = NSImage.alloc().initWithContentsOfFile(tiberius_file) diff --git a/src/winforms/toga_winforms/command.py b/src/winforms/toga_winforms/command.py index 3bbbe7d62c..4fd4d2c588 100644 --- a/src/winforms/toga_winforms/command.py +++ b/src/winforms/toga_winforms/command.py @@ -1,10 +1,14 @@ -#from .widgets.icon import Icon +from toga.widgets.icon import Icon as CoreIcon class Command: def __init__(self, interface): self.interface = interface - - # if self.interface.icon_id: - # self.icon = Icon.load(self.interface.icon_id) - # else: - # self.icon = None + self.native = None + if self.interface.icon_id: + # If icon_id is an icon, not a filepath + if type(self.interface.icon_id) is not str: + self.interface.icon = self.interface.icon_id + else: + self.interface.icon = CoreIcon(self.interface.icon_id) + else: + self.interface.icon = None diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 6197a80f6b..5c5f8bff26 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -1,7 +1,9 @@ import os +from toga import Icon as toga_Icon from toga_winforms.libs import Bitmap, WinIcon + class Icon: def __init__(self, interface): @@ -12,7 +14,6 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self - valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) @@ -32,5 +33,9 @@ def create_icon_from_file(filename): self.native = create_icon_from_file(file_path + '.bmp') else: - # Return tiberius? - raise AttributeError("No valid icon format for winforms") + print("[Winforms] No valid icon format available for {}; " + "fall back on Tiberius instead".format( + self.interface.filename)) + tiberius_file = toga_Icon.TIBERIUS_ICON.filename + '.ico' + self.interface.icon = toga_Icon.TIBERIUS_ICON + self.native = WinIcon(tiberius_file) diff --git a/src/winforms/toga_winforms/widgets/webview.py b/src/winforms/toga_winforms/widgets/webview.py index b139ec796b..e1253c0c50 100644 --- a/src/winforms/toga_winforms/widgets/webview.py +++ b/src/winforms/toga_winforms/widgets/webview.py @@ -1,6 +1,6 @@ from travertino.size import at_least -from toga_winforms.libs import WinForms +from toga_winforms.libs import WinForms, Uri from .base import Widget diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index bcae2ac4a2..10d718aa45 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -1,7 +1,8 @@ from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport -from .libs import WinForms, Size +from .libs import WinForms, Size, Bitmap, WinIcon +import os class WinFormsViewport: @@ -36,14 +37,30 @@ def create(self): self.toolbar_items = None def create_toolbar(self): - self.toolbar_native = WinForms.ToolStrip() + self.toolbar_native = WinForms.MenuStrip() for cmd in self.interface.toolbar: if cmd == GROUP_BREAK: item = WinForms.ToolStripSeparator() elif cmd == SECTION_BREAK: item = WinForms.ToolStripSeparator() else: - item = WinForms.ToolStripButton() + cmd.native = cmd.bind(self.interface.factory) + native_icon = cmd.icon.bind(self.interface.factory).native + if cmd.icon is not None: + item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap()) + else: + item = WinForms.ToolStripMenuItem(cmd.label) + + def add_handler(cmd): + action = cmd.action + + def handler(sender, event): + return action(None) + + return handler + + item.Click += add_handler(cmd) + self.toolbar_native.Items.Add(item) def set_position(self, position): From ecc53e89a25342c5ba1bf3a846b55150f613080a Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:26:18 +0300 Subject: [PATCH 04/22] Icons implementation in the backend for winforms --- src/winforms/toga_winforms/widgets/icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 5c5f8bff26..8952c8ef2d 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -3,7 +3,6 @@ from toga import Icon as toga_Icon from toga_winforms.libs import Bitmap, WinIcon - class Icon: def __init__(self, interface): @@ -14,6 +13,7 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self + valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) From 7fa66ba4a75c49a195d41d344cdebc5717c73758 Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:47:00 +0300 Subject: [PATCH 05/22] Icons implementation in the backend for cocoa, tests adjusted --- src/cocoa/toga_cocoa/widgets/icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index d7ef5985e3..7e0dc31c3a 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -2,7 +2,7 @@ from toga import Icon as toga_Icon from toga_cocoa.libs import NSImage - +import os class Icon: def __init__(self, interface): From c9544b48142fbd6e57c30db7a5905e2a86c01e2a Mon Sep 17 00:00:00 2001 From: obulat Date: Sun, 11 Mar 2018 08:47:06 +0300 Subject: [PATCH 06/22] Added icon resolution and fallback to winforms and cocoa; updated command icons for winforms --- src/cocoa/toga_cocoa/widgets/icon.py | 2 +- src/winforms/toga_winforms/widgets/icon.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index 7e0dc31c3a..d7ef5985e3 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -2,7 +2,7 @@ from toga import Icon as toga_Icon from toga_cocoa.libs import NSImage -import os + class Icon: def __init__(self, interface): diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 8952c8ef2d..5c5f8bff26 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -3,6 +3,7 @@ from toga import Icon as toga_Icon from toga_winforms.libs import Bitmap, WinIcon + class Icon: def __init__(self, interface): @@ -13,7 +14,6 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self - valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) From 59fbc518b18617235b1ff913f02f7e374244ee82 Mon Sep 17 00:00:00 2001 From: obulat Date: Fri, 16 Mar 2018 20:14:22 +0300 Subject: [PATCH 07/22] Implemented menu in winforms Signed-off-by: obulat --- src/core/toga/command.py | 2 ++ src/winforms/toga_winforms/window.py | 54 ++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/core/toga/command.py b/src/core/toga/command.py index bbaccb0935..88216ddc4f 100644 --- a/src/core/toga/command.py +++ b/src/core/toga/command.py @@ -76,6 +76,8 @@ def enabled(self, value): self._enabled = value for widget in self._widgets: widget.enabled = value + if self._impl is not None: + self._impl.enabled = value GROUP_BREAK = object() diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index 10d718aa45..9d207c0a03 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -1,8 +1,7 @@ from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport -from .libs import WinForms, Size, Bitmap, WinIcon -import os +from .libs import WinForms, Size class WinFormsViewport: @@ -50,19 +49,56 @@ def create_toolbar(self): item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap()) else: item = WinForms.ToolStripMenuItem(cmd.label) - def add_handler(cmd): action = cmd.action - def handler(sender, event): return action(None) - return handler - item.Click += add_handler(cmd) - self.toolbar_native.Items.Add(item) + def create_menus(self): + # Should I put this to libs? or somewhere in the window? It is repeated twice + # TODO: add standard commands + def add_handler(cmd): + action = cmd.action + + def handler(sender, event): + return action(None) + + return handler + + # Only create the menu if the menu item index has been created. + if hasattr(self, '_menu_items'): + self._menu_items = {} + menubar = WinForms.MenuStrip() + submenu = None + for cmd in self.interface._app.commands: + if cmd == GROUP_BREAK: + menubar.Items.Add(submenu) + submenu = None + elif cmd == SECTION_BREAK: + submenu.DropDownItems.Add(WinForms.ToolStripSeparator) + else: + if submenu is None: + submenu = WinForms.ToolStripMenuItem(cmd.group.label) + + item = WinForms.ToolStripMenuItem(cmd.label) + item.Click += add_handler(cmd) + cmd._widgets.append(item) + self._menu_items[item] = cmd + # This line may appear redundant, but it triggers the logic + # to force the enabled status on the underlying widgets. + cmd.enabled = cmd.enabled + submenu.DropDownItems.Add(item) + if submenu: + menubar.Items.Add(submenu) + + # Set the menu for the app. + self.native.MainMenuStrip = menubar + self.native.Controls.Add(menubar) + + def set_position(self, position): pass @@ -83,6 +119,10 @@ def vertical_shift(self): def set_content(self, widget): if self.toolbar_native: self.native.Controls.Add(self.toolbar_native) + # Create the lookup table of menu items, + # then force the creation of the menus. + self._menu_items = {} + self.create_menus() self.native.Controls.Add(widget.native) From 819823212340ccf909c49adc1881e9faaf37b9ac Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Wed, 4 Apr 2018 07:58:38 +0300 Subject: [PATCH 08/22] Implemented menustrip in winforms Signed-off-by: obulat --- src/winforms/toga_winforms/window.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index 9d207c0a03..af4f07fcf7 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -1,3 +1,4 @@ +import toga from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport @@ -49,17 +50,22 @@ def create_toolbar(self): item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap()) else: item = WinForms.ToolStripMenuItem(cmd.label) + def add_handler(cmd): action = cmd.action + def handler(sender, event): return action(None) + return handler + item.Click += add_handler(cmd) self.toolbar_native.Items.Add(item) def create_menus(self): - # Should I put this to libs? or somewhere in the window? It is repeated twice - # TODO: add standard commands + + toga.Group.FILE.order = 0 + def add_handler(cmd): action = cmd.action @@ -78,11 +84,10 @@ def handler(sender, event): menubar.Items.Add(submenu) submenu = None elif cmd == SECTION_BREAK: - submenu.DropDownItems.Add(WinForms.ToolStripSeparator) + submenu.DropDownItems.Add('-') else: if submenu is None: submenu = WinForms.ToolStripMenuItem(cmd.group.label) - item = WinForms.ToolStripMenuItem(cmd.label) item.Click += add_handler(cmd) cmd._widgets.append(item) @@ -98,7 +103,6 @@ def handler(sender, event): self.native.MainMenuStrip = menubar self.native.Controls.Add(menubar) - def set_position(self, position): pass @@ -122,8 +126,8 @@ def set_content(self, widget): # Create the lookup table of menu items, # then force the creation of the menus. self._menu_items = {} - self.create_menus() - + if self.interface is self.interface.app._main_window: + self.create_menus() self.native.Controls.Add(widget.native) # Set the widget's viewport to be based on the window's content. From 3b09ad3b04b80d295d2de29a4e68ea5991e0cfeb Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:26:18 +0300 Subject: [PATCH 09/22] Icons implementation in the backend for winforms --- src/winforms/toga_winforms/widgets/icon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 5c5f8bff26..a0faeb13a1 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -14,6 +14,7 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self + valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) From 595477765ef2a7b628ce1996545560feff1da208 Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:47:00 +0300 Subject: [PATCH 10/22] Icons implementation in the backend for cocoa, tests adjusted --- src/cocoa/toga_cocoa/widgets/icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index d7ef5985e3..7e0dc31c3a 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -2,7 +2,7 @@ from toga import Icon as toga_Icon from toga_cocoa.libs import NSImage - +import os class Icon: def __init__(self, interface): From 70639094d97b8b3a5d8c447ff48a4009133dd921 Mon Sep 17 00:00:00 2001 From: obulat Date: Sun, 11 Mar 2018 08:47:06 +0300 Subject: [PATCH 11/22] Added icon resolution and fallback to winforms and cocoa; updated command icons for winforms --- src/cocoa/toga_cocoa/widgets/icon.py | 2 +- src/winforms/toga_winforms/widgets/icon.py | 1 - src/winforms/toga_winforms/window.py | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cocoa/toga_cocoa/widgets/icon.py b/src/cocoa/toga_cocoa/widgets/icon.py index 7e0dc31c3a..d7ef5985e3 100644 --- a/src/cocoa/toga_cocoa/widgets/icon.py +++ b/src/cocoa/toga_cocoa/widgets/icon.py @@ -2,7 +2,7 @@ from toga import Icon as toga_Icon from toga_cocoa.libs import NSImage -import os + class Icon: def __init__(self, interface): diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index a0faeb13a1..5c5f8bff26 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -14,7 +14,6 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self - valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index af4f07fcf7..e56cb24157 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -2,7 +2,8 @@ from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport -from .libs import WinForms, Size +from .libs import WinForms, Size, Bitmap, WinIcon +import os class WinFormsViewport: @@ -60,6 +61,7 @@ def handler(sender, event): return handler item.Click += add_handler(cmd) + self.toolbar_native.Items.Add(item) def create_menus(self): From 36fa784630c80f6f7c1802ea8398c7dd58fd091c Mon Sep 17 00:00:00 2001 From: obulat Date: Sat, 10 Mar 2018 13:26:18 +0300 Subject: [PATCH 12/22] Icons implementation in the backend for winforms --- src/winforms/toga_winforms/widgets/icon.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 5c5f8bff26..6197a80f6b 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -1,9 +1,7 @@ import os -from toga import Icon as toga_Icon from toga_winforms.libs import Bitmap, WinIcon - class Icon: def __init__(self, interface): @@ -14,6 +12,7 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self + valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) @@ -33,9 +32,5 @@ def create_icon_from_file(filename): self.native = create_icon_from_file(file_path + '.bmp') else: - print("[Winforms] No valid icon format available for {}; " - "fall back on Tiberius instead".format( - self.interface.filename)) - tiberius_file = toga_Icon.TIBERIUS_ICON.filename + '.ico' - self.interface.icon = toga_Icon.TIBERIUS_ICON - self.native = WinIcon(tiberius_file) + # Return tiberius? + raise AttributeError("No valid icon format for winforms") From a5633ef634a350a8ddbc6a588bc7e05f2dc41608 Mon Sep 17 00:00:00 2001 From: obulat Date: Sun, 11 Mar 2018 08:47:06 +0300 Subject: [PATCH 13/22] Added icon resolution and fallback to winforms and cocoa; updated command icons for winforms --- src/winforms/toga_winforms/widgets/icon.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/winforms/toga_winforms/widgets/icon.py b/src/winforms/toga_winforms/widgets/icon.py index 6197a80f6b..5c5f8bff26 100644 --- a/src/winforms/toga_winforms/widgets/icon.py +++ b/src/winforms/toga_winforms/widgets/icon.py @@ -1,7 +1,9 @@ import os +from toga import Icon as toga_Icon from toga_winforms.libs import Bitmap, WinIcon + class Icon: def __init__(self, interface): @@ -12,7 +14,6 @@ def create_icon_from_file(filename): self.interface = interface self.interface._impl = self - valid_icon_extensions = ('.png', '.bmp', '.ico') file_path, file_extension = os.path.splitext(self.interface.filename) @@ -32,5 +33,9 @@ def create_icon_from_file(filename): self.native = create_icon_from_file(file_path + '.bmp') else: - # Return tiberius? - raise AttributeError("No valid icon format for winforms") + print("[Winforms] No valid icon format available for {}; " + "fall back on Tiberius instead".format( + self.interface.filename)) + tiberius_file = toga_Icon.TIBERIUS_ICON.filename + '.ico' + self.interface.icon = toga_Icon.TIBERIUS_ICON + self.native = WinIcon(tiberius_file) From e7d7aac64a1f22794e65c2385c161e844b72f007 Mon Sep 17 00:00:00 2001 From: obulat Date: Fri, 16 Mar 2018 20:14:22 +0300 Subject: [PATCH 14/22] Implemented menu in winforms Signed-off-by: obulat --- src/winforms/toga_winforms/window.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index e56cb24157..bd07673493 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -2,8 +2,7 @@ from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport -from .libs import WinForms, Size, Bitmap, WinIcon -import os +from .libs import WinForms, Size class WinFormsViewport: @@ -51,23 +50,19 @@ def create_toolbar(self): item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap()) else: item = WinForms.ToolStripMenuItem(cmd.label) - def add_handler(cmd): action = cmd.action - def handler(sender, event): return action(None) - return handler - item.Click += add_handler(cmd) - self.toolbar_native.Items.Add(item) def create_menus(self): - toga.Group.FILE.order = 0 + # Should I put this to libs? or somewhere in the window? It is repeated twice + # TODO: add standard commands def add_handler(cmd): action = cmd.action @@ -86,10 +81,11 @@ def handler(sender, event): menubar.Items.Add(submenu) submenu = None elif cmd == SECTION_BREAK: - submenu.DropDownItems.Add('-') + submenu.DropDownItems.Add(WinForms.ToolStripSeparator) else: if submenu is None: submenu = WinForms.ToolStripMenuItem(cmd.group.label) + item = WinForms.ToolStripMenuItem(cmd.label) item.Click += add_handler(cmd) cmd._widgets.append(item) @@ -128,8 +124,8 @@ def set_content(self, widget): # Create the lookup table of menu items, # then force the creation of the menus. self._menu_items = {} - if self.interface is self.interface.app._main_window: - self.create_menus() + self.create_menus() + self.native.Controls.Add(widget.native) # Set the widget's viewport to be based on the window's content. From 673ae5eebb2aa257f7a12517570b7ffc95de3c8a Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Wed, 4 Apr 2018 07:58:38 +0300 Subject: [PATCH 15/22] Implemented menustrip in winforms Signed-off-by: obulat --- src/winforms/toga_winforms/window.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index bd07673493..ef3af7fc5b 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -50,19 +50,21 @@ def create_toolbar(self): item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap()) else: item = WinForms.ToolStripMenuItem(cmd.label) + def add_handler(cmd): action = cmd.action + def handler(sender, event): return action(None) + return handler + item.Click += add_handler(cmd) self.toolbar_native.Items.Add(item) def create_menus(self): toga.Group.FILE.order = 0 - # Should I put this to libs? or somewhere in the window? It is repeated twice - # TODO: add standard commands def add_handler(cmd): action = cmd.action @@ -81,11 +83,10 @@ def handler(sender, event): menubar.Items.Add(submenu) submenu = None elif cmd == SECTION_BREAK: - submenu.DropDownItems.Add(WinForms.ToolStripSeparator) + submenu.DropDownItems.Add('-') else: if submenu is None: submenu = WinForms.ToolStripMenuItem(cmd.group.label) - item = WinForms.ToolStripMenuItem(cmd.label) item.Click += add_handler(cmd) cmd._widgets.append(item) @@ -124,8 +125,8 @@ def set_content(self, widget): # Create the lookup table of menu items, # then force the creation of the menus. self._menu_items = {} - self.create_menus() - + if self.interface is self.interface.app._main_window: + self.create_menus() self.native.Controls.Add(widget.native) # Set the widget's viewport to be based on the window's content. From 358788d645c47c84c3e95c9920067e33421b9976 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Wed, 4 Apr 2018 09:47:51 +0300 Subject: [PATCH 16/22] Added standard menu items to WinForms backend Signed-off-by: obulat --- src/winforms/toga_winforms/app.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index 502ee46fff..ece70eea60 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -1,5 +1,7 @@ from .libs import Threading, WinForms from .window import Window +import toga +import sys class MainWindow(Window): @@ -17,8 +19,16 @@ def __init__(self, interface): def create(self): self.native = WinForms.Application - # Set the menu for the app. - # self.native.setMainMenu_(self.menu) + self.interface.commands.add( + toga.Command(None, 'About ' + self.interface.name, group=toga.Group.HELP), + + toga.Command(None, 'Preferences', group=toga.Group.FILE), + # Quit should always be the last item, in a section on it's own + toga.Command(lambda s: self.exit(), 'Exit ' + self.interface.name, shortcut='q', group=toga.Group.FILE, + section=sys.maxsize), + + toga.Command(None, 'Visit homepage', group=toga.Group.HELP) + ) # Call user code to populate the main window self.interface.startup() From f1fcd0785d7903d498bded40d529ddb2e37c77f6 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Thu, 5 Apr 2018 09:29:01 +0300 Subject: [PATCH 17/22] Moved add_handler function to winforms.libs, added app.exit() implementation Signed-off-by: obulat --- src/winforms/toga_winforms/app.py | 5 +---- src/winforms/toga_winforms/libs.py | 9 +++++++++ src/winforms/toga_winforms/window.py | 18 +----------------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index ece70eea60..46470bcc75 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -42,9 +42,6 @@ def open_document(self, fileURL): '''Add a new document to this app.''' print("STUB: If you want to handle opening documents, implement App.open_document(fileURL)") - def create_menus(self): - self.interface.factory.not_implemented('App.create_menus()') - def run_app(self): self.create() self.native.Run(self.interface.main_window._impl.native) @@ -56,4 +53,4 @@ def main_loop(self): thread.Join() def exit(self): - self.interface.factory.not_implemented('App.exit()') + self.native.Exit() diff --git a/src/winforms/toga_winforms/libs.py b/src/winforms/toga_winforms/libs.py index bf1878b8be..fd89bea992 100644 --- a/src/winforms/toga_winforms/libs.py +++ b/src/winforms/toga_winforms/libs.py @@ -19,3 +19,12 @@ def TextAlignment(value): CENTER: ContentAlignment.MiddleCenter, JUSTIFY: ContentAlignment.MiddleLeft, }[value] + + +def add_handler(cmd): + action = cmd.action + + def handler(sender, event): + return action(None) + + return handler diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index ef3af7fc5b..09d0be7496 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -2,7 +2,7 @@ from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport -from .libs import WinForms, Size +from .libs import WinForms, Size, add_handler class WinFormsViewport: @@ -51,28 +51,12 @@ def create_toolbar(self): else: item = WinForms.ToolStripMenuItem(cmd.label) - def add_handler(cmd): - action = cmd.action - - def handler(sender, event): - return action(None) - - return handler - item.Click += add_handler(cmd) self.toolbar_native.Items.Add(item) def create_menus(self): toga.Group.FILE.order = 0 - def add_handler(cmd): - action = cmd.action - - def handler(sender, event): - return action(None) - - return handler - # Only create the menu if the menu item index has been created. if hasattr(self, '_menu_items'): self._menu_items = {} From 78b70244126932d9bac356ffa912df12718ef220 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 7 Apr 2018 16:27:30 +0300 Subject: [PATCH 18/22] Move create_menus to app --- src/winforms/toga_winforms/app.py | 33 ++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index 46470bcc75..3c76fac735 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -21,21 +21,48 @@ def create(self): self.interface.commands.add( toga.Command(None, 'About ' + self.interface.name, group=toga.Group.HELP), - toga.Command(None, 'Preferences', group=toga.Group.FILE), # Quit should always be the last item, in a section on it's own toga.Command(lambda s: self.exit(), 'Exit ' + self.interface.name, shortcut='q', group=toga.Group.FILE, section=sys.maxsize), - toga.Command(None, 'Visit homepage', group=toga.Group.HELP) ) # Call user code to populate the main window self.interface.startup() - + self._menu_items = {} + self.create_menus() self.interface.main_window._impl.native.Icon = \ self.interface.icon.bind(self.interface.factory).native + def create_menus(self): + toga.Group.FILE.order = 0 + # Only create the menu if the menu item index has been created. + if hasattr(self, '_menu_items'): + menubar = WinForms.MenuStrip() + submenu = None + for cmd in self.interface.commands: + if cmd == toga.GROUP_BREAK: + menubar.Items.Add(submenu) + submenu = None + elif cmd == toga.SECTION_BREAK: + submenu.DropDownItems.Add('-') + else: + if submenu is None: + submenu = WinForms.ToolStripMenuItem(cmd.group.label) + item = WinForms.ToolStripMenuItem(cmd.label) + item.Click += add_handler(cmd) + cmd._widgets.append(item) + self._menu_items[item] = cmd + # This line may appear redundant, but it triggers the logic + # to force the enabled status on the underlying widgets. + cmd.enabled = cmd.enabled + submenu.DropDownItems.Add(item) + if submenu: + menubar.Items.Add(submenu) + + self.interface.main_window._impl.native.Controls.Add(menubar) + def open_document(self, fileURL): From e4b97c9100664c06e0e3861201baa7048ad3bfdb Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 7 Apr 2018 16:29:18 +0300 Subject: [PATCH 19/22] Deleted create_menus from window --- src/winforms/toga_winforms/window.py | 32 ---------------------------- 1 file changed, 32 deletions(-) diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index 09d0be7496..58ef7cb2d4 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -54,38 +54,6 @@ def create_toolbar(self): item.Click += add_handler(cmd) self.toolbar_native.Items.Add(item) - def create_menus(self): - toga.Group.FILE.order = 0 - - # Only create the menu if the menu item index has been created. - if hasattr(self, '_menu_items'): - self._menu_items = {} - menubar = WinForms.MenuStrip() - submenu = None - for cmd in self.interface._app.commands: - if cmd == GROUP_BREAK: - menubar.Items.Add(submenu) - submenu = None - elif cmd == SECTION_BREAK: - submenu.DropDownItems.Add('-') - else: - if submenu is None: - submenu = WinForms.ToolStripMenuItem(cmd.group.label) - item = WinForms.ToolStripMenuItem(cmd.label) - item.Click += add_handler(cmd) - cmd._widgets.append(item) - self._menu_items[item] = cmd - # This line may appear redundant, but it triggers the logic - # to force the enabled status on the underlying widgets. - cmd.enabled = cmd.enabled - submenu.DropDownItems.Add(item) - if submenu: - menubar.Items.Add(submenu) - - # Set the menu for the app. - self.native.MainMenuStrip = menubar - self.native.Controls.Add(menubar) - def set_position(self, position): pass From f4bb445c20da1186a76bb6293df375509185b7a3 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Mon, 9 Apr 2018 09:19:39 +0300 Subject: [PATCH 20/22] Small fixes Signed-off-by: obulat --- src/winforms/toga_winforms/app.py | 2 +- src/winforms/toga_winforms/libs.py | 2 -- src/winforms/toga_winforms/window.py | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index 3c76fac735..3104f707d5 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -1,4 +1,4 @@ -from .libs import Threading, WinForms +from .libs import Threading, WinForms, add_handler from .window import Window import toga import sys diff --git a/src/winforms/toga_winforms/libs.py b/src/winforms/toga_winforms/libs.py index fd89bea992..fe71ffa4de 100644 --- a/src/winforms/toga_winforms/libs.py +++ b/src/winforms/toga_winforms/libs.py @@ -23,8 +23,6 @@ def TextAlignment(value): def add_handler(cmd): action = cmd.action - def handler(sender, event): return action(None) - return handler diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index 58ef7cb2d4..17bea56f92 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -76,9 +76,6 @@ def set_content(self, widget): self.native.Controls.Add(self.toolbar_native) # Create the lookup table of menu items, # then force the creation of the menus. - self._menu_items = {} - if self.interface is self.interface.app._main_window: - self.create_menus() self.native.Controls.Add(widget.native) # Set the widget's viewport to be based on the window's content. From 711419bd639f1e6151d5dfd36e562b4d75774807 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Fri, 13 Apr 2018 18:14:47 +0300 Subject: [PATCH 21/22] Menu items without actions are disabled Signed-off-by: obulat --- src/winforms/toga_winforms/app.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index 3104f707d5..6dacbb486d 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -51,12 +51,12 @@ def create_menus(self): if submenu is None: submenu = WinForms.ToolStripMenuItem(cmd.group.label) item = WinForms.ToolStripMenuItem(cmd.label) - item.Click += add_handler(cmd) + if cmd.action: + item.Click += add_handler(cmd) + else: + item.Enabled = False cmd._widgets.append(item) self._menu_items[item] = cmd - # This line may appear redundant, but it triggers the logic - # to force the enabled status on the underlying widgets. - cmd.enabled = cmd.enabled submenu.DropDownItems.Add(item) if submenu: menubar.Items.Add(submenu) From b30fd8edaefa0d0b2f71f1966da66c27fe85ade4 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 14 Apr 2018 07:30:41 +0300 Subject: [PATCH 22/22] Menu items without actions are disabled Signed-off-by: obulat --- src/winforms/toga_winforms/app.py | 11 ++++++----- src/winforms/toga_winforms/window.py | 11 ++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/winforms/toga_winforms/app.py b/src/winforms/toga_winforms/app.py index 6dacbb486d..bb89f65204 100644 --- a/src/winforms/toga_winforms/app.py +++ b/src/winforms/toga_winforms/app.py @@ -1,7 +1,9 @@ +import sys + +import toga + from .libs import Threading, WinForms, add_handler from .window import Window -import toga -import sys class MainWindow(Window): @@ -60,10 +62,9 @@ def create_menus(self): submenu.DropDownItems.Add(item) if submenu: menubar.Items.Add(submenu) - self.interface.main_window._impl.native.Controls.Add(menubar) - - + self.interface.main_window._impl.native.MainMenuStrip = menubar + self.interface.main_window.content.refresh() def open_document(self, fileURL): '''Add a new document to this app.''' diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py index 17bea56f92..667d60966d 100644 --- a/src/winforms/toga_winforms/window.py +++ b/src/winforms/toga_winforms/window.py @@ -1,4 +1,3 @@ -import toga from toga import GROUP_BREAK, SECTION_BREAK from travertino.layout import Viewport @@ -66,10 +65,16 @@ def set_app(self, app): @property def vertical_shift(self): # vertical shift is the toolbar height or 0 + result = 0 try: - return self.native.interface._impl.toolbar_native.Height + result += self.native.interface._impl.toolbar_native.Height except AttributeError: - return 0 + pass + try: + result += self.native.interface._impl.native.MainMenuStrip.Height + except AttributeError: + pass + return result def set_content(self, widget): if self.toolbar_native: