Compare commits

..

2 Commits

Author SHA1 Message Date
Juan Pablo Ugarte
fa89006ff2 Super massive commit to port to Gtk 4
Fix issue #40 "Update GUI to GTK 4"
2024-02-06 17:08:19 -05:00
Juan Pablo Ugarte
15b8ecf3d8 CmbDB: add support to load properties and signals from project. 2024-02-04 22:32:02 -05:00
15 changed files with 219 additions and 238 deletions

View File

@ -52,6 +52,11 @@ popover.cmb-tutor label {
font-weight: bold; font-weight: bold;
} }
popover.cmb-tutor image {
padding-right: 1em;
-gtk-icon-size: 48px;
}
button.cmb-tutor-highlight, button.cmb-tutor-highlight,
modelbutton.cmb-tutor-highlight, modelbutton.cmb-tutor-highlight,
buttonbox.cmb-tutor-highlight > button, buttonbox.cmb-tutor-highlight > button,

View File

@ -141,10 +141,16 @@ class CmbTutor(GObject.GObject):
def __popover_new(self, text): def __popover_new(self, text):
popover = Gtk.Popover(autohide=False) popover = Gtk.Popover(autohide=False)
popover.add_css_class("cmb-tutor") popover.add_css_class("cmb-tutor")
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, hexpand=True)
box.append(Gtk.Image(icon_name="dialog-information-symbolic", icon_size=Gtk.IconSize.LARGE)) box.append(Gtk.Image(icon_name="dialog-information-symbolic"))
box.append(Gtk.Label(label=text, wrap=True, max_width_chars=28)) box.append(Gtk.Label(
label=text,
vexpand=False,
hexpand=True,
wrap=True,
max_width_chars=24
))
popover.set_child(box) popover.set_child(box)
return popover return popover

View File

