]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/layout/NasalWidget.cxx
canvas::Layout: proper cleanup/update on removing items.
[simgear.git] / simgear / canvas / layout / NasalWidget.cxx
1 // Glue for GUI layout items implemented in Nasal space
2 //
3 // Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #include "NasalWidget.hxx"
20
21 #include <simgear/canvas/Canvas.hxx>
22 #include <simgear/nasal/cppbind/Ghost.hxx>
23
24 namespace simgear
25 {
26 namespace canvas
27 {
28
29   //----------------------------------------------------------------------------
30   NasalWidget::NasalWidget(naRef impl):
31     Object(impl)
32   {
33
34   }
35
36   //----------------------------------------------------------------------------
37   void NasalWidget::invalidate()
38   {
39     LayoutItem::invalidate();
40     _flags |= LAYOUT_DIRTY;
41   }
42
43   //----------------------------------------------------------------------------
44   void NasalWidget::setGeometry(const SGRect<int>& geom)
45   {
46     if( _geometry != geom )
47       _geometry = geom;
48     else if( !(_flags & LAYOUT_DIRTY) || !_set_geometry )
49       return;
50
51     naContext c = naNewContext();
52     try
53     {
54       _set_geometry(nasal::to_nasal(c, this), geom);
55       _flags &= ~LAYOUT_DIRTY;
56     }
57     catch( std::exception const& ex )
58     {
59       SG_LOG(
60         SG_GUI,
61         SG_WARN,
62         "NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
63       );
64     }
65     naFreeContext(c);
66   }
67
68   //----------------------------------------------------------------------------
69   void NasalWidget::onRemove()
70   {
71     if( !_nasal_impl.valid() )
72       return;
73
74     typedef boost::function<void(nasal::Me)> Deleter;
75
76     naContext c = naNewContext();
77     try
78     {
79       Deleter del =
80         nasal::get_member<Deleter>(c, _nasal_impl.get_naRef(), "onRemove");
81       if( del )
82         del(_nasal_impl.get_naRef());
83     }
84     catch( std::exception const& ex )
85     {
86       SG_LOG(
87         SG_GUI,
88         SG_WARN,
89         "NasalWidget::onRemove: callback error: '" << ex.what() << "'"
90       );
91     }
92     naFreeContext(c);
93   }
94
95   //----------------------------------------------------------------------------
96   void NasalWidget::setSetGeometryFunc(const SetGeometryFunc& func)
97   {
98     _set_geometry = func;
99   }
100
101   //----------------------------------------------------------------------------
102   void NasalWidget::setHeightForWidthFunc(const HeightForWidthFunc& func)
103   {
104     _height_for_width = func;
105     invalidateParent();
106   }
107
108   //----------------------------------------------------------------------------
109   void NasalWidget::setMinimumHeightForWidthFunc(const HeightForWidthFunc& func)
110   {
111     _min_height_for_width = func;
112     invalidateParent();
113   }
114
115   //----------------------------------------------------------------------------
116   void NasalWidget::setSizeHint(const SGVec2i& s)
117   {
118     if( _size_hint == s )
119       return;
120
121     _size_hint = s;
122
123     // TODO just invalidate size_hint? Probably not a performance issue...
124     invalidateParent();
125   }
126
127   //----------------------------------------------------------------------------
128   void NasalWidget::setMinimumSize(const SGVec2i& s)
129   {
130     if( _min_size == s )
131       return;
132
133     _min_size = s;
134     invalidateParent();
135   }
136
137   //----------------------------------------------------------------------------
138   void NasalWidget::setMaximumSize(const SGVec2i& s)
139   {
140     if( _max_size == s )
141       return;
142
143     _max_size = s;
144     invalidateParent();
145   }
146
147   //----------------------------------------------------------------------------
148   bool NasalWidget::hasHeightForWidth() const
149   {
150     return !_height_for_width.empty() || !_min_height_for_width.empty();
151   }
152
153   //----------------------------------------------------------------------------
154   int NasalWidget::heightForWidth(int w) const
155   {
156     return callHeightForWidthFunc( _height_for_width.empty()
157                                  ? _min_height_for_width
158                                  : _height_for_width, w );
159   }
160
161   //----------------------------------------------------------------------------
162   int NasalWidget::minimumHeightForWidth(int w) const
163   {
164     return callHeightForWidthFunc( _min_height_for_width.empty()
165                                  ? _height_for_width
166                                  : _min_height_for_width, w );
167   }
168
169   //----------------------------------------------------------------------------
170   static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
171   {
172     return ctx.to_nasal(NasalWidgetRef(
173       new NasalWidget( ctx.requireArg<naRef>(0) )
174     ));
175   }
176
177   //----------------------------------------------------------------------------
178   void NasalWidget::setupGhost(nasal::Hash& ns)
179   {
180     nasal::Ghost<NasalWidgetRef>::init("canvas.Widget")
181       .bases<LayoutItemRef>()
182       .bases<nasal::ObjectRef>()
183       .method("setSetGeometryFunc", &NasalWidget::setSetGeometryFunc)
184       .method("setMinimumHeightForWidthFunc",
185                                     &NasalWidget::setMinimumHeightForWidthFunc)
186       .method("setHeightForWidthFunc", &NasalWidget::setHeightForWidthFunc)
187       .method("setSizeHint", &NasalWidget::setSizeHint)
188       .method("setMinimumSize", &NasalWidget::setMinimumSize)
189       .method("setMaximumSize", &NasalWidget::setMaximumSize);
190
191     nasal::Hash widget_hash = ns.createHash("Widget");
192     widget_hash.set("new", &f_makeNasalWidget);
193   }
194
195   //----------------------------------------------------------------------------
196   int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
197                                            int w ) const
198   {
199     if( hfw.empty() )
200       return -1;
201
202     naContext c = naNewContext();
203     try
204     {
205       return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
206     }
207     catch( std::exception const& ex )
208     {
209       SG_LOG(
210         SG_GUI,
211         SG_WARN,
212         "NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
213       );
214     }
215     naFreeContext(c);
216
217     return -1;
218   }
219
220   //----------------------------------------------------------------------------
221   SGVec2i NasalWidget::sizeHintImpl() const
222   {
223     return _size_hint;
224   }
225
226   //----------------------------------------------------------------------------
227   SGVec2i NasalWidget::minimumSizeImpl() const
228   {
229     return _min_size;
230   }
231
232   //----------------------------------------------------------------------------
233   SGVec2i NasalWidget::maximumSizeImpl() const
234   {
235     return _max_size;
236   }
237
238 } // namespace canvas
239 } // namespace simgear