Bug fixes and tests for LayoutView

This commit is contained in:
Matthias Koefferlein 2022-05-05 23:37:33 +02:00
parent 0877de73d4
commit 6feed82808
19 changed files with 235 additions and 48 deletions

View File

@ -327,7 +327,7 @@ static void save_as2 (lay::LayoutView *view, unsigned int index, const std::stri
view->save_as (index, filename, tl::OutputStream::OM_Auto, options, true, 0);
}
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QTBINDINGS) // @@@
static QImage get_image_with_options (lay::LayoutView *view, unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution, const db::DBox &target_box, bool monochrome)
{
return view->get_image_with_options (width, height, linewidth, oversampling, resolution, lay::Color (), lay::Color (), lay::Color (), target_box, monochrome);

View File

@ -37,13 +37,11 @@
#include "layRedrawThread.h"
#include "layLayoutView.h"
#include "layMarker.h"
#if defined(HAVE_QT) // @@@
#if defined(HAVE_QT)
# include "gtf.h"
#endif
#if defined(HAVE_QT) // @@@
#include "layBitmapsToImage.h"
#endif
#include <sstream>
#include <algorithm>

View File

@ -94,7 +94,7 @@ static LayoutView *ms_current = 0;
LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options)
: QFrame (parent),
LayoutViewBase (manager, editable, plugin_parent, options),
LayoutViewBase (this, this, manager, editable, plugin_parent, options),
dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages)
{
// ensures the deferred method scheduler is present
@ -106,7 +106,7 @@ LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin
LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options)
: QFrame (parent),
LayoutViewBase (source, manager, editable, plugin_parent, options),
LayoutViewBase (this, this, source, manager, editable, plugin_parent, options),
dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages)
{
// ensures the deferred method scheduler is present
@ -1117,13 +1117,13 @@ namespace lay
{
LayoutView::LayoutView (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options)
: LayoutViewBase (mgr, editable, plugin_parent, options)
: LayoutViewBase (this, mgr, editable, plugin_parent, options)
{
// .. nothing yet ..
}
LayoutView::LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options)
: LayoutViewBase (source, mgr, editable, plugin_parent, options)
: LayoutViewBase (this, source, mgr, editable, plugin_parent, options)
{
// .. nothing yet ..
}

View File

@ -413,11 +413,6 @@ public:
return mp_editor_options_frame;
}
/**
* @brief Gets the QWidget interface
*/
virtual QWidget *widget () { return this; }
/**
* @brief Copies to clipboard
*
@ -758,12 +753,6 @@ protected:
virtual void emit_dirty_changed ();
virtual void emit_layer_order_changed ();
protected:
/**
* @brief Gets the LayoutView interface
*/
virtual LayoutView *get_ui () { return this; }
private:
using LayoutViewBase::ui;
};

View File

@ -232,8 +232,16 @@ struct OpDeleteLayerProps
const double animation_interval = 0.5;
LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#if defined(HAVE_QT)
LayoutViewBase::LayoutViewBase (QWidget *widget, lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#else
LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#endif
: lay::Dispatcher (plugin_parent, false /*not standalone*/),
#if defined(HAVE_QT)
mp_widget (widget),
#endif
mp_ui (ui),
m_editable (editable),
m_options (options),
m_annotation_shapes (manager)
@ -244,8 +252,16 @@ LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin
init (manager);
}
LayoutViewBase::LayoutViewBase (lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#if defined(HAVE_QT)
LayoutViewBase::LayoutViewBase (QWidget *widget, lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#else
LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options)
#endif
: lay::Dispatcher (plugin_parent, false /*not standalone*/),
#if defined(HAVE_QT)
mp_widget (widget),
#endif
mp_ui (ui),
m_editable (editable),
m_options (options),
m_annotation_shapes (manager)
@ -274,7 +290,7 @@ LayoutViewBase::LayoutViewBase (lay::LayoutViewBase *source, db::Manager *manage
} else {
*m_layer_properties_lists [i] = *source->m_layer_properties_lists [i];
}
m_layer_properties_lists [i]->attach_view (ui (), (unsigned int) i);
m_layer_properties_lists [i]->attach_view (this, (unsigned int) i);
}
if (! m_layer_properties_lists.empty ()) {
@ -367,7 +383,7 @@ LayoutViewBase::init (db::Manager *mgr)
m_search_range_box = 0;
m_layer_properties_lists.push_back (new LayerPropertiesList ());
m_layer_properties_lists.back ()->attach_view (ui (), (unsigned int) (m_layer_properties_lists.size () - 1));
m_layer_properties_lists.back ()->attach_view (this, (unsigned int) (m_layer_properties_lists.size () - 1));
m_current_layer_list = 0;
#if defined(HAVE_QT)
@ -388,16 +404,16 @@ LayoutViewBase::init (db::Manager *mgr)
// occupy services and editables:
// these services get deleted by the canvas destructor automatically:
if ((m_options & LV_NoTracker) == 0) {
mp_tracker = new lay::MouseTracker (ui ());
mp_tracker = new lay::MouseTracker (this);
}
if ((m_options & LV_NoZoom) == 0) {
mp_zoom_service = new lay::ZoomService (ui ());
mp_zoom_service = new lay::ZoomService (this);
}
if ((m_options & LV_NoSelection) == 0) {
mp_selection_service = new lay::SelectionService (ui ());
mp_selection_service = new lay::SelectionService (this);
}
if ((m_options & LV_NoMove) == 0) {
mp_move_service = new lay::MoveService (ui ());
mp_move_service = new lay::MoveService (this);
}
create_plugins ();
@ -3207,14 +3223,14 @@ LayoutViewBase::box () const
QWidget *
LayoutViewBase::widget ()
{
tl_assert (false);
return mp_widget;
}
#endif
LayoutView *
LayoutViewBase::get_ui ()
{
tl_assert (false);
return mp_ui;
}
// @@@ needs to be called "as often as possible"

View File

@ -183,12 +183,20 @@ public:
/**
* @brief Constructor
*/
LayoutViewBase (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#if defined(HAVE_QT)
LayoutViewBase (QWidget *widget, lay::LayoutView *ui, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#else
LayoutViewBase (lay::LayoutView *ui, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#endif
/**
* @brief Constructor (clone from another view)
*/
LayoutViewBase (lay::LayoutViewBase *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#if defined(HAVE_QT)
LayoutViewBase (QWidget *widget, lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#else
LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal);
#endif
/**
* @brief Destructor
@ -2504,7 +2512,7 @@ public:
/**
* @brief Gets the QWidget interface
*/
virtual QWidget *widget ();
QWidget *widget ();
#endif
/**
@ -2536,6 +2544,10 @@ private:
void signal_apply_technology (lay::LayoutHandle *layout_handle);
private:
#if defined(HAVE_QT)
QWidget *mp_widget;
#endif
lay::LayoutView *mp_ui;
bool m_editable;
int m_disabled_edits;
unsigned int m_options;

View File

@ -28,7 +28,7 @@
namespace lay
{
MouseTracker::MouseTracker (lay::LayoutView *view)
MouseTracker::MouseTracker (lay::LayoutViewBase *view)
: lay::ViewService (view->view_object_widget ()), mp_view (view)
{
widget ()->grab_mouse (this, false);

View File

@ -31,17 +31,17 @@ class QMouseEvent;
namespace lay {
class LayoutCanvas;
class LayoutView;
class LayoutViewBase;
class MouseTracker
: public lay::ViewService
{
public:
MouseTracker (lay::LayoutView *view);
MouseTracker (lay::LayoutViewBase *view);
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
private:
lay::LayoutView *mp_view;
lay::LayoutViewBase *mp_view;
};
}

View File

@ -34,7 +34,7 @@ namespace lay
// -------------------------------------------------------------
// MoveService implementation
MoveService::MoveService (lay::LayoutView *view)
MoveService::MoveService (lay::LayoutViewBase *view)
: lay::ViewService (view->view_object_widget ()),
m_dragging (false),
m_dragging_transient (false),

View File

@ -31,13 +31,13 @@
namespace lay {
class Editables;
class LayoutView;
class LayoutViewBase;
class MoveService :
public lay::ViewService
{
public:
MoveService (lay::LayoutView *view);
MoveService (lay::LayoutViewBase *view);
~MoveService ();
virtual bool configure (const std::string &name, const std::string &value);
@ -59,7 +59,7 @@ private:
bool m_dragging;
bool m_dragging_transient;
lay::Editables *mp_editables;
lay::LayoutView *mp_view;
lay::LayoutViewBase *mp_view;
double m_global_grid;
db::DPoint m_shift;
db::DPoint m_mouse_pos;

View File

@ -37,7 +37,7 @@ namespace lay
// -------------------------------------------------------------
// SelectionService implementation
SelectionService::SelectionService (lay::LayoutView *view)
SelectionService::SelectionService (lay::LayoutViewBase *view)
: QObject (),
lay::ViewService (view->view_object_widget ()),
mp_view (view),

View File

@ -38,7 +38,7 @@
namespace lay {
class RubberBox;
class LayoutView;
class LayoutViewBase;
class LayoutCanvas;
class LAYBASIC_PUBLIC SelectionService :
@ -52,7 +52,7 @@ Q_OBJECT
#endif
public:
SelectionService (lay::LayoutView *view);
SelectionService (lay::LayoutViewBase *view);
~SelectionService ();
void set_colors (lay::Color background, lay::Color color);
@ -88,7 +88,7 @@ private:
db::DPoint m_p1, m_p2;
db::DPoint m_current_position;
lay::LayoutView *mp_view;
lay::LayoutViewBase *mp_view;
lay::RubberBox *mp_box;
unsigned int m_color;
unsigned int m_buttons;

View File

@ -31,7 +31,7 @@ namespace lay
// -------------------------------------------------------------
// ZoomService implementation
ZoomService::ZoomService (lay::LayoutView *view)
ZoomService::ZoomService (lay::LayoutViewBase *view)
: lay::ViewService (view->view_object_widget ()),
mp_view (view),
mp_box (0),

View File

@ -30,7 +30,7 @@
namespace lay
{
class LayoutView;
class LayoutViewBase;
class LayoutCanvas;
class RubberBox;
@ -38,7 +38,7 @@ class LAYBASIC_PUBLIC ZoomService
: public lay::ViewService
{
public:
ZoomService (lay::LayoutView *view);
ZoomService (lay::LayoutViewBase *view);
~ZoomService ();
void set_colors (lay::Color background, lay::Color text);
@ -55,7 +55,7 @@ private:
db::DPoint m_p1, m_p2;
db::DBox m_vp;
lay::LayoutView *mp_view;
lay::LayoutViewBase *mp_view;
lay::RubberBox *mp_box;
unsigned int m_color;
};

View File

@ -0,0 +1,171 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 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
*/
#include "layLayoutView.h"
#include "tlUnitTest.h"
#include "tlTimer.h"
#if defined(HAVE_QT)
# include <QImage>
# include <QPainter>
static bool compare_images (const QImage &qimg, const std::string &au)
{
QImage qimg2;
qimg2.load (tl::to_qstring (au));
if (qimg2.width () == (int) qimg.width () && qimg2.height () == (int) qimg.height ()) {
for (int j = 0; j < qimg.height (); ++j) {
for (int i = 0; i < qimg.width (); ++i) {
if (((const lay::color_t *) qimg.scanLine (j))[i] != ((const lay::color_t *) qimg2.scanLine (j))[i]) {
return false;
}
}
}
return true;
} else {
return false;
}
}
static bool compare_images_mono (const QImage &qimg, const std::string &au)
{
QImage qimg2;
qimg2.load (tl::to_qstring (au));
if (qimg2.width () == (int) qimg.width () && qimg2.height () == (int) qimg.height ()) {
// NOTE: slooooow ...
for (int j = 0; j < qimg.height (); ++j) {
for (int i = 0; i < qimg.width (); ++i) {
if ((qimg.scanLine (j)[i / 8] & (0x80 >> (i % 8))) != (qimg2.scanLine (j)[i / 8] & (0x80 >> (i % 8)))) {
return false;
}
}
}
return true;
} else {
return false;
}
}
static bool compare_images (const lay::PixelBuffer &img, const lay::PixelBuffer &img2)
{
if (img2.width () == img.width () && img2.height () == img.height ()) {
for (unsigned int j = 0; j < img.height (); ++j) {
for (unsigned int i = 0; i < img.width (); ++i) {
if (((const lay::color_t *) img.scan_line (j))[i] != ((const lay::color_t *) img2.scan_line (j))[i]) {
return false;
}
}
}
return true;
} else {
return false;
}
}
static bool compare_images (const lay::BitmapBuffer &img, const lay::BitmapBuffer &img2)
{
if (img2.width () == img.width () && img2.height () == img.height ()) {
for (unsigned int j = 0; j < img.height (); ++j) {
for (unsigned int i = 0; i < img.stride (); ++i) {
if (((const uint8_t *) img.scan_line (j))[i] != ((const uint8_t *) img2.scan_line (j))[i]) {
return false;
}
}
}
return true;
} else {
return false;
}
}
#endif
TEST(1)
{
lay::LayoutView lv (0, false, 0);
lv.cell_box_color (lay::Color (0, 0, 0));
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
QImage qimg;
qimg = lv.get_image_with_options (500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), false);
EXPECT_EQ (qimg.format () == QImage::Format_RGB32, true);
std::string tmp = tmp_file ("test.png");
qimg.save (tl::to_qstring (tmp));
tl::info << "PNG file written to " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv1.png";
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (qimg, au), true);
}
TEST(2)
{
lay::LayoutView lv (0, false, 0);
lv.full_hier_new_cell (true);
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
QImage qimg;
qimg = lv.get_image_with_options (500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), false);
EXPECT_EQ (qimg.format () == QImage::Format_RGB32, true);
std::string tmp = tmp_file ("test.png");
qimg.save (tl::to_qstring (tmp));
tl::info << "PNG file written to " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv2.png";
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (qimg, au), true);
}
// monochrome
TEST(3)
{
lay::LayoutView lv (0, false, 0);
lv.full_hier_new_cell (true);
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
QImage qimg;
qimg = lv.get_image_with_options (500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), true);
EXPECT_EQ (qimg.format () == QImage::Format_RGB32, true);
std::string tmp = tmp_file ("test.png");
qimg.save (tl::to_qstring (tmp));
tl::info << "PNG file written to " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv3.png";
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (qimg, au), true);
}

View File

@ -14,6 +14,7 @@ SOURCES = \
layLayerProperties.cc \
layParsedLayerSource.cc \
layPixelBufferTests.cc \
layLayoutViewTests.cc \
layRenderer.cc \
layNetlistBrowserModelTests.cc \
layNetlistBrowserTreeModelTests.cc \

BIN
testdata/lay/au_lv1.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
testdata/lay/au_lv2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
testdata/lay/au_lv3.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB