1# abstract_optionsbar.py 2# 3# Copyright 2018-2021 Romain F. T. 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18from gi.repository import Gtk 19 20RSRC_PREFIX = '/com/github/maoschanz/drawing/optionsbars/' 21 22class AbstractOptionsBar(): 23 __gtype_name__ = 'AbstractOptionsBar' 24 25 def __init__(self): 26 # Quite high as a precaution, will be more precise later 27 self._limit_size = 700 28 self._is_narrow = False 29 30 def _build_ui(self, end_of_path): 31 """Creates a Gtk.Builder for the resource whose path is hinted in the 32 method parameter, and tries to extract usual widgets ids from it. Most 33 resulting widgets can be `None`, except `action_bar`. The builder is 34 returned if the caller wants to extract more objects from it. 35 This is valid for any instance of `AbstractOptionsBar`.""" 36 builder = Gtk.Builder.new_from_resource(RSRC_PREFIX + end_of_path) 37 self.action_bar = builder.get_object('bottom-pane') 38 self.cancel_btn = builder.get_object('cancel_btn') # may be None 39 self.centered_box = builder.get_object('centered_box') # may be None 40 self.apply_btn = builder.get_object('apply_btn') # may be None 41 self.help_btn = builder.get_object('help_btn') # may be None 42 self.options_btn = builder.get_object('options_btn') # may be None 43 self._togglable_btn = self.options_btn # default value, may change later 44 return builder # for implementations-specific widgets 45 46 def _hydrate_transform_tool(self, end_of_path): 47 """Same as above, BUT this isn't valid for any instance of 48 `AbstractOptionsBar`: only an optionsbar for a transform tool should 49 call that method, and it should call it *after* `_build_ui`. This method 50 will "hydrate" the previously built (but still incomplete) widgets.""" 51 builder = Gtk.Builder.new_from_resource(RSRC_PREFIX + end_of_path) 52 self.centered_box = builder.get_object('centered_box') 53 self.action_bar.set_center_widget(self.centered_box) 54 actions_menu = builder.get_object('actions-menu') 55 if actions_menu: 56 self.options_btn.set_menu_model(actions_menu) 57 else: 58 self.options_btn.destroy() 59 self.options_btn = None 60 return builder 61 62 def build_options_menu(self, widget, model, label): 63 """Set a widget (or a menu) as the popover with tools options. In 64 practice this is used only with the classic tools' pane, and all classic 65 tools provide a menu instead of a widget.""" 66 pass 67 68 def update_for_new_tool(self, tool): 69 """Update the pane when a tool using it has just been activated. Widgets 70 may be hidden/shown or enabled/disabled depending on the properties of 71 the given tool.""" 72 pass 73 74 def get_minimap_btn(self): 75 pass 76 77 def set_minimap_label(self, label): 78 pass 79 80 def toggle_options_menu(self): 81 if self._togglable_btn and self._togglable_btn.get_visible(): 82 self._togglable_btn.set_active(not self._togglable_btn.get_active()) 83 84 def hide_options_menu(self): 85 if self._togglable_btn: 86 self._togglable_btn.set_active(False) 87 88 def middle_click_action(self): 89 pass 90 91 def init_adaptability(self): 92 """Instructions to run during the first window size allocation (and only 93 the first). Calling this is managed by the window's `DrOptionsManager`. 94 It estimates the minimal amount of pixels for the mobile version, and 95 gives it to the `_set_limit_size` method. 96 Any implementation HAS TO end with a call to `_set_limit_size`!""" 97 self.set_compact(False) 98 self.action_bar.show_all() 99 # + implementation-specific instructions 100 101 def _set_limit_size(self, temp_limit_size): 102 self._limit_size = int(1.25 * temp_limit_size) 103 self.set_compact(True) 104 105 def adapt_to_window_size(self, allocated_width): 106 """Check whether or not the costly `set_compact` method should be 107 called, depending on a given window width, and the pane's limit 108 previously set.""" 109 can_expand = (allocated_width > self._limit_size) 110 incoherent = (can_expand == self._is_narrow) 111 if incoherent: 112 self.set_compact(not self._is_narrow) 113 114 def set_compact(self, state): 115 """The parameter is a boolean telling if the bottom pane should become 116 compact or not.""" 117 self._is_narrow = state 118 if self.help_btn is not None: 119 self.help_btn.set_visible(not state) 120 # + implementation-specific instructions 121 122 ############################################################################ 123################################################################################ 124 125