Merge remote-tracking branch 'origin/bugfix/issue-2356' into wip

This commit is contained in:
Matthias Koefferlein 2026-05-25 20:51:55 +02:00
commit 4db6afb5f3
28 changed files with 665 additions and 216 deletions

View File

@ -594,12 +594,12 @@
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="t_snap_cbx">
<widget class="QCheckBox" name="t_never_snap_cbx">
<property name="toolTip">
<string>If checked, snap to edges or vertices of objects unless disabled above</string>
</property>
<property name="text">
<string>Snap to objects</string>
<string>Never snap to objects</string>
</property>
</widget>
</item>
@ -893,7 +893,7 @@
<tabstop>style_cb</tabstop>
<tabstop>outline_cb</tabstop>
<tabstop>t_angle_cb</tabstop>
<tabstop>t_snap_cbx</tabstop>
<tabstop>t_never_snap_cbx</tabstop>
</tabstops>
<resources>
<include location="../../icons/icons.qrc"/>

242
src/ant/ant/RulerOptions.ui Normal file
View File

@ -0,0 +1,242 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RulerOptions</class>
<widget class="QWidget" name="RulerOptions">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>446</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>446</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Snapping</string>
</property>
<layout class="QGridLayout" name="_5">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="snap_to_grid_cbx">
<property name="text">
<string>Snap to grid</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="snap_to_objects_cbx">
<property name="text">
<string>Snap to edge/vertex</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Angle Constraints</string>
</property>
<layout class="QGridLayout" name="_2">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="1">
<widget class="QComboBox" name="angle_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Any Angle</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal only</string>
</property>
</item>
<item>
<property name="text">
<string>Orthogonal</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal only</string>
</property>
</item>
<item>
<property name="text">
<string>Vertical only</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Ruler direction</string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Note: certain rulers may ignore these options</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>70</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>scrollArea</tabstop>
<tabstop>snap_to_grid_cbx</tabstop>
<tabstop>snap_to_objects_cbx</tabstop>
<tabstop>angle_cb</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -14,6 +14,7 @@ FORMS = \
RulerConfigPage3.ui \
RulerConfigPage4.ui \
RulerPropertiesPage.ui \
RulerOptions.ui \
}
@ -22,10 +23,12 @@ FORMS = \
HEADERS = \
antConfigPage.h \
antPropertiesPage.h \
antRulerOptionsPage.h
SOURCES = \
antConfigPage.cc \
antPropertiesPage.cc \
antRulerOptionsPage.cc
# Enabled without Qt:

View File

@ -375,7 +375,7 @@ ConfigPage4::show ()
mp_ui->style_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].style ());
mp_ui->outline_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].outline ());
mp_ui->t_angle_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].angle_constraint ());
mp_ui->t_snap_cbx->setChecked (m_ruler_templates [m_current_template].snap ());
mp_ui->t_never_snap_cbx->setChecked (! m_ruler_templates [m_current_template].snap ());
mp_ui->t_mode_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].mode ());
mp_ui->main_position->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].main_position ());
@ -410,7 +410,7 @@ ConfigPage4::commit ()
ant::Template::ruler_mode_type mode = ant::Template::ruler_mode_type (mp_ui->t_mode_cb->currentIndex ());
m_ruler_templates [m_current_template].set_mode (mode);
m_ruler_templates [m_current_template].snap (mp_ui->t_snap_cbx->isChecked ());
m_ruler_templates [m_current_template].snap (! mp_ui->t_never_snap_cbx->isChecked ());
m_ruler_templates [m_current_template].set_main_position (Object::position_type (mp_ui->main_position->currentIndex ()));
m_ruler_templates [m_current_template].set_main_xalign (Object::alignment_type (mp_ui->main_xalign->currentIndex ()));

View File