@ -25,44 +25,44 @@ from .cmb_tutor import CmbTutorPosition
from cambalache import _ from cambalache import _
intro = [ intro = [
# (_("Hi, I will show you around Cambalache"), "intro_button", 5), (_("Hi, I will show you around Cambalache"), "intro_button", 5),
# (_("You can open a project"), "open_button", 3), (_("You can open a project"), "open_button", 3),
# ( (
# _("find recently used"), _("find recently used"),
# "recent_button", "recent_button",
# 2, 2,
# ), ),
# (_("or create a new one"), "new_button", 4), (_("or create a new one"), "new_button", 4),
# (_("Common actions like Undo"), "undo_button", 4), (_("Common actions like Undo"), "undo_button", 4),
# (_("Redo"), "redo_button", 2), (_("Redo"), "redo_button", 2),
# (_("Add new UI file"), "add_button", 3), (_("Add new UI file"), "add_button", 3),
# (_("and Save are directly accessible in the headerbar"), "cmb_save_button", 6), (_("and Save are directly accessible in the headerbar"), "cmb_save_button", 6),
# (_("just like Save As"), "save_as_button", 2), (_("just like Save As"), "save_as_button", 2),
# (_("and the main menu"), "menu_button", 3, "main-menu"), (_("and the main menu"), "menu_button", 3, "menu_button"),
# (_("Create a project to continue"), "intro_button", 2, "add-project"), (_("Create a project to continue"), "intro_button", 2, "add-project"),
# (_("Great!"), "intro_button", 2), (_("Great!"), "intro_button", 2),
# ( (
# _("This is the project workspace, where you can see and select the widgets to edit"), _("This is the project workspace, where you can see and select the widgets to edit"),
# "view", "view",
# 6, 6,
# None, None,
# CmbTutorPosition.CENTER, CmbTutorPosition.CENTER,
# ), ),
# (_("Project tree, with multiple UI support"), "tree_view", 4, None, CmbTutorPosition.CENTER), (_("Project tree, with multiple UI support"), "tree_view", 4, None, CmbTutorPosition.CENTER),
# ( (
# _("Class selector bar"), _("Class selector bar"),
# "type_chooser_box", "type_chooser_box",
# 3, 3,
# ), ),
# (_("And the object editor"), "editor_stack", 3, None, CmbTutorPosition.CENTER), (_("And the object editor"), "editor_stack", 3, None, CmbTutorPosition.CENTER),
# (_("You can search all supported classes here"), "type_chooser_all", 4, "show-type-popover", CmbTutorPosition.LEFT), (_("You can search all supported classes here"), "type_chooser_all", 4, "show-type-popover", CmbTutorPosition.LEFT),
# (_("or investigate what is in each group"), "type_chooser_gtk", 4, "show-type-popover-gtk", CmbTutorPosition.LEFT), (_("or investigate what is in each group"), "type_chooser_gtk", 4, "show-type-popover-gtk", CmbTutorPosition.LEFT),
# (_("Now let's add a new UI file"), "add_button", 5, "add-ui"), (_("Now let's add a new UI file"), "add_button", 5, "add-ui"),
# (_("Good, now try to create a window"), "intro_button", 4, "add-window"), (_("Good, now try to create a window"), "intro_button", 4, "add-window"),
# (_("Excellent!"), "intro_button", 2), (_("Excellent!"), "intro_button", 2),
# (_("BTW, did you know you can double click on any placeholder to create widgets?"), "intro_button", 5), (_("BTW, did you know you can double click on any placeholder to create widgets?"), "intro_button", 5),
# (_("Try adding a grid"), "intro_button", 3, "add-grid"), (_("Try adding a grid"), "intro_button", 3, "add-grid"),
# (_("and a button"), "intro_button", 3, "add-button"), (_("and a button"), "intro_button", 3, "add-button"),
(_("Quite easy! Isn't it?"), "intro_button", 3), (_("Quite easy! Isn't it?"), "intro_button", 3),
( (
_("Once you finish, you can export all UI files to xml here"), _("Once you finish, you can export all UI files to xml here"),

View File

@ -49,6 +49,7 @@ class CmbWindow(Gtk.ApplicationWindow):
headerbar = Gtk.Template.Child() headerbar = Gtk.Template.Child()
subtitle = Gtk.Template.Child() subtitle = Gtk.Template.Child()
recent_menu = Gtk.Template.Child()
undo_button = Gtk.Template.Child() undo_button = Gtk.Template.Child()
redo_button = Gtk.Template.Child() redo_button = Gtk.Template.Child()
stack = Gtk.Template.Child() stack = Gtk.Template.Child()
@ -148,8 +149,12 @@ class CmbWindow(Gtk.ApplicationWindow):
# Stateful actions # Stateful actions
for action, parameter_type, state in [ for action, parameter_type, state in [
("open_recent", "s", None),
("workspace_theme", "s", "") ("workspace_theme", "s", "")
]: ]:
if state is None:
gaction = Gio.SimpleAction.new(action, GLib.VariantType.new(parameter_type))
else:
gaction = Gio.SimpleAction.new_stateful( gaction = Gio.SimpleAction.new_stateful(
action, action,
GLib.VariantType.new(parameter_type), GLib.VariantType.new(parameter_type),
@ -256,6 +261,8 @@ class CmbWindow(Gtk.ApplicationWindow):
) )
self.view.connect("notify::gtk-theme", self.__on_view_gtk_theme_notify) self.view.connect("notify::gtk-theme", self.__on_view_gtk_theme_notify)
self.connect("notify::focus-widget", self.__on_focus_widget_notify)
self.__update_recent_menu()
def __on_view_gtk_theme_notify(self, obj, pspec): def __on_view_gtk_theme_notify(self, obj, pspec):
print("__on_view_gtk_theme_notify", obj.props.gtk_theme) print("__on_view_gtk_theme_notify", obj.props.gtk_theme)
@ -362,14 +369,6 @@ class CmbWindow(Gtk.ApplicationWindow):
) )
popover.popup() popover.popup()
# FIXME: GTK4
#@Gtk.Template.Callback("on_open_recent_action_item_activated")
def __on_open_recent_action_item_activated(self, recent):
uri = recent.get_current_uri()
if uri is not None:
filename, host = GLib.filename_from_uri(uri)
self.emit("open-project", filename, None, None)
@Gtk.Template.Callback("on_ui_editor_remove_ui") @Gtk.Template.Callback("on_ui_editor_remove_ui")
def __on_ui_editor_remove_ui(self, editor): def __on_ui_editor_remove_ui(self, editor):
self.__remove_object_with_confirmation(editor.object) self.__remove_object_with_confirmation(editor.object)
@ -380,10 +379,10 @@ class CmbWindow(Gtk.ApplicationWindow):
self.__remove_object_with_confirmation(editor.object) self.__remove_object_with_confirmation(editor.object)
return True return True
# FIXME: GTK4 def __on_focus_widget_notify(self, obj, pspec):
#@Gtk.Template.Callback("on_window_set_focus") widget = self.props.focus_widget
def __on_window_set_focus(self, window, widget):
types = [Gtk.Entry, Gtk.TextView, Gtk.SpinButton] types = [Gtk.Text, Gtk.TextView]
focused_widget_needs = True focused_widget_needs = True
for type in types: for type in types:
@ -434,8 +433,10 @@ class CmbWindow(Gtk.ApplicationWindow):
# If foreground luminance is closer to 1 then the background must be dark # If foreground luminance is closer to 1 then the background must be dark
if luminance(fg) > 0.5: if luminance(fg) > 0.5:
self.add_css_class("dark") self.add_css_class("dark")
self.view._set_dark_mode(True)
else: else:
self.remove_css_class("dark") self.remove_css_class("dark")
self.view._set_dark_mode(False)
def __np_name_to_ui(self, binding, value): def __np_name_to_ui(self, binding, value):
if len(value): if len(value):
@ -1037,7 +1038,7 @@ class CmbWindow(Gtk.ApplicationWindow):
self.project.connect("object-added", self.__on_object_added, "GtkGrid") self.project.connect("object-added", self.__on_object_added, "GtkGrid")
elif node == "add-button": elif node == "add-button":
self.project.connect("object-added", self.__on_object_added, "GtkButton") self.project.connect("object-added", self.__on_object_added, "GtkButton")
elif node == "main-menu": elif node in ["menu_button", "main-menu"]:
self.menu_button.popup() self.menu_button.popup()
elif node == "show-type-popover": elif node == "show-type-popover":
widget.props.popover.popup() widget.props.popover.popup()
@ -1056,7 +1057,7 @@ class CmbWindow(Gtk.ApplicationWindow):
elif node in ["add-ui", "add-window", "add-grid", "add-button"]: elif node in ["add-ui", "add-window", "add-grid", "add-button"]:
self.tutor_waiting_for_user_action = True self.tutor_waiting_for_user_action = True
self.tutor.pause() self.tutor.pause()
elif node == "donate": elif node in ["menu_button", "donate"]:
self.menu_button.popdown() self.menu_button.popdown()
elif node == "show-type-popover": elif node == "show-type-popover":
widget.props.popover.popdown() widget.props.popover.popdown()
@ -1097,6 +1098,29 @@ class CmbWindow(Gtk.ApplicationWindow):
def _on_inspect_activate(self, action, data): def _on_inspect_activate(self, action, data):
self.view.inspect() self.view.inspect()
def _on_open_recent_activate(self, action, data):
self.emit("open-project", data.get_string(), None, None)
def __update_recent_menu(self):
manager = Gtk.RecentManager.get_default()
mime_types = [
"application/x-cambalache-project"
]
for recent in manager.get_items():
if recent.get_mime_type() not in mime_types:
continue
filename, host = GLib.filename_from_uri(recent.get_uri())
if not os.path.exists(filename):
continue
item = Gio.MenuItem()
item.set_label(recent.get_display_name())
item.set_action_and_target_value("win.open_recent", GLib.Variant("s", filename))
self.recent_menu.append_item(item)
def __load_window_state(self): def __load_window_state(self):
state = self.window_settings.get_uint("state") state = self.window_settings.get_uint("state")

View File

@ -59,6 +59,7 @@
</item> </item>
</section> </section>
</menu> </menu>
<menu id="recent_menu"/>
<object class="GtkFileFilter" id="open_filter"> <object class="GtkFileFilter" id="open_filter">
<mime-types> <mime-types>
<mime-type>application/x-cambalache-project</mime-type> <mime-type>application/x-cambalache-project</mime-type>
@ -321,6 +322,7 @@
<property name="start-child"> <property name="start-child">
<object class="GtkBox" id="inspector"> <object class="GtkBox" id="inspector">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="focusable">1</property>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="vexpand">1</property> <property name="vexpand">1</property>
@ -330,11 +332,9 @@
<property name="propagate-natural-height">1</property> <property name="propagate-natural-height">1</property>
<child> <child>
<object class="CmbTreeView" id="tree_view"> <object class="CmbTreeView" id="tree_view">
<property name="focusable">1</property>
<property name="headers-visible">False</property> <property name="headers-visible">False</property>
<property name="headers-clickable">False</property> <property name="headers-clickable">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
</object> </object>
</child> </child>
</object> </object>
@ -434,11 +434,6 @@
<property name="title" translatable="1">Signals</property> <property name="title" translatable="1">Signals</property>
<property name="child"> <property name="child">
<object class="CmbSignalEditor" id="signal_editor"> <object class="CmbSignalEditor" id="signal_editor">
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="margin-bottom">4</property>
<property name="orientation">vertical</property>
<property name="spacing">4</property>
</object> </object>
</property> </property>
</object> </object>
@ -449,10 +444,6 @@
<property name="title" translatable="0">&lt;/&gt;</property> <property name="title" translatable="0">&lt;/&gt;</property>
<property name="child"> <property name="child">
<object class="CmbFragmentEditor" id="fragment_editor"> <object class="CmbFragmentEditor" id="fragment_editor">
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="margin-bottom">4</property>
<property name="orientation">vertical</property>
</object> </object>
</property> </property>
</object> </object>
@ -742,8 +733,7 @@
</child> </child>
<child> <child>
<object class="GtkMenuButton" id="recent_button"> <object class="GtkMenuButton" id="recent_button">
<property name="focusable">1</property> <property name="menu-model">recent_menu</property>
<property name="receives-default">1</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="icon-name">pan-down-symbolic</property> <property name="icon-name">pan-down-symbolic</property>
@ -752,6 +742,7 @@
</object> </object>
</child> </child>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkButton" id="new_button"> <object class="GtkButton" id="new_button">

View File

@ -34,9 +34,10 @@ class CmbContextMenu(Gtk.PopoverMenu):
target_tk = GObject.Property(type=str, flags=GObject.ParamFlags.READWRITE) target_tk = GObject.Property(type=str, flags=GObject.ParamFlags.READWRITE)
main_section = Gtk.Template.Child() main_section = Gtk.Template.Child()
theme_submenu = Gtk.Template.Child()
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.theme_submenu = None
super().__init__(**kwargs) super().__init__(**kwargs)
self.connect("notify::target-tk", lambda o, p: self.__populate_css_theme_box()) self.connect("notify::target-tk", lambda o, p: self.__populate_css_theme_box())
@ -54,6 +55,9 @@ class CmbContextMenu(Gtk.PopoverMenu):
else: else:
themes = ["Adwaita", "HighContrast", "HighContrastInverse"] themes = ["Adwaita", "HighContrast", "HighContrastInverse"]
if self.theme_submenu is None:
self.theme_submenu = Gio.Menu()
self.main_section.prepend_submenu(_("CSS theme"), self.theme_submenu)
# Remove all items from theme submenu # Remove all items from theme submenu
self.theme_submenu.remove_all() self.theme_submenu.remove_all()
@ -88,3 +92,9 @@ class CmbContextMenu(Gtk.PopoverMenu):
item.set_action_and_target_value("win.workspace_theme", GLib.Variant("s", theme)) item.set_action_and_target_value("win.workspace_theme", GLib.Variant("s", theme))
self.theme_submenu.append_item(item) self.theme_submenu.append_item(item)
def popup_at(self, x, y):
r = Gdk.Rectangle()
r.x, r.y = (x, y)
r.width = r.height = 0
self.set_pointing_to(r)
self.popup()

View File

@ -38,11 +38,7 @@
<attribute name="label" translatable="1">Read Documentation</attribute> <attribute name="label" translatable="1">Read Documentation</attribute>
</item> </item>
</section> </section>
<section id="main_section"> <section id="main_section"/>
<submenu id="theme_submenu">
<attribute name="label" translatable="1">CSS theme</attribute>
</submenu>
</section>
</menu> </menu>
<template class="CmbContextMenu" parent="GtkPopoverMenu"> <template class="CmbContextMenu" parent="GtkPopoverMenu">
<property name="menu-model">menu_model</property> <property name="menu-model">menu_model</property>

View File

@ -618,8 +618,8 @@ class CmbDB(GObject.GObject):
return f"\t({r})" return f"\t({r})"
def _dump_table(c, table): def _dump_query(c, query):
c.execute(f"SELECT * FROM {table};") c.execute(query)
row = c.fetchone() row = c.fetchone()
if row is None: if row is None:
@ -635,20 +635,27 @@ class CmbDB(GObject.GObject):
return f"\n{retval}\n " return f"\n{retval}\n "
def append_data(project, name, data):
if data is None:
return
element = etree.Element(name)
element.text = data
project.append(element)
self.conn.commit() self.conn.commit()
c = self.conn.cursor() c = self.conn.cursor()
project = E("cambalache-project", version=config.FILE_FORMAT_VERSION, target_tk=self.target_tk) project = E("cambalache-project", version=config.FILE_FORMAT_VERSION, target_tk=self.target_tk)
for table in self.__tables: for table in self.__tables:
data = _dump_table(c, table) data = _dump_query(c, f"SELECT * FROM {table};")
append_data(project, table, data)
if data is None: # DUMP custom properties and signals
continue for table in ["property", "signal"]:
data = _dump_query(c, f"SELECT {table}.* FROM {table},type WHERE {table}.owner_id == type.type_id AND type.library_id IS NULL;")
element = etree.Element(table) append_data(project, table, data)
element.text = data
project.append(element)
# Dump xml to file # Dump xml to file
with open(filename, "wb") as fd: with open(filename, "wb") as fd:

View File

@ -40,7 +40,6 @@ class CmbTreeView(Gtk.TreeView):
self.__in_selection_change = False self.__in_selection_change = False
self._selection.connect("changed", self.__on_selection_changed) self._selection.connect("changed", self.__on_selection_changed)
self.set_headers_visible(False) self.set_headers_visible(False)
self.__right_click = False
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Object(Type)", renderer) column = Gtk.TreeViewColumn("Object(Type)", renderer)
@ -50,31 +49,14 @@ class CmbTreeView(Gtk.TreeView):
self.connect("notify::model", self.__on_model_notify) self.connect("notify::model", self.__on_model_notify)
self.connect("row-activated", self.__on_row_activated) self.connect("row-activated", self.__on_row_activated)
self.menu = CmbContextMenu() gesture = Gtk.GestureClick(button=3)
gesture.connect("pressed", self.__on_button_press)
# FIXME: GTK4 self.add_controller(gesture)
#self.connect("button-press-event", self.__on_button_press_event)
#self.connect("button-release-event", self.__on_button_release_event)
self.set_reorderable(True) self.set_reorderable(True)
def __on_button_press_event(self, widget, event): def __on_button_press(self, widget, npress, x, y):
if event.window != self.get_bin_window() or event.button != 3: retval = self.get_path_at_pos(x, y)
return False
self.__right_click = True
return True
def __on_button_release_event(self, widget, event):
if event.window != self.get_bin_window() or event.button != 3:
return False
if not self.__right_click:
return False
self.__right_click = False
retval = self.get_path_at_pos(event.x, event.y)
if retval is None: if retval is None:
return False return False
@ -82,7 +64,12 @@ class CmbTreeView(Gtk.TreeView):
path, col, xx, yy = retval path, col, xx, yy = retval
self.get_selection().select_path(path) self.get_selection().select_path(path)
self.menu.popup_at(event.x, event.y) menu = CmbContextMenu()
# Use parent instead of self to avoid warning and focus not working properly
# (run-dev.py:188589): Gtk-CRITICAL **: 16:45:12.790: gtk_css_node_insert_after: assertion 'previous_sibling == NULL || previous_sibling->parent == parent' failed
menu.set_parent(self.props.parent)
menu.popup_at(x, y)
return True return True

View File

@ -75,7 +75,6 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="width-chars">16</property>
<property name="placeholder-text" translatable="1">&lt;translation domain&gt;</property> <property name="placeholder-text" translatable="1">&lt;translation domain&gt;</property>
<layout> <layout>
<property name="column">1</property> <property name="column">1</property>

View File

@ -131,6 +131,7 @@ class CmbView(Gtk.Box):
self.__restart_project = None self.__restart_project = None
self.__ui_id = 0 self.__ui_id = 0
self.__theme = None self.__theme = None
self.__dark = False
self.menu = self.__create_context_menu() self.menu = self.__create_context_menu()
@ -147,10 +148,6 @@ class CmbView(Gtk.Box):
self.__port = None self.__port = None
self.__merengue_last_exit = None self.__merengue_last_exit = None
# FIXME: GTK4
#context = self.get_style_context()
#context.connect("changed", lambda ctx: self.__update_webview_bg())
if self.__broadwayd_bin is None: if self.__broadwayd_bin is None:
logger.warning("broadwayd not found, Gtk 3 workspace wont work.") logger.warning("broadwayd not found, Gtk 3 workspace wont work.")
@ -169,21 +166,15 @@ class CmbView(Gtk.Box):
def __evaluate_js(self, script): def __evaluate_js(self, script):
self.webview.evaluate_javascript(script, -1, None, None, None, None, None, None) self.webview.evaluate_javascript(script, -1, None, None, None, None, None, None)
def __update_webview_bg(self): def _set_dark_mode(self, dark):
context = self.get_style_context() self.__dark = dark
self.__evaluate_js(f"document.body.style.background = '{'#222' if dark else 'inherit'}';")
# FIXME: GTK4
# with warnings.catch_warnings():
# warnings.filterwarnings("ignore", category=DeprecationWarning)
# bg = context.get_background_color(Gtk.StateFlags.NORMAL)
# self.__evaluate_js(f"document.body.style.background = '{bg.to_string()}';")
def __on_load_changed(self, webview, event): def __on_load_changed(self, webview, event):
if event != WebKit.LoadEvent.FINISHED: if event != WebKit.LoadEvent.FINISHED:
return return
self.__update_webview_bg() self._set_dark_mode(self.__dark)
# Disable alert() function used when broadwayd get disconnected # Disable alert() function used when broadwayd get disconnected
# Monkey pat ch setupDocument() to avoid disabling document.oncontextmenu # Monkey pat ch setupDocument() to avoid disabling document.oncontextmenu
@ -463,11 +454,9 @@ window.setupDocument = function (document) {
self.__theme = theme self.__theme = theme
self.__merengue_command("gtk_settings_set", args={"property": "gtk-theme-name", "value": theme}) self.__merengue_command("gtk_settings_set", args={"property": "gtk-theme-name", "value": theme})
# FIXME: GTK4
@Gtk.Template.Callback("on_context_menu") @Gtk.Template.Callback("on_context_menu")
def __on_context_menu(self, webview, menu, hit_test_result): def __on_context_menu(self, webview, menu, hit_test_result):
self.menu.set_pointing_to(utils.get_pointing_to(self)) self.menu.popup_at(*utils.get_pointer(self))
self.menu.popup()
return True return True
def __webview_set_msg(self, msg): def __webview_set_msg(self, msg):

View File

@ -24,7 +24,7 @@
import os import os
from cambalache import _ from cambalache import _
from gi.repository import GdkPixbuf, GObject, Gdk, Gtk, Pango from gi.repository import GLib, Gio, GdkPixbuf, GObject, Gdk, Gtk, Pango
from .cmb_entry import CmbEntry from .cmb_entry import CmbEntry
from .icon_naming_spec import standard_icon_context, standard_icon_names from .icon_naming_spec import standard_icon_context, standard_icon_names
@ -48,6 +48,8 @@ class CmbIconNameEntry(CmbEntry):
# Model, store it in a Python class variable to share between all instances # Model, store it in a Python class variable to share between all instances
icon_model = None icon_model = None
iconlist = []
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._filters = {} self._filters = {}
@ -92,33 +94,55 @@ class CmbIconNameEntry(CmbEntry):
iconlist = [] iconlist = []
theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
# FIXME: GTK4
# print(theme.get_icon_names())
# for context in theme.list_contexts(): # FIXME: get the context/category of each icon
# for icon in theme.list_icons(context): for icon in theme.get_icon_names():
# iconlist.append((icon, context, icon in standard_icon_names)) iconlist.append((icon, "cmb_all", icon in standard_icon_names))
# for icon, context, standard in sorted(iconlist, key=lambda i: i[0].lower()): for icon, context, standard in sorted(iconlist, key=lambda i: i[0].lower()):
# if icon.endswith(".symbolic"): if icon.endswith(".symbolic"):
# continue continue
# info = theme.lookup_icon(icon, 32, Gtk.IconLookupFlags.FORCE_SIZE) icon_paintable = theme.lookup_icon(icon, None, 32, 1, Gtk.TextDirection.NONE, Gtk.IconLookupFlags.PRELOAD)
# symbolic = info.is_symbolic() symbolic = icon_paintable.is_symbolic()
# if not os.path.exists(info.get_filename()): icon_file = icon_paintable.get_file()
# continue if icon_file is None:
continue
# standard_symbolic = symbolic and icon.removesuffix("-symbolic") in standard_icon_names icon_path = icon_file.get_path()
if icon_path is None or not os.path.exists(icon_path):
continue
# iter = cls.icon_model.append( standard_symbolic = symbolic and icon.removesuffix("-symbolic") in standard_icon_names
# [icon, icon if standard else f"<i>{icon}</i>", context, standard, symbolic, standard_symbolic, None]
# ) try:
# info.load_icon_async(None, cls.__load_icon_finish, iter) iter = cls.icon_model.append(
[icon, icon if standard else f"<i>{icon}</i>", context, standard, symbolic, standard_symbolic, None]
)
cls.iconlist.append((icon_file, iter))
except Exception as e:
print(e)
# Kickoff async loading
file, iter = cls.iconlist.pop()
file.read_async(GLib.PRIORITY_DEFAULT, None, cls.__load_file_finish, iter)
@classmethod @classmethod
def __load_icon_finish(cls, info, res, data): def __load_file_finish(cls, obj, res, iter):
cls.icon_model[data][6] = info.load_icon_finish(res) stream = obj.read_finish(res)
GdkPixbuf.Pixbuf.new_from_stream_at_scale_async(stream, 32, 32, True, None, cls.__load_icon_finish, iter)
@classmethod
def __load_icon_finish(cls, obj, res, iter):
try:
cls.icon_model[iter][cls.COL_PIXBUF] = GdkPixbuf.Pixbuf.new_from_stream_finish(res)
except Exception as e:
print(e)
if len(cls.iconlist):
file, iter = cls.iconlist.pop()
file.read_async(GLib.PRIORITY_DEFAULT, None, cls.__load_file_finish, iter)
def __model_filter_func(self, model, iter, data): def __model_filter_func(self, model, iter, data):
if self.standard_only and self.symbolic_only: if self.standard_only and self.symbolic_only:
@ -151,6 +175,8 @@ class CmbIconNameEntry(CmbEntry):
def __on_icon_pressed(self, widget, icon_pos): def __on_icon_pressed(self, widget, icon_pos):
# Create popover with icon chooser # Create popover with icon chooser
popover = Gtk.Popover() popover = Gtk.Popover()
popover.set_parent(self)
hbox = Gtk.Box(visible=True) hbox = Gtk.Box(visible=True)
vbox = Gtk.Box(visible=True, orientation=Gtk.Orientation.VERTICAL, vexpand=True) vbox = Gtk.Box(visible=True, orientation=Gtk.Orientation.VERTICAL, vexpand=True)
stack = Gtk.Stack(visible=True, transition_type=Gtk.StackTransitionType.CROSSFADE) stack = Gtk.Stack(visible=True, transition_type=Gtk.StackTransitionType.CROSSFADE)
@ -159,9 +185,10 @@ class CmbIconNameEntry(CmbEntry):
hbox.append(vbox) hbox.append(vbox)
hbox.append(stack) hbox.append(stack)
theme = Gtk.IconTheme.get_default() theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
sorted_contexts = sorted(theme.list_contexts()) # sorted_contexts = sorted(theme.list_contexts())
sorted_contexts = []
sorted_contexts.insert(0, "cmb_all") sorted_contexts.insert(0, "cmb_all")
# Add one icon view per context # Add one icon view per context

View File

@ -39,9 +39,8 @@ class CmbToplevelChooser(Gtk.ComboBox):
self.connect("changed", self.__on_changed) self.connect("changed", self.__on_changed)
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
# FIXME: GTK4 self.pack_start(renderer, True)
#self.pack_start(renderer, True) self.set_cell_data_func(renderer, self.__name_cell_data_func, None)
#self.set_cell_data_func(renderer, self.__name_cell_data_func, None)
def __name_cell_data_func(self, column, cell, model, iter_, data): def __name_cell_data_func(self, column, cell, model, iter_, data):
obj = model.get_value(iter_, 0) obj = model.get_value(iter_, 0)

View File

@ -1,13 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<object class="GtkTextBuffer" id="buffer_comments"/> <object class="GtkTextBuffer" id="buffer_comments"/>
<object class="GtkTextBuffer" id="buffer_context"/> <object class="GtkTextBuffer" id="buffer_context"/>
<object class="GtkTextBuffer" id="buffer_text"/> <object class="GtkTextBuffer" id="buffer_text"/>
<template class="CmbTranslatableWidget" parent="GtkBox"> <template class="CmbTranslatableWidget" parent="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property> <property name="margin-start">4</property>
<property name="margin-end">4</property> <property name="margin-end">4</property>
<property name="margin-top">4</property> <property name="margin-top">4</property>
@ -16,126 +13,70 @@
<property name="spacing">4</property> <property name="spacing">4</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Text:</property> <property name="label" translatable="1">Text:</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="width-request">300</property> <property name="width-request">300</property>
<property name="height-request">60</property> <property name="height-request">60</property>
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property> <property name="child">
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="text_view_value"> <object class="GtkTextView" id="text_view_value">
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property>
<property name="border-width">2</property>
<property name="buffer">buffer_text</property> <property name="buffer">buffer_text</property>
<property name="accepts-tab">False</property> <property name="accepts-tab">0</property>
</object> </object>
</child> </property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="check_button_translatable"> <object class="GtkCheckButton" id="check_button_translatable">
<property name="label" translatable="yes">translatable</property> <property name="label" translatable="1">translatable</property>
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="draw-indicator">True</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="margin-top">8</property> <property name="margin-top">8</property>
<property name="label" translatable="yes">Translation context:</property> <property name="label" translatable="1">Translation context:</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="height-request">60</property> <property name="height-request">60</property>
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property> <property name="child">
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="text_view_context"> <object class="GtkTextView" id="text_view_context">
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property>
<property name="border-width">2</property>
<property name="buffer">buffer_context</property> <property name="buffer">buffer_context</property>
<property name="accepts-tab">False</property> <property name="accepts-tab">0</property>
</object> </object>
</child> </property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="margin-top">8</property> <property name="margin-top">8</property>
<property name="label" translatable="yes">Comments for translators:</property> <property name="label" translatable="1">Comments for translators:</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="height-request">60</property> <property name="height-request">60</property>
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property> <property name="child">
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="text_view_comments"> <object class="GtkTextView" id="text_view_comments">
<property name="visible">True</property> <property name="focusable">1</property>
<property name="can-focus">True</property>
<property name="border-width">2</property>
<property name="buffer">buffer_comments</property> <property name="buffer">buffer_comments</property>
<property name="accepts-tab">False</property> <property name="accepts-tab">0</property>
</object> </object>
</child> </property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child> </child>
</template> </template>
</interface> </interface>

View File

@ -6,7 +6,7 @@ project(
# File format version follows app version and only changes when there is a # File format version follows app version and only changes when there is a
# change that prevents older versions to load it. # change that prevents older versions to load it.
fileformatversion = '0.13.1' fileformatversion = '0.17.0'
python = import('python') python = import('python')
python_bin = python.find_installation('python3') python_bin = python.find_installation('python3')