Commit 5abd9bb6 authored by sumpfralle's avatar sumpfralle

moved all references to progress bar handling to a new plugin


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1112 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 3a8e8027
......@@ -2,6 +2,29 @@
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy project-wide -->
<object class="GtkListStore" id="ModelList">
<columns>
<!-- column-name id -->
<column type="gint"/>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name state -->
<column type="gboolean"/>
<!-- column-name color -->
<column type="gchararray"/>
<!-- column-name alpha -->
<column type="guint"/>
</columns>
<data>
<row>
<col id="0">0</col>
<col id="1" translatable="yes">Model #1</col>
<col id="2">False</col>
<col id="3" translatable="yes">#ffff00000000</col>
<col id="4">0</col>
</row>
</data>
</object>
<object class="GtkWindow" id="window1">
<child>
<object class="GtkVPaned" id="ModelBox">
......@@ -173,33 +196,10 @@
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
<property name="shrink">False</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="ModelList">
<columns>
<!-- column-name id -->
<column type="gint"/>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name state -->
<column type="gboolean"/>
<!-- column-name color -->
<column type="gchararray"/>
<!-- column-name alpha -->
<column type="guint"/>
</columns>
<data>
<row>
<col id="0">0</col>
<col id="1" translatable="yes">Model #1</col>
<col id="2">False</col>
<col id="3" translatable="yes">#ffff00000000</col>
<col id="4">0</col>
</row>
</data>
</object>
</interface>
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="DummyWindow">
<child>
<object class="GtkVBox" id="ProgressBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkProgressBar" id="MultipleProgressBar">
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="ProgressWidget">
<property name="spacing">3</property>
<child>
<object class="GtkProgressBar" id="ProgressBar">
<property name="visible">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox13">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToggleButton" id="ShowToolpathProgressButton">
<property name="label" translatable="yes">Show Progress</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ProgressCancelButton">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
......@@ -269,108 +269,6 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkNotebook" id="MainTabs">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="MultipleProgressBar">
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="ProgressWidget">
<property name="spacing">3</property>
<child>
<object class="GtkProgressBar" id="ProgressBar">
<property name="visible">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox13">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToggleButton" id="ShowToolpathProgressButton">
<property name="label" translatable="yes">Show Progress</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ProgressCancelButton">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="StatusBarEventBox">
<property name="visible">True</property>
<child>
<object class="GtkHBox" id="hbox37">
<property name="visible">True</property>
<child>
<object class="GtkImage" id="StatusBarWarning">
<property name="stock">gtk-dialog-warning</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStatusbar" id="StatusBar">
<property name="visible">True</property>
<property name="spacing">2</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
......@@ -5107,7 +5005,11 @@ upon interesting bugs and weird results.</property>
<property name="tooltip">Paste a model from clipboard</property>
<property name="stock_id">gtk-paste</property>
</object>
<object class="GtkWindow" id="window1">
<object class="GtkWindow" id="DummyWindow">
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkNotebook" id="TabDump">
<property name="visible">True</property>
......@@ -7849,6 +7751,54 @@ upon interesting bugs and weird results.</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="MainTabs">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="StatusBarEventBox">
<property name="visible">True</property>
<child>
<object class="GtkHBox" id="hbox37">
<property name="visible">True</property>
<child>
<object class="GtkImage" id="StatusBarWarning">
<property name="stock">gtk-dialog-warning</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStatusbar" id="StatusBar">
<property name="visible">True</property>
<property name="spacing">2</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkImage" id="GenerateOneToolPathIcon">
......
......@@ -103,6 +103,9 @@ class BaseModel(TransformableContainer):
def to_OpenGL(self, visible_filter=None, show_directions=False):
if not GL_enabled:
return
gl_color = tuple([float(val) for val in GL.glGetFloatv(GL.GL_CURRENT_COLOR)])
# the index should contain all relevant context details
cache_index = (show_directions, gl_color)
if not visible_filter is None:
for item in self.next():
# ignore invisble things like the normal of a ContourModel
......@@ -110,17 +113,17 @@ class BaseModel(TransformableContainer):
do_paint, color = visible_filter(item)
if do_paint:
item.to_OpenGL(color, show_directions=show_directions)
elif not show_directions in self._opengl_display_cache:
elif not cache_index in self._opengl_display_cache:
# compile an OpenGL display list
# Rendering a display list takes less than 5% of the time for a
# complete rebuild.
list_index = GL.glGenLists(1)
if list_index > 0:
self._opengl_display_cache[show_directions] = list_index
self._opengl_display_cache[cache_index] = list_index
# somehow "GL_COMPILE_AND_EXECUTE" fails - we render it later
GL.glNewList(list_index, GL.GL_COMPILE)
for item in self.next():
# ignore invisble things like the normal of a ContourModel
# ignore invisible things like the normal of a ContourModel
if hasattr(item, "to_OpenGL"):
item.to_OpenGL(show_directions=show_directions)
if list_index > 0:
......@@ -128,7 +131,7 @@ class BaseModel(TransformableContainer):
GL.glCallList(list_index)
else:
# render a previously compiled display list
GL.glCallList(self._opengl_display_cache[show_directions])
GL.glCallList(self._opengl_display_cache[cache_index])
def is_export_supported(self):
return not self._export_function is None
......@@ -289,16 +292,26 @@ class Model(BaseModel):
return self._t_kdtree.Search(minx, maxx, miny, maxy)
return self._triangles
def get_waterline_contour(self, plane):
def get_waterline_contour(self, plane, callback=None):
collision_lines = []
progress_max = 2 * len(self._triangles)
counter = 0
for t in self._triangles:
if callback and callback(percent=100.0 * counter / progress_max):
return
collision_line = plane.intersect_triangle(t, counter_clockwise=True)
if not collision_line is None:
collision_lines.append(collision_line)
else:
counter += 1
counter += 1
# combine these lines into polygons
contour = ContourModel(plane=plane)
for line in collision_lines:
if callback and callback(percent=100.0 * counter / progress_max):
return
contour.append(line)
counter += 1
log.debug("Waterline: %f - %d - %s" % (plane.p.z,
len(contour.get_polygons()),
[len(p.get_lines()) for p in contour.get_polygons()]))
......
......@@ -36,7 +36,7 @@ from pycam.Geometry.Plane import Plane
import pycam.Geometry.Path
import pycam.Utils.log
from pycam.Utils.locations import get_data_file_location, \
get_ui_file_location, get_font_dir
get_ui_file_location, get_font_dir, get_external_program_location
import pycam.Utils
from pycam.Geometry.utils import sqrt
from pycam.Gui.OpenGLTools import ModelViewWindowGL
......@@ -193,7 +193,8 @@ def get_icons_pixbuffers():
UI_FUNC_INDEX, UI_WIDGET_INDEX = range(2)
WIDGET_NAME_INDEX, WIDGET_OBJ_INDEX, WIDGET_WEIGHT_INDEX = range(3)
WIDGET_NAME_INDEX, WIDGET_OBJ_INDEX, WIDGET_WEIGHT_INDEX, WIDGET_ARGS_INDEX = \
range(4)
HANDLER_FUNC_INDEX, HANDLER_ARG_INDEX = range(2)
EVENT_HANDLER_INDEX, EVENT_BLOCKER_INDEX = range(2)
......@@ -226,7 +227,7 @@ class EventCore(pycam.Gui.Settings.Settings):
else:
log.debug("Trying to unregister an unknown event: %s" % event)
def emit_event(self, event):
def emit_event(self, event, *args, **kwargs):
log.debug("Event emitted: %s" % str(event))
if event in self.event_handlers:
if self.event_handlers[event][EVENT_BLOCKER_INDEX] != 0:
......@@ -234,9 +235,9 @@ class EventCore(pycam.Gui.Settings.Settings):
self.block_event(event)
for handler in self.event_handlers[event][EVENT_HANDLER_INDEX]:
func = handler[HANDLER_FUNC_INDEX]
args = handler[HANDLER_ARG_INDEX]
data = handler[HANDLER_ARG_INDEX]
# prevent infinite recursion
func(*args)
func(*(data + args), **kwargs)
self.unblock_event(event)
else:
log.debug("No events registered for event '%s'" % str(event))
......@@ -273,19 +274,25 @@ class EventCore(pycam.Gui.Settings.Settings):
key=lambda x: x[WIDGET_WEIGHT_INDEX])
clear_func()
for item in ui_section[UI_WIDGET_INDEX]:
add_func(item[WIDGET_OBJ_INDEX], item[WIDGET_NAME_INDEX])
if item[WIDGET_ARGS_INDEX]:
args = item[WIDGET_ARGS_INDEX]
else:
args = {}
add_func(item[WIDGET_OBJ_INDEX], item[WIDGET_NAME_INDEX],
**args)
else:
log.debug("Failed to rebuild unknown ui section: %s" % str(section))
def register_ui(self, section, name, widget, weight=0):
def register_ui(self, section, name, widget, weight=0, args_dict=None):
if not section in self.ui_sections:
self.ui_sections[section] = [None, None]
self.ui_sections[section][UI_WIDGET_INDEX] = []
assert WIDGET_NAME_INDEX == 0
assert WIDGET_OBJ_INDEX == 1
assert WIDGET_WEIGHT_INDEX == 2
assert WIDGET_ARGS_INDEX == 3
self.ui_sections[section][UI_WIDGET_INDEX].append((name, widget,
weight))
weight, args_dict))
self._rebuild_ui_section(section)
def unregister_ui(self, section, widget):
......@@ -329,12 +336,9 @@ class ProjectGui(object):
# we set the final value later
self.no_dialog = True
self._batch_queue = []
self._progress_running = False
self._progress_cancel_requested = False
self._last_gtk_events_time = None
self._undo_states = []
self._fonts_cache = pycam.Utils.FontCache.FontCache(get_font_dir(),
callback=self.update_progress_bar)
core=self.settings)
self.gui = gtk.Builder()
gtk_build_file = get_ui_file_location(GTKBUILD_FILE)
if gtk_build_file is None:
......@@ -439,8 +443,6 @@ class ProjectGui(object):
self.settings.register_event("model-change-after", self.update_view)
self.settings.register_event("visual-item-updated", self.update_view)
self.settings.register_event("visual-item-updated", self.update_model_dimensions)
self.settings.set("update_progress", self.update_progress_bar)
self.settings.set("disable_progress_cancel_button", self.disable_progress_cancel_button)
self.settings.set("load_model", self.load_model)
self.settings.register_event("boundary-updated", self.update_view)
# configure drag-n-drop for config files and models
......@@ -553,6 +555,22 @@ class ProjectGui(object):
for name in tab_names:
item = self.gui.get_object(name + "Tab")
self.settings.register_ui("main", name, item, tab_names.index(name))
main_window = self.gui.get_object("WindowBox")
event_bar = self.gui.get_object("StatusBarEventBox")
def clear_main_window():
main_window.foreach(lambda x: main_window.remove(x))
def add_main_window_item(item, name, **extra_args):
# some widgets may want to override the defaults
args = {"expand": False, "fill": False}
args.update(extra_args)
main_window.pack_start(item, **args)
main_tab.unparent()
event_bar.unparent()
self.settings.register_ui_section("main_window", add_main_window_item,
clear_main_window)
self.settings.register_ui("main_window", "Tabs", main_tab, -20,
args_dict={"expand": True, "fill": True})
self.settings.register_ui("main_window", "Status", event_bar, 100)
# unit control (mm/inch)
unit_field = self.gui.get_object("unit_control")
unit_field.connect("changed", self.change_unit_init)
......@@ -655,10 +673,14 @@ class ProjectGui(object):
# all of the objects above should trigger redraw
obj.connect("toggled", lambda widget: \
self.settings.emit_event("model-change-after"))
self.show_progress_button = self.gui.get_object("ShowToolpathProgressButton")
self.settings.add_item("show_drill_progress",
self.show_progress_button.get_active,
self.show_progress_button.set_active)
def disable_gui():
self.menubar.set_sensitive(False)
main_tab.set_sensitive(False)
def enable_gui():
self.menubar.set_sensitive(True)
main_tab.set_sensitive(True)
self.settings.register_event("gui-disable", disable_gui)
self.settings.register_event("gui-enable", enable_gui)
for name, objname in (
("view_light", "OpenGLLight"),
("view_shadow", "OpenGLShadow"),
......@@ -798,12 +820,6 @@ class ProjectGui(object):
self.gui.get_object("ProcessListMoveDown").connect("clicked", self.handle_process_table_event, "move_down")
self.gui.get_object("ProcessListAdd").connect("clicked", self.handle_process_table_event, "add")
self.gui.get_object("ProcessListDelete").connect("clicked", self.handle_process_table_event, "delete")
# progress bar and task pane
self.progress_bar = self.gui.get_object("ProgressBar")
self.progress_widget = self.gui.get_object("ProgressWidget")
self.task_pane = self.gui.get_object("MainTabs")
self.progress_cancel_button = self.gui.get_object("ProgressCancelButton")
self.progress_cancel_button.connect("clicked", self.cancel_progress)
# make sure that the toolpath settings are consistent
self.toolpath_table = self.gui.get_object("ToolPathTable")
self.toolpath_table.get_selection().connect("changed", self.toolpath_table_event, "update_buttons")
......@@ -1064,9 +1080,7 @@ class ProjectGui(object):
self.gui.get_object("OpenRecentModel").set_visible(False)
# load the menubar and connect functions to its items
self.menubar = uimanager.get_widget("/MenuBar")
window_box = self.gui.get_object("WindowBox")
window_box.pack_start(self.menubar, False)
window_box.reorder_child(self.menubar, 0)
self.settings.register_ui("main_window", "Main", self.menubar, -100)
# some more initialization
self.reset_preferences()
self.load_preferences()
......@@ -1168,19 +1182,6 @@ class ProjectGui(object):
else:
self.enable_ode_control.set_sensitive(True)
def progress_activity_guard(func):
def progress_activity_guard_wrapper(self, *args, **kwargs):
if self._progress_running:
return
self._progress_running = True
self._progress_cancel_requested = False
self.toggle_progress_bar(True)
result = func(self, *args, **kwargs)
self.toggle_progress_bar(False)
self._progress_running = False
return result
return progress_activity_guard_wrapper
def gui_activity_guard(func):
def gui_activity_guard_wrapper(self, *args, **kwargs):
if self.gui_is_active:
......@@ -1380,7 +1381,7 @@ class ProjectGui(object):
def _locate_external_program(self, widget=None, key=None):
# the button was just activated
location = pycam.Utils.get_external_program_location(key)
location = get_external_program_location(key)
if not location:
log.error("Failed to locate the external program '%s'. " % key \
+ "Please install the program and try again." \
......@@ -1635,17 +1636,15 @@ class ProjectGui(object):
task = task_list[index]
if task["enabled"]:
enabled_tasks.append(task)
progress_bar = self.gui.get_object("MultipleProgressBar")
progress_bar.show()
for index in range(len(enabled_tasks)):
progress_bar.set_fraction(float(index) / len(enabled_tasks))
progress_bar.set_text("Toolpath %d/%d" % (index, len(enabled_tasks)))
task = enabled_tasks[index]
progress = self.settings.get("progress")
progress.set_multiple(len(enabled_tasks), "Toolpath")
for task in enabled_tasks:
if not self.generate_toolpath(task["tool"], task["process"],
task["bounds"]):
task["bounds"], progress=progress):
# break out of the loop, if cancel was requested
break
progress_bar.hide()
progress.update_multiple()
progress.finish()
def update_process_controls(self, widget=None, data=None):
# possible dependencies of the DropCutter
......@@ -1715,7 +1714,6 @@ class ProjectGui(object):
self.gui.get_object("ExportEMCToolDefinition").set_sensitive(len(self.tool_list) > 0)
@gui_activity_guard
@progress_activity_guard
def toggle_font_dialog_window(self, widget=None, event=None, state=None):
# only "delete-event" uses four arguments
# TODO: unify all these "toggle" functions for different windows into one single function (including storing the position)
......@@ -1725,7 +1723,6 @@ class ProjectGui(object):
state = not self._font_dialog_window_visible
if state:
if self.font_selector is None:
self.update_progress_bar("Initializing fonts")
# create it manually to ease access
font_selector = gtk.combo_box_new_text()
self.gui.get_object("FontSelectionBox").pack_start(
......@@ -1855,18 +1852,18 @@ class ProjectGui(object):
return data, importer
return None, None
@progress_activity_guard
@gui_activity_guard
def paste_model_from_clipboard(self, widget=None):
data, importer = self._get_data_and_importer_from_clipboard()
progress = self.settings.get("progress")
if data:
self.update_progress_bar(text="Loading model from clipboard")
progress.update(text="Loading model from clipboard")
text_buffer = StringIO.StringIO(data.data)
model = importer(text_buffer,
program_locations=self._get_program_locations(),
unit=self.settings.get("unit"),
fonts_cache=self._fonts_cache,
callback=self.update_progress_bar)
callback=progress.update)
if model:
log.info("Loaded a model from clipboard")
self.load_model(model)
......@@ -1874,6 +1871,7 @@ class ProjectGui(object):
log.warn("Failed to load a model from clipboard")
else:
log.warn("The clipboard does not contain suitable data")
progress.finish()
@gui_activity_guard
def update_font_dialog_preview(self, widget=None, event=None):
......@@ -2384,16 +2382,21 @@ class ProjectGui(object):
# transform the model if it is selected
# keep the original center of the model
self.settings.emit_event("model-change-before")
for model in self.settings.get("models"):
models = self.settings.get("models")
progress = self.settings.get("progress")
progress.disable_cancel()
progress.set_multiple(len(models), "Scaling model")
for model in models:
new_x, new_y, new_z = ((model.maxx + model.minx) / 2,
(model.maxy + model.miny) / 2,
(model.maxz + model.minz) / 2)
model.scale(factor)
model.scale(factor, callback=progress.update)
cur_x, cur_y, cur_z = self._get_model_center()
self.update_progress_bar("Centering model")
model.shift(new_x - cur_x, new_y - cur_y,
new_z - cur_z,
callback=self.update_progress_bar)
callback=progress.update)
progress.update_multiple()
progress.finish()
if self.gui.get_object("UnitChangeProcesses").get_active():
# scale the process settings
for process in self.process_list:
......@@ -2613,18 +2616,6 @@ class ProjectGui(object):
def destroy(self, widget=None, data=None):
self.update_view()
# check if there is a running process
# BEWARE: this is useless without threading - but we keep it for now
if self._progress_running:
self.cancel_progress()
# wait steps
delay = 0.5
# timeout in seconds
timeout = 5
# wait until if is finished
while self._progress_running and (timeout > 0):
time.sleep(delay)
timeout -= delay
gtk.main_quit()
self.quit()
......@@ -2692,7 +2683,6 @@ class ProjectGui(object):
return program_locations
@gui_activity_guard
@progress_activity_guard
def load_model_file(self, widget=None, filename=None, store_filename=True):
if callable(filename):
filename = filename()
......@@ -2702,20 +2692,23 @@ class ProjectGui(object):
if filename:
file_type, importer = pycam.Importers.detect_file_type(filename)
if file_type and callable(importer):
self.update_progress_bar(text="Loading model ...")
progress = self.settings.get("progress")
progress.update(text="Loading model ...")
# "cancel" is not allowed
self.disable_progress_cancel_button()
progress.disable_cancel()
if self.load_model(importer(filename,
program_locations=self._get_program_locations(),
unit=self.settings.get("unit"),
fonts_cache=self._fonts_cache,
callback=self.update_progress_bar)):
callback=progress.update)):
if store_filename:
self.set_model_filename(filename)
self.add_to_recent_file_list(filename)
return True
result = True
else:
return False
result = False
progress.finish()
return result
else:
log.error("Failed to detect filetype!")
return False
......@@ -3271,93 +3264,6 @@ class ProjectGui(object):
self.add_to_recent_file_list(filename)
self.update_save_actions()
def toggle_progress_bar(self, status):
# always hide the progress button - it will be enabled later
self.show_progress_button.hide()
if status:
self.menubar.set_sensitive(False)
self.task_pane.set_sensitive(False)
self._progress_start_time = time.time()
self.update_progress_bar(text="", percent=0)
self.progress_cancel_button.set_sensitive(True)
# enable "pulse" mode for a start (in case of unknown ETA)
self.progress_bar.pulse()
self.progress_widget.show()
else:
self.progress_widget.hide()
self.task_pane.set_sensitive(True)
self.menubar.set_sensitive(True)
def disable_progress_cancel_button(self):
""" mainly useful for non-interruptable operations (e.g. model
transformations)
"""
self.progress_cancel_button.set_sensitive(False)
def update_progress_bar(self, text=None, percent=None):
if not percent is None:
percent = min(max(percent, 0.0), 100.0)
self.progress_bar.set_fraction(percent/100.0)
if (not percent) and (self.progress_bar.get_fraction() == 0):
# use "pulse" mode until we reach 1% of the work to be done
self.progress_bar.pulse()
# update the GUI
current_time = time.time()
# Don't update the GUI more often than once per second.
# Exception: text-only updates
# This restriction improves performance and reduces the
# "snappiness" of the GUI.
if (self._last_gtk_events_time is None) \
or text \
or (self._last_gtk_events_time + 1 <= current_time):
# "estimated time of arrival" text
time_estimation_suffix = " remaining ..."
if self.progress_bar.get_fraction() > 0:
eta_full = (time.time() - self._progress_start_time) / self.progress_bar.get_fraction()
if eta_full > 0:
eta_delta = eta_full - (time.time() - self._progress_start_time)
eta_delta = int(round(eta_delta))
if hasattr(self, "_last_eta_delta"):
previous_eta_delta = self._last_eta_delta
if eta_delta == previous_eta_delta + 1:
# We are currently toggling between two numbers.
# We want to avoid screen flicker, thus we just live
# with the slight inaccuracy.
eta_delta = self._last_eta_delta
self._last_eta_delta = eta_delta
eta_delta_obj = datetime.timedelta(seconds=eta_delta)
eta_text = "%s%s" % (eta_delta_obj, time_estimation_suffix)
else:
eta_text = None
else:
eta_text = None
if not text is None:
lines = [text]
else:
old_lines = self.progress_bar.get_text().split(os.linesep)
# skip the time estimation line
lines = [line for line in old_lines
if not line.endswith(time_estimation_suffix)]
if eta_text:
lines.append(eta_text)
self.progress_bar.set_text(os.linesep.join(lines))
# show the "show_tool_button" ("hide" is called in the progress decorator)
if self.settings.get("toolpath_in_progress"):
self.show_progress_button.show()
while gtk.events_pending():
gtk.main_iteration()
if not text or (self._progress_start_time + 5 < current_time):
# We don't store the timining if the text was changed.
# This is especially nice for the snappines during font
# initialization. This exception is only valid for the first
# five seconds of the operation.
self._last_gtk_events_time = current_time
# return if the user requested a break
return self._progress_cancel_requested
def cancel_progress(self, widget=None):
self._progress_cancel_requested = True
def finish_toolpath_simulation(self, widget=None, data=None):
# hide the simulation tab
self.simulation_window.hide()
......@@ -3428,7 +3334,6 @@ class ProjectGui(object):
progress_value_percent)
return True
@progress_activity_guard
def update_toolpath_simulation_ode(self, widget=None, toolpath=None):
import pycam.Simulation.ODEBlocks as ODEBlocks
# get the currently selected toolpath, if none is give
......@@ -3460,10 +3365,11 @@ class ProjectGui(object):
# update the view
self.update_view()
# calculate the simulation and show it simulteneously
progress = self.settings.get("progress")
for path_index, path in enumerate(paths):
progress_text = "Simulating path %d/%d" % (path_index, len(paths))
progress_value_percent = 100.0 * path_index / len(paths)
if self.update_progress_bar(progress_text, progress_value_percent):
if progress.update(text=progress_text, percent=progress_value_percent):
# break if the user pressed the "cancel" button
break
for index in range(len(path.points)):
......@@ -3475,8 +3381,9 @@ class ProjectGui(object):
simulation_backend.process_cutter_movement(start, end)
self.update_view()
# break the loop if someone clicked the "cancel" button
if self.update_progress_bar():
if progress.update():
break
progress.finish()
# enable the simulation widget again (if we were started from the GUI)
if not widget is None:
self.gui.get_object("SimulationTab").set_sensitive(True)
......@@ -3495,10 +3402,15 @@ class ProjectGui(object):
# update the toolpath simulation repeatedly
gobject.timeout_add(time_step, self.update_toolpath_simulation)
@progress_activity_guard
def generate_toolpath(self, tool_settings, process_settings, bounds):
def generate_toolpath(self, tool_settings, process_settings, bounds,
progress=None):
start_time = time.time()
self.update_progress_bar("Preparing toolpath generation")
if progress:
use_multi_progress = True
else:
use_multi_progress = False
progress = self.settings.get("progress")
progress.update(text="Preparing toolpath generation")
parent = self
class UpdateView(object):
def __init__(self, func, max_fps=1):
......@@ -3518,17 +3430,19 @@ class ProjectGui(object):
if self.func:
self.func()
# break the loop if someone clicked the "cancel" button
return parent.update_progress_bar(text, percent)
return progress.update(text=text, percent=percent)
draw_callback = UpdateView(self.update_view,
max_fps=self.settings.get("drill_progress_max_fps")).update
self.update_progress_bar("Generating collision model")
progress.update(text="Generating collision model")
# turn the toolpath settings into a dict
toolpath_settings = self.get_toolpath_settings(tool_settings,
process_settings, bounds)
if toolpath_settings is None:
# behave as if "cancel" was requested
if not use_multi_progress:
progress.finish()
return True
self.cutter = toolpath_settings.get_tool()
......@@ -3537,13 +3451,15 @@ class ProjectGui(object):
model = self.settings.get("models")[0]
# run the toolpath generation
self.update_progress_bar("Starting the toolpath generation")
progress.update(text="Starting the toolpath generation")
try:
toolpath = pycam.Toolpath.Generator.generate_toolpath_from_settings(
model, toolpath_settings, callback=draw_callback)
except Exception:
# catch all non-system-exiting exceptions
report_exception()
if not use_multi_progress:
progress.finish()
return False
log.info("Toolpath generation time: %f" % (time.time() - start_time))
......@@ -3553,12 +3469,12 @@ class ProjectGui(object):
if toolpath is None:
# user interruption
# return "False" if the action was cancelled
return not self.update_progress_bar()
result = not progress.update()
elif isinstance(toolpath, basestring):
# an error occoured - "toolpath" contains the error message
log.error("Failed to generate toolpath: %s" % toolpath)
# we were not successful (similar to a "cancel" request)
return False
result = False
else:
# hide the previous toolpath if it is the only visible one (automatic mode)
if (len([True for path in self.toolpath if path.visible]) == 1) \
......@@ -3572,7 +3488,11 @@ class ProjectGui(object):
self.update_toolpath_table()
self.update_view()
# return "False" if the action was cancelled
return not self.update_progress_bar()
cancelled = progress.update()
result = not cancelled
if not use_multi_progress:
progress.finish()
return result
def get_toolpath_settings(self, tool_settings, process_settings, bounds):
toolpath_settings = pycam.Gui.Settings.ToolpathSettings()
......
......@@ -21,16 +21,19 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Importers.DXFImporter
from pycam.Utils.locations import get_external_program_location
import pycam.Utils
import tempfile
import subprocess
import os
log = pycam.Utils.log.get_logger()
def convert_svg2eps(svg_filename, eps_filename, location=None):
if location is None:
location = pycam.Utils.get_external_program_location("inkscape")
location = get_external_program_location("inkscape")
if location is None:
location = "inkscape"
try:
......@@ -54,7 +57,7 @@ def convert_svg2eps(svg_filename, eps_filename, location=None):
def convert_eps2dxf(eps_filename, dxf_filename, location=None, unit="mm"):
if location is None:
location = pycam.Utils.get_external_program_location("pstoedit")
location = get_external_program_location("pstoedit")
if location is None:
location = "pstoedit"
args = [location, "-dt", "-nc", "-f", "dxf:-polyaslines"]
......
......@@ -84,14 +84,12 @@ class ModelExtrusion(pycam.Plugins.PluginBase):
extrude_widget.hide()
def _extrude_model(self, widget=None):
models = self._get_extrudable_models()
if not models:
selected_models = self._get_extrudable_models()
if not selected_models:
return
self.core.get("update_progress")("Extruding models")
extrusion_type_selector = self.gui.get_object("ExtrusionTypeSelector")
type_model = extrusion_type_selector.get_model()
type_active = extrusion_type_selector.get_active()
# TODO: progress bar for main/sub if more than one model is selected
if type_active >= 0:
type_string = type_model[type_active][0]
height = self.gui.get_object("ExtrusionHeight").get_value()
......@@ -111,9 +109,12 @@ class ModelExtrusion(pycam.Plugins.PluginBase):
self.log.error("Unknown extrusion type selected: %s" % type_string)
return
model_manager = self.core.get("models")
for model in models:
progress = self.core.get("progress")
progress.update(text="Extruding models")
progress.set_multiple(len(selected_models), "Model")
for model in selected_models:
new_model = model.extrude(stepping=grid_size, func=func,
callback=self.core.get("update_progress"))
callback=progress.update)
if new_model:
self.core.get("load_model")(new_model)
try:
......@@ -126,4 +127,6 @@ class ModelExtrusion(pycam.Plugins.PluginBase):
(new_name, original_name))
except LookupError:
pass
progress.update_multiple()
progress.finish()
......@@ -54,16 +54,21 @@ class ModelPlaneMirror(pycam.Plugins.PluginBase):
plane_widget.hide()
def _plane_mirror(self, widget=None):
model = self.core.get("model")
if not model:
models = self.core.get("models").get_selected()
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Mirroring model")
self.core.get("disable_progress_cancel_button")()
progress = self.core.get("progress")
progress.update(text="Mirroring model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for plane in ("XY", "XZ", "YZ"):
if self.gui.get_object("MirrorPlane%s" % plane).get_active():
break
for model in models:
model.transform_by_template("%s_mirror" % plane.lower(),
callback=self.core.get("update_progress"))
callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
......@@ -81,8 +81,12 @@ class ModelPolygons(pycam.Plugins.PluginBase):
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Analyzing directions of contour model")
progress = self.core.get("progress")
progress.update(text="Analyzing directions of contour model")
progress.set_multiple(len(models), "Model")
for model in models:
model.revise_directions(callback=self.core.get("update_progress"))
model.revise_directions(callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
......@@ -75,14 +75,17 @@ class ModelPosition(pycam.Plugins.PluginBase):
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Aligning model")
self.core.get("disable_progress_cancel_button")()
progress = self.core.get("progress")
progress.update(text="Aligning model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
shift = [self.gui.get_object("ShiftPosition%s" % axis).get_value()
for axis in "XYZ"]
# TODO: main/sub progress bar for multiple models
for model in models:
model.shift(shift[0], shift[1], shift[2],
callback=self.core.get("update_progress"))
callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
def _align_model(self, widget=None):
......@@ -90,8 +93,6 @@ class ModelPosition(pycam.Plugins.PluginBase):
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Shifting model")
self.core.get("disable_progress_cancel_button")()
dest = [self.gui.get_object("AlignPosition%s" % axis).get_value()
for axis in "XYZ"]
shift_values = []
......@@ -110,10 +111,14 @@ class ModelPosition(pycam.Plugins.PluginBase):
else:
shift = dest - max_axis
shift_values.append(shift)
# TODO: main/sub progress bar for multiple models
progress = self.core.get("progress")
progress.update(text="Shifting model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for model in models:
model.shift(shift_values[0], shift_values[1], shift_values[2],
callback=self.core.get("update_progress"))
callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
......@@ -73,8 +73,9 @@ class ModelProjection(pycam.Plugins.PluginBase):
models = self._get_projectable_models()
if not models:
return
self.core.get("update_progress")("Calculating 2D projection")
# TODO: main/sub progress for multiple models
progress = self.core.get("progress")
progress.update(text="Calculating 2D projection")
progress.set_multiple(len(models), "Model")
for model in models:
for objname, z_level in (("ProjectionModelTop", model.maxz),
("ProjectionModelMiddle", (model.minz + model.maxz) / 2.0),
......@@ -84,7 +85,8 @@ class ModelProjection(pycam.Plugins.PluginBase):
if self.gui.get_object(objname).get_active():
plane = Plane(Point(0, 0, z_level), Vector(0, 0, 1))
self.log.info("Projecting 3D model at level z=%g" % plane.p.z)
new_model = model.get_waterline_contour(plane)
new_model = model.get_waterline_contour(plane,
callback=progress.update)
if new_model:
self.core.get("load_model")(new_model)
model_manager = self.core.get("models")
......@@ -102,4 +104,6 @@ class ModelProjection(pycam.Plugins.PluginBase):
self.log.warn("The 2D projection at z=%g is empty. Aborted." % \
plane.p.z)
break
progress.update_multiple()
progress.finish()
......@@ -60,8 +60,6 @@ class ModelRotation(pycam.Plugins.PluginBase):
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Rotating model")
self.core.get("disable_progress_cancel_button")()
for axis in "XYZ":
if self.gui.get_object("RotationAxis%s" % axis).get_active():
break
......@@ -75,9 +73,13 @@ class ModelRotation(pycam.Plugins.PluginBase):
break
matrix = pycam.Geometry.Matrix.get_rotation_matrix_axis_angle(
axis_vector, angle, use_radians=False)
# TODO: main/sub progress for multiple models
progress = self.core.get("progress")
progress.update(text="Rotating model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for model in models:
model.transform_by_matrix(matrix,
callback=self.core.get("update_progress"))
model.transform_by_matrix(matrix, callback=progress.update)
progress.update_multiple()
self.core.emit_event("model-change-after")
progress.finish()
......@@ -109,11 +109,14 @@ class ModelScaling(pycam.Plugins.PluginBase):
if (factor <= 0) or (factor == 1):
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Scaling model")
self.core.get("disable_progress_cancel_button")()
# TODO: main/sub progress for multiple models
progress = self.core.get("progress")
progress.update(text="Scaling model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for model in models:
model.scale(factor, callback=self.core.get("update_progress"))
model.scale(factor, callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
def _scale_model_axis_fit(self, widget=None, proportionally=False):
......@@ -129,12 +132,14 @@ class ModelScaling(pycam.Plugins.PluginBase):
factor = value / (getattr(model, "max" + axis_suffix) - \
getattr(model, "min" + axis_suffix))
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Scaling model")
self.core.get("disable_progress_cancel_button")()
# TODO: main/sub progress for multiple models
progress = self.core.get("progress")
progress.update(text="Scaling model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for model in models:
# TODO: use different scaling for multiple models
if proportionally:
model.scale(factor, callback=self.core.get("update_progress"))
model.scale(factor, callback=progress.update)
else:
factor_x, factor_y, factor_z = (1, 1, 1)
if index == 0:
......@@ -146,6 +151,8 @@ class ModelScaling(pycam.Plugins.PluginBase):
else:
return
model.scale(factor_x, factor_y, factor_z,
callback=self.core.get("update_progress"))
callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
......@@ -58,15 +58,18 @@ class ModelSwapAxes(pycam.Plugins.PluginBase):
if not models:
return
self.core.emit_event("model-change-before")
self.core.get("update_progress")("Swap axes of model")
self.core.get("disable_progress_cancel_button")()
for axes, template in (("XY", "x_swap_y"), ("XZ", "x_swap_z"),
("YZ", "y_swap_z")):
if self.gui.get_object("SwapAxes%s" % axes).get_active():
break
# TODO: main/sub progress for multiple models
progress = self.core.get("progress")
progress.update(text="Swap axes of model")
progress.disable_cancel()
progress.set_multiple(len(models), "Model")
for model in models:
model.transform_by_template(template,
callback=self.core.get("update_progress"))
callback=progress.update)
progress.update_multiple()
progress.finish()
self.core.emit_event("model-change-after")
# -*- coding: utf-8 -*-
"""
$Id: __init__.py 1061 2011-04-12 13:14:12Z sumpfralle $
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
......@@ -43,7 +43,7 @@ class Models(pycam.Plugins.ListPluginBase):
self._gtk = gtk
model_frame = self.gui.get_object("ModelBox")
model_frame.unparent()
self.core.register_ui("main", "Models", model_frame, -50)
self.core.register_ui("main", "Models", model_frame, weight=-50)
model_handling_obj = self.gui.get_object("ModelHandlingNotebook")
def clear_model_handling_obj():
for index in range(model_handling_obj.get_n_pages()):
......
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import os
import time
import datetime
import pycam.Plugins
class ProgressBar(pycam.Plugins.PluginBase):
UI_FILE = "progress_bar.ui"
def setup(self):
if self.gui:
box = self.gui.get_object("ProgressBox")
box.unparent()
self.core.register_ui("main_window", "Progress", box, 50)
self.core.add_item("progress", lambda: ProgressGTK(self.core, self.gui))
show_progress_button = self.gui.get_object("ShowToolpathProgressButton")
self.core.add_item("show_drill_progress",
show_progress_button.get_active,
show_progress_button.set_active)
return True
def teardown(self):
self.core.set("progress", None)
class ProgressGTK(object):
def __init__(self, core, gui):
import gtk
self._gtk = gtk
self._gui = gui
self.core = core
self._cancel_requested = False
self._start_time = 0
self._multi_maximum = 0
self._multi_counter = 0
self._multi_base_text = ""
self._last_gtk_events_time = None
self._main_widget = self._gui.get_object("ProgressWidget")
self._multi_widget = self._gui.get_object("MultipleProgressBar")
self._cancel_button = self._gui.get_object("ProgressCancelButton")
self._cancel_button.connect("clicked", self.cancel)
self._progress_bar = self._gui.get_object("ProgressBar")
self._progress_button = self._gui.get_object("ShowToolpathProgressButton")
self._start_time = time.time()
self._progress_button.show()
self.update(text="", percent=0)
self._cancel_button.set_sensitive(True)
self._progress_button.hide()
# enable "pulse" mode for a start (in case of unknown ETA)
self._progress_bar.pulse()
self._main_widget.show()
self._multi_widget.hide()
self._multi_widget.set_text("")
self._multi_widget.set_fraction(0)
self.core.emit_event("gui-disable")
def set_multiple(self, count, base_text=None):
if base_text:
self._multi_base_text = base_text
else:
self._multi_base_text = ""
self._multi_counter = 1
if count > 1:
self._multi_maximum = count
self.update_multiple(increment=False)
self._multi_widget.show()
else:
self._multi_maximum = 0
def update_multiple(self, increment=True):
if self._multi_maximum <= 1:
return
if increment:
self._multi_counter += 1
self._progress_bar.set_fraction(0)
if self._multi_base_text:
text = "%s %d/%d" % (self._multi_base_text, self._multi_counter,
self._multi_maximum)
else:
text = "%d/%d" % (self._multi_counter, self._multi_maximum)
self._multi_widget.set_text(text)
self._multi_widget.set_fraction(
float(self._multi_counter) / self._multi_maximum)
def disable_cancel(self):
self._cancel_button.set_sensitive(False)
def cancel(self):
self._cancel_requested = True
def finish(self):
self._main_widget.hide()
self._multi_widget.hide()
widget = self._main_widget
while widget:
if hasattr(widget, "resize_children"):
widget.resize_children()
if hasattr(widget, "check_resize"):
widget.check_resize()
widget = widget.get_parent()
self.core.emit_event("gui-enable")
def __del__(self):
self.finish()
def update(self, text=None, percent=None):
if not percent is None:
percent = min(max(percent, 0.0), 100.0)
self._progress_bar.set_fraction(percent/100.0)
if (not percent) and (self._progress_bar.get_fraction() == 0):
# use "pulse" mode until we reach 1% of the work to be done
self._progress_bar.pulse()
# update the GUI
current_time = time.time()
# Don't update the GUI more often than once per second.
# Exception: text-only updates
# This restriction improves performance and reduces the
# "snappiness" of the GUI.
if (self._last_gtk_events_time is None) \
or text \
or (self._last_gtk_events_time + 0.5 <= current_time):
# "estimated time of arrival" text
time_estimation_suffix = " remaining ..."
if self._progress_bar.get_fraction() > 0:
total_fraction = (self._progress_bar.get_fraction() + self._multi_counter) / max(1, self._multi_maximum)
eta_full = (time.time() - self._start_time) / total_fraction
if eta_full > 0:
eta_delta = eta_full - (time.time() - self._start_time)
eta_delta = int(round(eta_delta))
if hasattr(self, "_last_eta_delta"):
previous_eta_delta = self._last_eta_delta
if eta_delta == previous_eta_delta + 1:
# We are currently toggling between two numbers.
# We want to avoid screen flicker, thus we just live
# with the slight inaccuracy.
eta_delta = self._last_eta_delta
self._last_eta_delta = eta_delta
eta_delta_obj = datetime.timedelta(seconds=eta_delta)
eta_text = "%s%s" % (eta_delta_obj, time_estimation_suffix)
else:
eta_text = None
else:
eta_text = None
if not text is None:
lines = [text]
else:
old_lines = self._progress_bar.get_text().split(os.linesep)
# skip the time estimation line
lines = [line for line in old_lines
if not line.endswith(time_estimation_suffix)]
if eta_text:
lines.append(eta_text)
self._progress_bar.set_text(os.linesep.join(lines))
# show the "show_tool_button" ("hide" is called in the progress decorator)
# TODO: move "in_progress" somewhere else
if self.core.get("toolpath_in_progress"):
self._progress_button.show()
while self._gtk.events_pending():
self._gtk.main_iteration()
if not text or (self._start_time + 5 < current_time):
# We don't store the timining if the text was changed.
# This is especially nice for the snappines during font
# initialization. This exception is only valid for the first
# five seconds of the operation.
self._last_gtk_events_time = current_time
# return if the user requested a break
return self._cancel_requested
# -*- coding: utf-8 -*-
"""
$Id: __init__.py 1061 2011-04-12 13:14:12Z sumpfralle $
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
......
......@@ -142,7 +142,7 @@ class PluginManager(object):
_log.debug("Initializing module %s (%s)" % (plugin_name, filename))
new_plugin = obj(self.core, plugin_name)
if not new_plugin.setup():
raise RuntimeError("Failed to load plugin '%s'" % str(name))
raise RuntimeError("Failed to load plugin '%s'" % str(plugin_name))
else:
self.modules[plugin_name] = new_plugin
......
......@@ -40,10 +40,10 @@ class FontCache(object):
of all available fonts.
"""
def __init__(self, font_dir=None, callback=None):
def __init__(self, font_dir=None, core=None):
self.font_dir = font_dir
self.fonts = {}
self.callback = callback
self.core = core
self._unused_font_files = list(self._get_font_files())
def is_loading_complete(self):
......@@ -96,15 +96,27 @@ class FontCache(object):
return self.fonts.values()[0]
def _load_all_files(self):
if self.core:
progress = self.core.get("progress")
progress.set_multiple(len(self._unused_font_files), "Loading font")
while not self.is_loading_complete():
self._load_next_file()
if self.core:
progress.update_multiple()
self._load_next_file(progress=progress)
if self.core:
progress.finish()
def _load_next_file(self):
def _load_next_file(self, progress=None):
if self.is_loading_complete():
return
filename = self._unused_font_files.pop(0)
charset = pycam.Importers.CXFImporter.import_font(filename,
callback=self.callback)
if progress:
callback = progress.update
else:
callback = None
charset = pycam.Importers.CXFImporter.import_font(filename, callback=callback)
if progress:
progress.finish()
if not charset is None:
for name in charset.get_names():
self.fonts[name] = charset
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment