Merge pull request #1587 from KLayout/issue-1583

Implemented solution for issue #1583
This commit is contained in:
Matthias Köfferlein 2024-01-06 11:30:27 +01:00 committed by GitHub
commit e2f7318236
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 177 additions and 10 deletions

View File

@ -656,6 +656,30 @@ Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M
"it can be beneficial for test or automation purposes, i.e. if a screenshot needs to be " "it can be beneficial for test or automation purposes, i.e. if a screenshot needs to be "
"produced once the application has finished drawing." "produced once the application has finished drawing."
) + ) +
gsi::method ("synchronous", &lay::MainWindow::synchronous,
"@brief Gets a value indicating whether synchronous mode is activated\n"
"See \\synchronous= for details about this attribute\n"
"\n"
"This property getter was introduced in version 0.29."
) +
gsi::method ("title=", &lay::MainWindow::set_title, gsi::arg ("title"),
"@brief Sets the window title\n"
"If the window title is not empty, it will be used for the application window's title. Otherwise "
"the default title is used. The title string is subject to expression interpolation. So it is "
"possible to implement the default scheme of adding the current view using the following code:\n"
"\n"
"@code\n"
"add_view_info = \"$(var view=LayoutView.current; view ? ' - ' + (view.is_dirty ? '[+] ' : '') + view.title : '')\"\n"
"RBA::MainWindow.instance.title = \"Custom Title\" + add_view_info\n"
"@/code\n"
"\n"
"This property was introduced in version 0.29."
) +
gsi::method ("title", &lay::MainWindow::title,
"@brief Gets the window title\n"
"See \\title= for a description of this property.\n"
"This property was introduced in version 0.29."
) +
gsi::method ("close_all", &lay::MainWindow::close_all, gsi::method ("close_all", &lay::MainWindow::close_all,
"@brief Closes all views\n" "@brief Closes all views\n"
"\n" "\n"

View File

@ -3597,26 +3597,42 @@ MainWindow::view_title_changed (lay::LayoutView *view)
} }
} }
void
MainWindow::set_title (const std::string &title)
{
if (title != m_title) {
m_title = title;
update_window_title ();
}
}
void void
MainWindow::update_window_title () MainWindow::update_window_title ()
{ {
std::string title = m_title;
if (! title.empty ()) {
tl::Eval eval;
title = eval.interpolate (title);
} else {
title = lay::ApplicationBase::version ();
if (current_view ()) { if (current_view ()) {
std::string sep = " - "; std::string sep = " - ";
if (current_view ()->is_dirty ()) { if (current_view ()->is_dirty ()) {
sep += "[+] "; sep += "[+] ";
} }
setWindowTitle (tl::to_qstring (lay::ApplicationBase::version () + sep + current_view ()->title ())); title += sep + current_view ()->title ();
} else {
setWindowTitle (tl::to_qstring (lay::ApplicationBase::version ()));
} }
} }
setWindowTitle (tl::to_qstring (title));
}
void void
MainWindow::current_view_changed () MainWindow::current_view_changed ()
{ {
update_window_title (); update_window_title ();
current_view_changed_event (); current_view_changed_event ();
// TODO: required? current_view_changed_event (int (view_index_org));
} }
double double

View File

@ -426,6 +426,22 @@ public:
return m_synchronous; return m_synchronous;
} }
/**
* @brief Sets the title string
*
* If empty, the default title will be created. Otherwise this string will
* be used. It is subject to expression interpolation.
*/
void set_title (const std::string &title);
/**
* @brief Gets the title string
*/
const std::string &title () const
{
return m_title;
}
/** /**
* @brief Returns true, if the edit functions of the current view are enabled * @brief Returns true, if the edit functions of the current view are enabled
*/ */
@ -760,6 +776,7 @@ private:
std::string m_message; std::string m_message;
std::unique_ptr<QPrinter> mp_printer; std::unique_ptr<QPrinter> mp_printer;
std::vector<QString> m_changed_files; std::vector<QString> m_changed_files;
std::string m_title;
// the object manager (undo/redo mechanism and others) // the object manager (undo/redo mechanism and others)
db::Manager m_manager; db::Manager m_manager;

View File

@ -474,6 +474,12 @@ static lay::AbstractMenu *menu (lay::LayoutViewBase *view)
return view->menu (); return view->menu ();
} }
static bool view_is_dirty (lay::LayoutViewBase *view)
{
view->refresh ();
return view->is_dirty ();
}
LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutViewBase", LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutViewBase",
gsi::constant ("LV_NoLayers", (unsigned int) lay::LayoutViewBase::LV_NoLayers, gsi::constant ("LV_NoLayers", (unsigned int) lay::LayoutViewBase::LV_NoLayers,
"@brief With this option, no layers view will be provided (see \\layer_control_frame)\n" "@brief With this option, no layers view will be provided (see \\layer_control_frame)\n"
@ -1136,6 +1142,13 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
"Show the layout in full depth down to the deepest level of hierarchy. " "Show the layout in full depth down to the deepest level of hierarchy. "
"This method may cause a redraw." "This method may cause a redraw."
) + ) +
gsi::method_ext ("is_dirty?", &view_is_dirty,
"@brief Gets a flag indicating whether one of the layouts displayed needs saving\n"
"A layout is 'dirty' if it is modified and needs saving. This method returns "
"true if this is the case for at least one of the layouts shown in the view.\n"
"\n"
"This method has been introduced in version 0.29.\n"
) +
gsi::method ("resize", static_cast<void (lay::LayoutViewBase::*) (unsigned int, unsigned int)> (&lay::LayoutViewBase::resize), gsi::method ("resize", static_cast<void (lay::LayoutViewBase::*) (unsigned int, unsigned int)> (&lay::LayoutViewBase::resize),
"@brief Resizes the layout view to the given dimension\n" "@brief Resizes the layout view to the given dimension\n"
"\n" "\n"

View File

@ -2749,6 +2749,11 @@ public:
return m_options; return m_options;
} }
/**
* @brief Calls deferred methods and updates view ops, provided for GSI bindings mainly
*/
void refresh ();
private: private:
// event handlers used to connect to the layout object's events // event handlers used to connect to the layout object's events
void signal_hier_changed (); void signal_hier_changed ();
@ -2917,8 +2922,6 @@ private:
void init_layer_properties (LayerProperties &props, const LayerPropertiesList &lp_list) const; void init_layer_properties (LayerProperties &props, const LayerPropertiesList &lp_list) const;
void merge_dither_pattern (lay::LayerPropertiesList &props); void merge_dither_pattern (lay::LayerPropertiesList &props);
void refresh ();
protected: protected:
/** /**
* @brief Constructor for calling from a LayoutView * @brief Constructor for calling from a LayoutView

View File

@ -143,6 +143,7 @@ RUBYTEST (extNetTracer, "extNetTracer.rb")
RUBYTEST (imgObject, "imgObject.rb") RUBYTEST (imgObject, "imgObject.rb")
RUBYTEST (layLayers, "layLayers.rb") RUBYTEST (layLayers, "layLayers.rb")
RUBYTEST (layLayoutView, "layLayoutView.rb") RUBYTEST (layLayoutView, "layLayoutView.rb")
RUBYTEST (layMainWindow, "layMainWindow.rb")
RUBYTEST (layMarkers, "layMarkers.rb") RUBYTEST (layMarkers, "layMarkers.rb")
RUBYTEST (layMacro, "layMacro.rb") RUBYTEST (layMacro, "layMacro.rb")
RUBYTEST (layMenuTest, "layMenuTest.rb") RUBYTEST (layMenuTest, "layMenuTest.rb")

View File

@ -570,6 +570,30 @@ class LAYLayoutView_TestClass < TestBase
end end
def test_9
if !RBA.constants.member?(:Application)
return
end
app = RBA::Application.instance
mw = app.main_window
mw.close_all
mw.create_layout(1)
assert_equal(false, mw.current_view.is_dirty?)
cv = mw.current_view.cellview(0)
cv.cell = cv.layout.create_cell("TOP")
assert_equal(true, mw.current_view.cellview(0).is_dirty?)
if cv.layout.is_editable?
assert_equal(true, mw.current_view.is_dirty?)
end
end
end end
load("test_epilogue.rb") load("test_epilogue.rb")

69
testdata/ruby/layMainWindow.rb vendored Normal file
View File

@ -0,0 +1,69 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2024 Matthias Koefferlein
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
if !$:.member?(File::dirname($0))
$:.push(File::dirname($0))
end
load("test_prologue.rb")
class LAYMainWindow_TestClass < TestBase
# Basic view creation and MainWindow events
def test_1
if !RBA.constants.member?(:Application)
return
end
app = RBA::Application.instance
mw = app.main_window
mw.title = "ABC$(1+2)"
assert_equal("ABC$(1+2)", mw.title)
if RBA.constants.member?(:QWidget)
# string is interpolated
assert_equal("ABC3", mw.windowTitle)
end
end
def test_2
# smoke test
app = RBA::Application.instance
mw = app.main_window
s = mw.synchronous
mw.synchronous = true
assert_equal(true, mw.synchronous)
mw.synchronous = false
assert_equal(false, mw.synchronous)
mw.synchronous = true
end
end
load("test_epilogue.rb")