@ -25,6 +25,7 @@
#include "layConverters.h"
#include "layDispatcher.h"
#include "layAbstractMenu.h"
#include "layLayoutViewBase.h"
#include "tlColor.h"
#include "tlLog.h"
#if defined(HAVE_QT)
@ -139,11 +140,10 @@ PluginDeclaration::create_plugin (db::Manager *manager, lay::Dispatcher *, lay::
}
std::vector<std::string>
PluginDeclaration::additional_editor_options_pages () const
PluginDeclaration::additional_editor_options_pages (lay::LayoutViewBase * /*view*/) const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
names.push_back ("ant::RulerOptions");
return names;
}

View File

@ -54,7 +54,7 @@ public:
virtual void uninitialize (lay::Dispatcher *);
virtual bool menu_activated (const std::string &symbol) const;
virtual std::vector<std::string> additional_editor_options_pages () const;
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *view) const;
void register_annotation_template (const ant::Template &t, lay::Plugin *plugin = 0);
void unregister_annotation_template (const std::string &category, lay::Plugin *plugin = 0);

View File

@ -0,0 +1,119 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2026 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 defined(HAVE_QT)
#include "antRulerOptionsPage.h"
#include "antConfig.h"
#include "laySnap.h"
#include "layConverters.h"
#include "layDispatcher.h"
#include "tlString.h"
#include "tlClassRegistry.h"
#include "ui_RulerOptions.h"
namespace ant
{
// ------------------------------------------------------------------
// RulerOptionsPage implementation
RulerOptionsPage::RulerOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::RulerOptions ();
mp_ui->setupUi (this);
connect (mp_ui->angle_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->snap_to_grid_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
connect (mp_ui->snap_to_objects_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
}
RulerOptionsPage::~RulerOptionsPage ()
{
delete mp_ui;
mp_ui = 0;
}
std::string
RulerOptionsPage::title () const
{
return tl::to_string (QObject::tr ("Ruler Options"));
}
// Must match order in angle_cb
static std::vector<lay::angle_constraint_type> s_ac_options =
{
lay::AC_Any,
lay::AC_Diagonal,
lay::AC_DiagonalOnly,
lay::AC_Ortho,
lay::AC_Horizontal,
lay::AC_Vertical
};
void
RulerOptionsPage::apply (lay::Dispatcher *root)
{
lay::angle_constraint_type ac = lay::AC_Any;
int ai = mp_ui->angle_cb->currentIndex ();
if (ai >= 0 && ai < int (s_ac_options.size ())) {
ac = s_ac_options [ai];
}
lay::ACConverter acc;
root->config_set (cfg_ruler_snap_mode, acc.to_string (ac));
root->config_set (cfg_ruler_obj_snap, tl::to_string (mp_ui->snap_to_objects_cbx->isChecked ()));
root->config_set (cfg_ruler_grid_snap, tl::to_string (mp_ui->snap_to_grid_cbx->isChecked ()));
}
void
RulerOptionsPage::setup (lay::Dispatcher *root)
{
lay::ACConverter acc;
lay::angle_constraint_type ac;
ac = lay::AC_Any;
root->config_get (cfg_ruler_snap_mode, ac, acc);
for (int ai = 0; ai < int (s_ac_options.size ()); ++ai) {
if (s_ac_options [ai] == ac) {
mp_ui->angle_cb->setCurrentIndex (ai);
}
}
bool snap_to_grid = false;
root->config_get (cfg_ruler_grid_snap, snap_to_grid);
mp_ui->snap_to_grid_cbx->setChecked (snap_to_grid);
bool snap_to_objects = false;
root->config_get (cfg_ruler_obj_snap, snap_to_objects);
mp_ui->snap_to_objects_cbx->setChecked (snap_to_objects);
}
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_ruler_options (new lay::EditorOptionsPageFactory<RulerOptionsPage> ("ant::RulerOptions"), 0);
}
#endif

View File

@ -0,0 +1,66 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2026 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 defined(HAVE_QT)
#ifndef HDR_antRulerOptionsPage
#define HDR_antRulerOptionsPage
#include "antCommon.h"
#include "layEditorOptionsPageWidget.h"
namespace Ui
{
class RulerOptions;
}
namespace ant
{
/**
* @brief The generic properties page
*/
class RulerOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
RulerOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~RulerOptionsPage ();
virtual std::string title () const;
virtual int order () const { return -10; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
private:
Ui::RulerOptions *mp_ui;
};
}
#endif
#endif

View File

@ -1610,7 +1610,7 @@ Service::move_transform (const db::DPoint & /*p*/, db::DFTrans tr, lay::angle_co
return;
}
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
auto ac_eff = ac == lay::AC_Global ? lay::AC_Any : ac;
clear_mouse_cursors ();
if (m_move_mode == MoveSelected) {
@ -1634,11 +1634,12 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
return;
}
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
clear_mouse_cursors ();
if (m_move_mode == MoveSelected) {
auto ac_eff = ac == lay::AC_Global ? lay::AC_Any : ac;
db::DVector dp = p - m_p1;
dp = lay::snap_angle (dp, ac_eff);
@ -1656,7 +1657,28 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
} else if (m_move_mode != MoveNone) {
db::DPoint ps = snap2_visual (m_p1, p, &m_current, ac);
db::DPoint ps;
if (m_move_mode == MoveP1 && m_current.segments () == 1) {
// when moving p1 in a normal ruler, observe the currently active angle constraints and use p2 as reference
db::DPoint pref = m_current.seg_p2 (m_seg_index);
ps = snap2_visual (pref, p, &m_current, ac);
} else if (m_move_mode == MoveP2 && m_current.segments () == 1) {
// when moving p2 in a normal ruler, observe the currently active angle constraints and use p1 as reference
db::DPoint pref = m_current.seg_p1 (m_seg_index);
ps = snap2_visual (pref, p, &m_current, ac);
} else {
// other move modes use the angle constraint imposed by the modifier buttons
// and the start point for reference
ps = snap2_visual (m_p1, p, &m_current, ac == lay::AC_Global ? lay::AC_Any : ac);
}
m_trans = db::DTrans (ps - m_p1);
apply_partial_move (ps);

View File

@ -458,7 +458,7 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
std::string param_name;
read_word_or_quoted (param_name);
int primary = read_int ();
int default_value = read_double ();
double default_value = read_double ();
if (! dc->has_parameter_with_name (param_name)) {
db::DeviceParameterDefinition pd;
pd.set_name (param_name);

View File

@ -33,14 +33,14 @@
just being horizontal. By default, the ruler uses the global setting. It can however be configured
to provide its own constraint.
</li>
<li><b>Object snapping:</b> each ruler can be configure to snap to the closest object edge or vertex.
By default, the rulers use the global setting. It may be disabled however for each ruler.
</li>
<li><b>Mode:</b> in normal mode, two clicks are required to define a ruler: to set the first
point and to set the second one. In "Single click" mode, a single click will set both
points to the same. In "Auto measure" mode, the points will be determined by looking
for edges in the vicinity of the click point and adjusting the points accordingly.
</li>
<li><b>Never snap to objects:</b> if this option is on, the ruler never snaps to drawing
objects, even if that global option is enabled.
</li>
</ul>
<p>

View File

@ -142,8 +142,8 @@ public:
}
}
virtual std::vector<std::string> additional_editor_options_pages () const
{
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *) const
{
std::vector<std::string> names;
names.push_back ("GenericEditorOptions");
return names;
@ -415,7 +415,7 @@ public:
return true;
}
virtual std::vector<std::string> additional_editor_options_pages () const
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *) const
{
std::vector<std::string> names;
names.push_back ("GenericEditorOptions");

View File

@ -62,15 +62,6 @@ PluginDeclaration::get_options (std::vector < std::pair<std::string, std::string
options.push_back (std::pair<std::string, std::string> (cfg_images_visible, "true"));
}
std::vector<std::string>
PluginDeclaration::additional_editor_options_pages () const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
return names;
}
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new img::PluginDeclaration (), 4000, "img::Plugin");
}

View File

@ -39,7 +39,6 @@ public:
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *, lay::LayoutViewBase *view) const;
virtual bool implements_editable (std::string &title) const;
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const;
virtual std::vector<std::string> additional_editor_options_pages () const;
};
}

View File

@ -56,6 +56,7 @@ static const std::string cfg_show_hierarchy_panel ("show-hierarchy-panel");
static const std::string cfg_show_libraries_view ("show-libraries-view");
static const std::string cfg_show_bookmarks_view ("show-bookmarks-view");
static const std::string cfg_show_layer_panel ("show-layer-panel");
static const std::string cfg_show_tool_options ("show-tool-options");
static const std::string cfg_window_state ("window-state");
static const std::string cfg_layout_file_watcher_enabled ("layout-file-watcher-enabled");
static const std::string cfg_window_geometry ("window-geometry");

View File

@ -74,6 +74,7 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_show_libraries_view, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_bookmarks_view, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_show_layer_panel, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_tool_options, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_layout_file_watcher_enabled, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_window_state, ""));
options.push_back (std::pair<std::string, std::string> (cfg_window_geometry, ""));

View File

@ -274,6 +274,34 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
connect (action, SIGNAL (triggered ()), this, SLOT (clone ()));
mp_tab_bar->addAction (action);
mp_view_stack = new ViewWidgetStack (mp_main_frame);
mp_view_stack->setObjectName (QString::fromUtf8 ("view_stack"));
vbl->addWidget (mp_view_stack);
mp_navigator_dock_widget = new QDockWidget (QObject::tr ("Navigator"), this);
mp_navigator_dock_widget->setObjectName (QString::fromUtf8 ("navigator_dock_widget"));
mp_navigator = new Navigator (this);
mp_navigator_dock_widget->setWidget (mp_navigator);
mp_navigator_dock_widget->setFocusProxy (mp_navigator);
connect (mp_navigator_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_navigator_visible = true;
mp_lp_dock_widget = new QDockWidget (QObject::tr ("Layers"), this);
mp_lp_dock_widget->setObjectName (QString::fromUtf8 ("lp_dock_widget"));
mp_lp_stack = new ControlWidgetStack (mp_lp_dock_widget, "lp_stack");
mp_lp_dock_widget->setWidget (mp_lp_stack);
mp_lp_dock_widget->setFocusProxy (mp_lp_stack);
connect (mp_lp_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_lp_visible = true;
mp_layer_toolbox_dock_widget = new QDockWidget (QObject::tr ("Layer Toolbox"), this);
mp_layer_toolbox_dock_widget->setObjectName (QString::fromUtf8 ("lt_dock_widget"));
mp_layer_toolbox_stack = new ControlWidgetStack (mp_layer_toolbox_dock_widget, "layer_toolbox_stack", true);
mp_layer_toolbox_dock_widget->setWidget (mp_layer_toolbox_stack);
mp_layer_toolbox_dock_widget->setFocusProxy (mp_layer_toolbox_stack);
connect (mp_layer_toolbox_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_layer_toolbox_visible = true;
mp_hp_dock_widget = new QDockWidget (QObject::tr ("Cells"), this);
mp_hp_dock_widget->setObjectName (QString::fromUtf8 ("hp_dock_widget"));
mp_hp_stack = new ControlWidgetStack (mp_hp_dock_widget, "hp_stack");
@ -290,15 +318,6 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
connect (mp_libs_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_libs_visible = true;
mp_eo_dock_widget = new QDockWidget (QObject::tr ("Editor Options"), this);
mp_eo_dock_widget->setObjectName (QString::fromUtf8 ("eo_dock_widget"));
mp_eo_dock_widget->setMinimumHeight (150);
mp_eo_stack = new ControlWidgetStack (mp_eo_dock_widget, "eo_stack");
mp_eo_dock_widget->setWidget (mp_eo_stack);
mp_eo_dock_widget->setFocusProxy (mp_eo_stack);
connect (mp_eo_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_eo_visible = true;
mp_bm_dock_widget = new QDockWidget (QObject::tr ("Bookmarks"), this);
mp_bm_dock_widget->setObjectName (QString::fromUtf8 ("bookmarks_dock_widget"));
mp_bm_stack = new ControlWidgetStack (mp_bm_dock_widget, "bookmarks_stack");
@ -307,33 +326,14 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
connect (mp_bm_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_bm_visible = true;
mp_view_stack = new ViewWidgetStack (mp_main_frame);
mp_view_stack->setObjectName (QString::fromUtf8 ("view_stack"));
vbl->addWidget (mp_view_stack);
mp_layer_toolbox_dock_widget = new QDockWidget (QObject::tr ("Layer Toolbox"), this);
mp_layer_toolbox_dock_widget->setObjectName (QString::fromUtf8 ("lt_dock_widget"));
mp_layer_toolbox_stack = new ControlWidgetStack (mp_layer_toolbox_dock_widget, "layer_toolbox_stack", true);
mp_layer_toolbox_dock_widget->setWidget (mp_layer_toolbox_stack);
mp_layer_toolbox_dock_widget->setFocusProxy (mp_layer_toolbox_stack);
connect (mp_layer_toolbox_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_layer_toolbox_visible = true;
mp_lp_dock_widget = new QDockWidget (QObject::tr ("Layers"), this);
mp_lp_dock_widget->setObjectName (QString::fromUtf8 ("lp_dock_widget"));
mp_lp_stack = new ControlWidgetStack (mp_lp_dock_widget, "lp_stack");
mp_lp_dock_widget->setWidget (mp_lp_stack);
mp_lp_dock_widget->setFocusProxy (mp_lp_stack);
connect (mp_lp_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_lp_visible = true;
mp_navigator_dock_widget = new QDockWidget (QObject::tr ("Navigator"), this);
mp_navigator_dock_widget->setObjectName (QString::fromUtf8 ("navigator_dock_widget"));
mp_navigator = new Navigator (this);
mp_navigator_dock_widget->setWidget (mp_navigator);
mp_navigator_dock_widget->setFocusProxy (mp_navigator);
connect (mp_navigator_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_navigator_visible = true;
mp_eo_dock_widget = new QDockWidget (QObject::tr ("Tool Options"), this);
mp_eo_dock_widget->setObjectName (QString::fromUtf8 ("eo_dock_widget"));
mp_eo_dock_widget->setMinimumHeight (150);
mp_eo_stack = new ControlWidgetStack (mp_eo_dock_widget, "eo_stack");
mp_eo_dock_widget->setWidget (mp_eo_stack);
mp_eo_dock_widget->setFocusProxy (mp_eo_stack);
connect (mp_eo_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_eo_visible = true;
// Add dock widgets
#if QT_VERSION >= 0x040500
@ -567,7 +567,7 @@ MainWindow::technology_changed ()
}
void
MainWindow::dock_widget_visibility_changed (bool visible)
MainWindow::dock_widget_visibility_changed (bool /*visible*/)
{
if (sender () == mp_lp_dock_widget) {
dispatcher ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ()));
@ -582,7 +582,7 @@ MainWindow::dock_widget_visibility_changed (bool visible)
} else if (sender () == mp_layer_toolbox_dock_widget) {
dispatcher ()->config_set (cfg_show_layer_toolbox, tl::to_string (!mp_layer_toolbox_dock_widget->isHidden ()));
} else if (sender () == mp_eo_dock_widget) {
m_eo_visible = visible;
dispatcher ()->config_set (cfg_show_tool_options, tl::to_string (!mp_eo_dock_widget->isHidden ()));
}
}
@ -1133,6 +1133,17 @@ MainWindow::configure (const std::string &name, const std::string &value)
return true;
} else if (name == cfg_show_tool_options) {
tl::from_string (value, m_eo_visible);
if (m_eo_visible) {
mp_eo_dock_widget->show ();
} else {
mp_eo_dock_widget->hide ();
}
return true;
} else if (name == cfg_navigator_show_images) {
bool flag = false;
@ -1321,6 +1332,7 @@ MainWindow::read_dock_widget_state ()
dispatcher ()->config_set (cfg_show_bookmarks_view, tl::to_string (!mp_bm_dock_widget->isHidden ()));
dispatcher ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ()));
dispatcher ()->config_set (cfg_show_layer_toolbox, tl::to_string (!mp_layer_toolbox_dock_widget->isHidden ()));
dispatcher ()->config_set (cfg_show_tool_options, tl::to_string (!mp_eo_dock_widget->isHidden ()));
}
void
@ -1699,38 +1711,6 @@ MainWindow::select_mode (int m)
}
}
update_editor_options_dock ();
}
}
void
MainWindow::update_editor_options_dock ()
{
// if the current mode supports editing, show the editor options panel
const lay::PluginDeclaration *pd_sel = 0;
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const lay::PluginDeclaration *pd = cls.operator-> ();
if (pd->id () == m_mode) {
pd_sel = pd;
}
}
bool eo_visible = false;
if (mp_eo_stack && pd_sel) {
eo_visible = pd_sel->editable_enabled ();
}
if (current_view () && eo_visible) {
lay::EditorOptionsPageCollection *eo_pages = current_view ()->editor_options_pages ();
if (! eo_pages || ! eo_pages->has_content ()) {
eo_visible = false;
}
}
if (eo_visible != m_eo_visible) {
m_eo_visible = eo_visible;
show_dock_widget (mp_eo_dock_widget, m_eo_visible);
}
}
@ -2499,7 +2479,6 @@ MainWindow::select_view (int index)
current_view_changed ();
update_editor_options_dock ();
clear_current_pos ();
edits_enabled_changed ();
clear_messages ();
@ -4502,7 +4481,6 @@ public:
at = "edit_menu.end";
menu_entries.push_back (lay::separator ("edit_options_group:edit_mode", "edit_menu.end"));
menu_entries.push_back (lay::menu_item ("cm_edit_options", "edit_options:edit_mode", "edit_menu.end", tl::to_string (QObject::tr ("Editor Options")) + "(F3)"));
at = "file_menu.end";
menu_entries.push_back (lay::menu_item ("cm_new_layout", "new_layout:edit:edit_mode", at, tl::to_string (QObject::tr ("New Layout"))));
@ -4568,6 +4546,7 @@ public:
menu_entries.push_back (lay::config_menu_item ("show_hierarchy_panel", at, tl::to_string (QObject::tr ("Cells")), cfg_show_hierarchy_panel, "?"));
menu_entries.push_back (lay::config_menu_item ("show_libraries_view", at, tl::to_string (QObject::tr ("Libraries")), cfg_show_libraries_view, "?"));
menu_entries.push_back (lay::config_menu_item ("show_bookmarks_view", at, tl::to_string (QObject::tr ("Bookmarks")), cfg_show_bookmarks_view, "?"));
menu_entries.push_back (lay::config_menu_item ("show_tool_options", at, tl::to_string (QObject::tr ("Tool Options(F3)")), cfg_show_tool_options, "?"));
menu_entries.push_back (lay::menu_item ("cm_reset_window_state", "reset_window_state", at, tl::to_string (QObject::tr ("Restore Window")))),
menu_entries.push_back (lay::separator ("selection_group", at));
menu_entries.push_back (lay::config_menu_item ("transient_selection", at, tl::to_string (QObject::tr ("Highlight Object Under Mouse")), cfg_sel_transient_mode, "?"));

View File

@ -859,7 +859,6 @@ private:
void interactive_close_view (int from, int to, bool invert_range, bool all_cellviews);
void call_on_current_view (void (lay::LayoutView::*func) (), const std::string &op_desc);
void current_view_changed ();
void update_editor_options_dock ();
void update_window_title ();
void update_tab_title (int i);
void add_view (LayoutViewWidget *view);

View File

@ -576,6 +576,7 @@ Navigator::showEvent (QShowEvent *)
void
Navigator::closeEvent (QCloseEvent *)
{
// TODO: this is most likely never called
mp_main_window->dispatcher ()->config_set (cfg_show_navigator, "false");
mp_main_window->dispatcher ()->config_end ();
}

View File

@ -1280,32 +1280,139 @@ AbstractMenu::extra_menu_name ()
void
AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
{
if (tbar) {
tbar->clear ();
}
std::set<std::pair<size_t, QAction *> > present_actions;
// Build the menu bar
if (mbar) {
std::set<std::pair<size_t, QAction *> > present_actions;
QList<QAction *> a = mbar->actions ();
for (QList<QAction *>::const_iterator i = a.begin (); i != a.end (); ++i) {
present_actions.insert (std::make_pair (id_from_action (*i), *i));
}
// NOTE: on MacOS, once the top level menu is created, we should not
// modify it and place menu items into the "Extras" menu instead.
bool menu_frozen = ! s_can_move_menu && ! present_actions.empty ();
// NOTE: the "extras" menu is relevant on MacOS only
QMenu *extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->clear ();
}
QAction *prev_action = 0;
for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) {
if (c->has_submenu ()) {
if (c->name ().find ("@") == 0) {
// done later.
} else {
if (c->menu () == 0) {
// NOTE: we intentionally do not make the item owner of the menu action
// as implicitly deleting it might cause trouble on MacOS. Instead we
// explicitly delete below or keep the action.
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
menu->setTitle (tl::to_qstring (c->action ()->get_title ()));
c->set_action (new Action (menu, false), true);
// This case happens when we dynamically create menus.
// MacOS does not like generating top-level menus dynamically, so
// we put them into the "_extra" top level one.
if (menu_frozen) {
if (extras_menu) {
extras_menu->addMenu (menu);
}
} else {
prev_action = insert_action_after (mbar, prev_action, menu->menuAction ());
}
} else {
// Move the action to the end if present in the menu already
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
if (a != present_actions.end ()) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
insert_action_after (mbar, prev_action, a->second);
}
prev_action = a->second;
present_actions.erase (*a);
} else if (menu_frozen) {
if (extras_menu) {
extras_menu->addMenu (c->menu ());
}
} else {
prev_action = insert_action_after (mbar, prev_action, c->menu ()->menuAction ());
}
}
// NOTE: the "extras" menu is built implicitly. You cannot put anything there.
if (c->menu () != extras_menu) {
build (c->menu (), c->children);
}
}
} else {
// Move the action to the end if present in the menu already
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ()->qaction ()), c->action ()->qaction ()));
if (a != present_actions.end ()) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
insert_action_after (mbar, prev_action, a->second);
}
prev_action = a->second;
present_actions.erase (*a);
} else if (menu_frozen) {
QMenu *extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->addAction (c->action ()->qaction ());
}
} else {
prev_action = insert_action_after (mbar, prev_action, c->action ()->qaction ());
}
}
}
// Disable the (maybe new) "extras" menu if empty
extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->setEnabled (! extras_menu->isEmpty ());
}
// Remove all actions that have vanished
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
delete a->second;
} else {
if (a->second->menu ()) {
a->second->menu ()->clear ();
}
a->second->setEnabled (false);
}
}
}
// NOTE: on MacOS, once the top level menu is created, we should not
// modify it and place menu items into the "Extras" menu instead.
bool menu_frozen = ! s_can_move_menu && ! present_actions.empty ();
// Finally build the context menus and toolbar.
// NOTE: this is done afterwards, as generating the submenus, specifically for the toolbar menu buttons
// messes with the QActions stored in "present_actions".
// NOTE: the "extras" menu is relevant on MacOS only
QMenu *extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->clear ();
if (tbar) {
tbar->clear ();
}
QAction *prev_action = 0;
for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) {
if (c->has_submenu ()) {
@ -1338,100 +1445,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
// prepare a detached menu which can be used as context menus
build (c->menu (), c->children);
} else if (mbar) {
if (c->menu () == 0) {
// NOTE: we intentionally do not make the item owner of the menu action
// as implicitly deleting it might cause trouble on MacOS. Instead we
// explicitly delete below or keep the action.
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
menu->setTitle (tl::to_qstring (c->action ()->get_title ()));
c->set_action (new Action (menu, false), true);
// This case happens when we dynamically create menus.
// MacOS does not like generating top-level menus dynamically, so
// we put them into the "_extra" top level one.
if (menu_frozen) {
if (extras_menu) {
extras_menu->addMenu (menu);
}
} else {
prev_action = insert_action_after (mbar, prev_action, menu->menuAction ());
}
} else {
// Move the action to the end if present in the menu already
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
if (a != present_actions.end ()) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
insert_action_after (mbar, prev_action, a->second);
}
prev_action = a->second;
present_actions.erase (*a);
} else if (menu_frozen) {
if (extras_menu) {
extras_menu->addMenu (c->menu ());
}
} else {
prev_action = insert_action_after (mbar, prev_action, c->menu ()->menuAction ());
}
}
// NOTE: the "extras" menu is built implicitly. You cannot put anything there.
if (c->menu () != extras_menu) {
build (c->menu (), c->children);
}
}
} else if (mbar) {
// Move the action to the end if present in the menu already
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ()->qaction ()), c->action ()->qaction ()));
if (a != present_actions.end ()) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
insert_action_after (mbar, prev_action, a->second);
}
prev_action = a->second;
present_actions.erase (*a);
} else if (menu_frozen) {
QMenu *extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->addAction (c->action ()->qaction ());
}
} else {
prev_action = insert_action_after (mbar, prev_action, c->action ()->qaction ());
}
}
}
// Disable the (maybe new) "extras" menu if empty
extras_menu = find_extras_menu (mbar);
if (extras_menu) {
extras_menu->setEnabled (! extras_menu->isEmpty ());
}
// Remove all actions that have vanished
if (mbar) {
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
if (s_can_move_menu) {
mbar->removeAction (a->second);
delete a->second;
} else {
if (a->second->menu ()) {
a->second->menu ()->clear ();
}
a->second->setEnabled (false);
}
}
}
}
void

View File

@ -482,11 +482,15 @@ public:
return new MoveService (view);
}
virtual std::vector<std::string> additional_editor_options_pages () const
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *view) const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
if (view->is_editable ()) {
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
}
// TODO: provide in a central place instead of borrowing from the ant module
names.push_back ("ant::RulerOptions");
return names;
}
};

View File

@ -354,7 +354,7 @@ public:
* In addition to providing pages through "get_editor_options_pages", the plugin can request pages
* from globally registered factories by name.
*/
virtual std::vector<std::string> additional_editor_options_pages () const
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase * /*view*/) const
{
return std::vector<std::string> ();
}

View File

@ -333,11 +333,13 @@ public:
return new SelectionService (view);
}
virtual std::vector<std::string> additional_editor_options_pages () const
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *view) const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
if (view->is_editable ()) {
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
}
return names;
}
};

View File

@ -554,7 +554,7 @@ private:
}
}
if (! any_point) {
if (! any_point && ! m_projection_constraint) {
// no certain direction to look into:
// compute the projection of the point and if within a

View File

@ -318,7 +318,7 @@ public:
m_additional_editor_options_pages.push_back (name);
}
virtual std::vector<std::string> additional_editor_options_pages () const
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *) const
{
return m_additional_editor_options_pages;
}

View File

@ -56,7 +56,7 @@ EditorOptionsFrame::populate (LayoutViewBase *view)
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
cls->get_editor_options_pages (editor_options_pages, view, view->dispatcher ());
std::vector<std::string> ap = cls->additional_editor_options_pages ();
std::vector<std::string> ap = cls->additional_editor_options_pages (view);
for (auto i = ap.begin (); i != ap.end (); ++i) {
additional_pages [*i].push_back (cls.operator-> ());
}

View File

@ -482,7 +482,7 @@ EditorOptionsModalPages::update_title ()
if (mp_single_page) {
setWindowTitle (tl::to_qstring (mp_single_page->title ()));
} else {
setWindowTitle (tr ("Editor Options"));
setWindowTitle (tr ("Tool Options"));
}
}

View File

@ -582,6 +582,8 @@
</customwidgets>
<tabstops>
<tabstop>le_pixel_size</tabstop>
<tabstop>le_window_size</tabstop>
<tabstop>cb_boundary_mode</tabstop>
<tabstop>sb_threads</tabstop>
<tabstop>layer_cb</tabstop>
<tabstop>cb_source_layer</tabstop>