Initial push...
16
README.md
|
@ -1,5 +1,5 @@
|
|||
# Python-With-Gtk-Template
|
||||
A template project for Python with Gtk applications.
|
||||
# Newton Editor
|
||||
A Python and Gtk+ quasi-IDE.
|
||||
|
||||
### Requirements
|
||||
* PyGObject
|
||||
|
@ -7,14 +7,4 @@ A template project for Python with Gtk applications.
|
|||
* pyxdg
|
||||
|
||||
### Note
|
||||
There are a "\<change_me\>" strings and files that need to be set according to your app's name located at:
|
||||
* \_\_builtins\_\_.py
|
||||
* user_config/bin/app_name
|
||||
* user_config/usr/share/app_name
|
||||
* user_config/usr/share/app_name/icons/app_name.png
|
||||
* user_config/usr/share/app_name/icons/app_name-64x64.png
|
||||
* user_config/usr/share/applications/app_name.desktop
|
||||
|
||||
|
||||
For the user_config, after changing names and files, copy all content to their respective destinations.
|
||||
The logic follows Debian Dpkg packaging and its placement logic.
|
||||
WIP
|
||||
|
|
|
@ -29,7 +29,7 @@ def daemon_threaded_wrapper(fn):
|
|||
|
||||
# NOTE: Just reminding myself we can add to builtins two different ways...
|
||||
# __builtins__.update({"event_system": Builtins()})
|
||||
builtins.app_name = "<change_me>"
|
||||
builtins.app_name = "Newton_Editor"
|
||||
builtins.keybindings = Keybindings()
|
||||
builtins.event_system = EventSystem()
|
||||
builtins.endpoint_registry = EndpointRegistry()
|
||||
|
|
|
@ -6,7 +6,8 @@ gi.require_version('Gtk', '3.0')
|
|||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
from .widgets.base.banner_controls import BannerControls
|
||||
from .widgets.base.editer_notebook import EditorNotebook
|
||||
|
||||
|
||||
|
||||
|
@ -14,8 +15,6 @@ class CoreWidget(Gtk.Box):
|
|||
def __init__(self):
|
||||
super(CoreWidget, self).__init__()
|
||||
|
||||
self._builder = settings.get_builder()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
@ -30,15 +29,5 @@ class CoreWidget(Gtk.Box):
|
|||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
glade_box = self._builder.get_object("glade_box")
|
||||
button = Gtk.Button(label="Click Me!")
|
||||
|
||||
button.connect("clicked", self._hello_world)
|
||||
|
||||
self.add(button)
|
||||
self.add(glade_box)
|
||||
|
||||
|
||||
|
||||
def _hello_world(self, widget=None, eve=None):
|
||||
print("Hello, World!")
|
||||
self.add(BannerControls())
|
||||
self.add(EditorNotebook())
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Widgets Module
|
||||
"""
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Widgets.Base Module
|
||||
"""
|
|
@ -0,0 +1,39 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..controls.toggle_line_highlight import ToggleLineHighlight
|
||||
from ..controls.scale_up_button import ScaleUpButton
|
||||
from ..controls.scale_down_button import ScaleDownButton
|
||||
|
||||
|
||||
|
||||
class BannerControls(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(BannerControls, self).__init__()
|
||||
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(0)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
# styles_chooser_button = GtkSource.StyleSchemeChooserButton()
|
||||
|
||||
self.add(ToggleLineHighlight())
|
||||
# self.add(styles_chooser_button)
|
||||
self.add(ScaleUpButton())
|
||||
self.add(ScaleDownButton())
|
|
@ -0,0 +1,57 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..tab_header_widget import TabHeaderWidget
|
||||
from .source_view import SourceView
|
||||
|
||||
|
||||
|
||||
class EditorNotebook(Gtk.Notebook):
|
||||
def __init__(self):
|
||||
super(EditorNotebook, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
...
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.create_view()
|
||||
|
||||
def create_view(self):
|
||||
scroll_view = Gtk.ScrolledWindow()
|
||||
source_view = SourceView()
|
||||
tab_widget = TabHeaderWidget(scroll_view, source_view, self.close_tab)
|
||||
scroll_view.add(source_view)
|
||||
|
||||
index = self.append_page(scroll_view, tab_widget)
|
||||
self.set_tab_detachable(scroll_view, True)
|
||||
self.set_current_page(index)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("notebook-unselected-focus")
|
||||
self.set_tab_reorderable(scroll_view, True)
|
||||
|
||||
def close_tab(self, button, scroll_view, source_view, eve=None):
|
||||
if self.get_n_pages() == 1:
|
||||
return
|
||||
|
||||
page_num = self.page_num(scroll_view)
|
||||
watcher = source_view.get_file_watcher()
|
||||
if watcher:
|
||||
watcher.cancel()
|
||||
|
||||
self.remove_page(page_num)
|
|
@ -0,0 +1,94 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class SourceView(GtkSource.View):
|
||||
def __init__(self):
|
||||
super(SourceView, self).__init__()
|
||||
|
||||
self._language_manager = GtkSource.LanguageManager()
|
||||
self._style_scheme_manager = GtkSource.StyleSchemeManager()
|
||||
self._general_style_tag = None
|
||||
|
||||
self._buffer = self.get_buffer()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_show_line_marks(True)
|
||||
self.set_show_line_numbers(True)
|
||||
self.set_smart_backspace(True)
|
||||
self.set_indent_on_tab(True)
|
||||
self.set_insert_spaces_instead_of_tabs(True)
|
||||
self.set_auto_indent(True)
|
||||
self.set_monospace(True)
|
||||
self.set_tab_width(4)
|
||||
# self.set_show_right_margin(True)
|
||||
# self.set_right_margin_position(80)
|
||||
self.set_background_pattern(0) # 0 = None, 1 = Grid
|
||||
|
||||
self._set_buffer_language()
|
||||
self._set_buffer_style()
|
||||
self._create_default_tag()
|
||||
|
||||
self.set_vexpand(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("set_buffer_language", self._set_buffer_language)
|
||||
event_system.subscribe("set_buffer_style", self._set_buffer_style)
|
||||
event_system.subscribe("toggle_highlight_line", self.toggle_highlight_line)
|
||||
event_system.subscribe("scale_up_text", self.scale_up_text)
|
||||
event_system.subscribe("scale_down_text", self.scale_down_text)
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _create_default_tag(self):
|
||||
self._general_style_tag = self._buffer.create_tag('general_style')
|
||||
self._general_style_tag.set_property('size', 100)
|
||||
self._general_style_tag.set_property('scale', 100)
|
||||
|
||||
def _set_buffer_language(self, language = "python3"):
|
||||
self._buffer.set_language( self._language_manager.get_language(language) )
|
||||
|
||||
def _set_buffer_style(self, style = "tango"):
|
||||
self._buffer.set_style_scheme( self._style_scheme_manager.get_scheme(style) )
|
||||
|
||||
def get_file_watcher(self):
|
||||
return None
|
||||
|
||||
|
||||
def toggle_highlight_line(self, widget=None, eve=None):
|
||||
self.set_highlight_current_line( not self.get_highlight_current_line() )
|
||||
|
||||
def scale_up_text(self, scale_step = 10):
|
||||
current_scale = self._general_style_tag.get_property('scale')
|
||||
start_itr = self._buffer.get_start_iter()
|
||||
end_itr = self._buffer.get_end_iter()
|
||||
|
||||
self._general_style_tag.set_property('scale', current_scale + scale_step)
|
||||
self._buffer.apply_tag(self._general_style_tag, start_itr, end_itr)
|
||||
|
||||
def scale_down_text(self, scale_step = 10):
|
||||
tag_table = self._buffer.get_tag_table()
|
||||
start_itr = self._buffer.get_start_iter()
|
||||
end_itr = self._buffer.get_end_iter()
|
||||
tag = tag_table.lookup('general_style')
|
||||
|
||||
tag.set_property('scale', tag.get_property('scale') - scale_step)
|
||||
self._buffer.apply_tag(tag, start_itr, end_itr)
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Widgets.Controls Module
|
||||
"""
|
|
@ -0,0 +1,35 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class ScaleDownButton(Gtk.Button):
|
||||
def __init__(self):
|
||||
super(ScaleDownButton, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_label("Zoom Out (-)")
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("released", self._emit_scale_eve)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _emit_scale_eve(self, widget, eve = None):
|
||||
event_system.emit('scale_down_text')
|
|
@ -0,0 +1,35 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class ScaleUpButton(Gtk.Button):
|
||||
def __init__(self):
|
||||
super(ScaleUpButton, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_label("Zoom In (+)")
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("released", self._emit_scale_eve)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _emit_scale_eve(self, widget, eve = None):
|
||||
event_system.emit('scale_up_text')
|
|
@ -0,0 +1,34 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
class ToggleLineHighlight(Gtk.ToggleButton):
|
||||
def __init__(self):
|
||||
super(ToggleLineHighlight, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_label("Toggle Line Highlight")
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("released", self._emit_toggle_eve)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _emit_toggle_eve(self, widget, eve = None):
|
||||
event_system.emit('toggle_highlight_line')
|
|
@ -0,0 +1,60 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class TabHeaderWidget(Gtk.ButtonBox):
|
||||
"""docstring for TabHeaderWidget"""
|
||||
|
||||
ccount = 0
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
obj = super(TabHeaderWidget, cls).__new__(cls)
|
||||
cls.ccount += 1
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
# def __init__(self, tab, close_tab):
|
||||
def __init__(self, scroll_view, source_view, close_tab):
|
||||
super(TabHeaderWidget, self).__init__()
|
||||
|
||||
self.INDEX = self.ccount
|
||||
self.NAME = f"tab_{self.INDEX}"
|
||||
self._scroll_view = scroll_view
|
||||
self._source_view = source_view
|
||||
self._close_tab = close_tab # NOTE: Close method in tab_mixin
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(0)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
label = Gtk.Label()
|
||||
close = Gtk.Button()
|
||||
icon = Gtk.Image(stock=Gtk.STOCK_CLOSE)
|
||||
|
||||
label.set_label(f"{self.NAME}")
|
||||
label.set_width_chars(len(self.NAME))
|
||||
label.set_xalign(0.0)
|
||||
|
||||
close.connect("released", self._close_tab, *(self._scroll_view, self._source_view,))
|
||||
|
||||
close.add(icon)
|
||||
self.add(label)
|
||||
self.add(close)
|
||||
|
||||
self.show_all()
|
|
@ -83,7 +83,7 @@ class Window(Gtk.ApplicationWindow):
|
|||
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
||||
cr.set_source_rgba(0, 0, 0, 0.54)
|
||||
cr.set_source_rgba( *settings.get_paint_bg_color() )
|
||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
cr.set_operator(cairo.OPERATOR_OVER)
|
||||
|
|
|
@ -29,7 +29,7 @@ class Settings(StartCheckMixin):
|
|||
self._CSS_FILE = f"{self._HOME_CONFIG_PATH}/stylesheet.css"
|
||||
self._KEY_BINDINGS_FILE = f"{self._HOME_CONFIG_PATH}/key-bindings.json"
|
||||
self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{app_name.lower()}.pid"
|
||||
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/icons/{app_name.lower()}.png"
|
||||
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png"
|
||||
|
||||
if not os.path.exists(self._HOME_CONFIG_PATH):
|
||||
os.mkdir(self._HOME_CONFIG_PATH)
|
||||
|
@ -73,6 +73,7 @@ class Settings(StartCheckMixin):
|
|||
self._main_window_w = 800
|
||||
self._main_window_h = 600
|
||||
self._builder = None
|
||||
self.PAINT_BG_COLOR = (0, 0, 0, 0.54)
|
||||
|
||||
self._trace_debug = False
|
||||
self._debug = False
|
||||
|
@ -108,9 +109,10 @@ class Settings(StartCheckMixin):
|
|||
return monitors
|
||||
|
||||
def get_main_window(self) -> any: return self._main_window
|
||||
def get_main_window_width(self) -> Gtk.ApplicationWindow: return self._main_window_w
|
||||
def get_main_window_height(self) -> Gtk.ApplicationWindow: return self._main_window_h
|
||||
def get_main_window_width(self) -> any: return self._main_window_w
|
||||
def get_main_window_height(self) -> any: return self._main_window_h
|
||||
def get_builder(self) -> any: return self._builder
|
||||
def get_paint_bg_color(self) -> any: return self.PAINT_BG_COLOR
|
||||
def get_glade_file(self) -> str: return self._GLADE_FILE
|
||||
|
||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||
|
|
|
@ -19,11 +19,11 @@ function main() {
|
|||
|
||||
# NOTE: Remove if you want to pass file(s) besides directories...
|
||||
if [ ! -d "${path}" ]; then
|
||||
echo "<change_me>: Path given not a directory..."
|
||||
echo "Newton Editor: Path given not a directory..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "/opt/"
|
||||
python /opt/<change_me>.zip "$@"
|
||||
python /opt/newton_editor.zip "$@"
|
||||
}
|
||||
main "$@";
|
|
@ -1,11 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=<change_me>
|
||||
GenericName=<change_me>
|
||||
Comment=<change_me>
|
||||
Exec=/bin/<change_me> %F
|
||||
Icon=/usr/share/<change_me>/icons/<change_me>.png
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=System;FileTools;Utility;Core;GTK;FileManager;
|
||||
MimeType=
|
||||
Terminal=false
|
|
@ -0,0 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Name=Newton Editor
|
||||
GenericName=Code IDE
|
||||
Comment=General purpose IDE
|
||||
Exec=/bin/newton_editor %F
|
||||
Icon=/usr/share/newton_editor/icons/newton_editor.png
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=System;FileTools;Utility;
|
||||
MimeType=
|
||||
Terminal=false
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 858 B |
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 702 B |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
Before Width: | Height: | Size: 798 B After Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 989 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |