]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/layout/NasalWidget.cxx
canvas::NasalWidget: ensure nasal part is destroyed
[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   NasalWidget::~NasalWidget()
38   {
39     onRemove();
40   }
41
42   //----------------------------------------------------------------------------
43   void NasalWidget::invalidate()
44   {
45     LayoutItem::invalidate();
46     _flags |= LAYOUT_DIRTY;
47   }
48
49   //----------------------------------------------------------------------------
50   void NasalWidget::setGeometry(const SGRect<int>& geom)
51   {
52     if( _geometry != geom )
53       _geometry = geom;
54     else if( !(_flags & LAYOUT_DIRTY) || !_set_geometry )
55       return;
56
57     naContext c = naNewContext();
58     try
59     {
60       _set_geometry(nasal::to_nasal(c, this), geom);
61       _flags &= ~LAYOUT_DIRTY;
62     }
63     catch( std::exception const& ex )
64     {
65       SG_LOG(
66         SG_GUI,
67         SG_WARN,
68         "NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
69       );
70     }
71     naFreeContext(c);
72   }
73
74   //----------------------------------------------------------------------------
75   void NasalWidget::onRemove()
76   {
77     if( !_nasal_impl.valid() )
78       return;
79
80     typedef boost::function<void(nasal::Me)> Deleter;
81
82     naContext c = naNewContext();
83     try
84     {
85       Deleter del =
86         nasal::get_member<Deleter>(c, _nasal_impl.get_naRef(), "onRemove");
87       if( del )
88         del(_nasal_impl.get_naRef());
89     }
90     catch( std::exception const& ex )
91     {
92       SG_LOG(
93         SG_GUI,
94         SG_WARN,
95         "NasalWidget::onRemove: callback error: '" << ex.what() << "'"
96       );
97     }
98     naFreeContext(c);
99   }
100
101   //----------------------------------------------------------------------------
102   void NasalWidget::setSetGeometryFunc(const SetGeometryFunc& func)
103   {
104     _set_geometry = func;
105   }
106
107   //----------------------------------------------------------------------------
108   void NasalWidget::setHeightForWidthFunc(const HeightForWidthFunc& func)
109   {
110     _height_for_width = func;
111     invalidateParent();
112   }
113
114   //----------------------------------------------------------------------------
115   void NasalWidget::setMinimumHeightForWidthFunc(const HeightForWidthFunc& func)
116   {
117     _min_height_for_width = func;
118     invalidateParent();
119   }
120
121   //----------------------------------------------------------------------------
122   void NasalWidget::setSizeHint(const SGVec2i& s)
123   {
124     if( _size_hint == s )
125       return;
126
127     _size_hint = s;
128
129     // TODO just invalidate size_hint? Probably not a performance issue...
130     invalidateParent();
131   }
132
133   //----------------------------------------------------------------------------
134   void NasalWidget::setMinimumSize(const SGVec2i& s)
135   {
136     if( _min_size == s )
137       return;
138
139     _min_size = s;
140     invalidateParent();
141   }
142
143   //----------------------------------------------------------------------------
144   void NasalWidget::setMaximumSize(const SGVec2i& s)
145   {
146     if( _max_size == s )
147       return;
148
149     _max_size = s;
150     invalidateParent();
151   }
152
153   //----------------------------------------------------------------------------
154   bool NasalWidget::hasHeightForWidth() const
155   {
156     return !_height_for_width.empty() || !_min_height_for_width.empty();
157   }
158
159   //----------------------------------------------------------------------------
160   int NasalWidget::heightForWidth(int w) const
161   {
162     return callHeightForWidthFunc( _height_for_width.empty()
163                                  ? _min_height_for_width
164                                  : _height_for_width, w );
165   }
166
167   //----------------------------------------------------------------------------
168   int NasalWidget::minimumHeightForWidth(int w) const
169   {
170     return callHeightForWidthFunc( _min_height_for_width.empty()
171                                  ? _height_for_width
172                                  : _min_height_for_width, w );
173   }
174
175   //----------------------------------------------------------------------------
176   static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
177   {
178     return ctx.to_nasal(NasalWidgetRef(
179       new NasalWidget( ctx.requireArg<naRef>(0) )
180     ));
181   }
182
183   //----------------------------------------------------------------------------
184   void NasalWidget::setupGhost(nasal::Hash& ns)
185   {
186     nasal::Ghost<NasalWidgetRef>::init("canvas.Widget")
187       .bases<LayoutItemRef>()
188       .bases<nasal::ObjectRef>()
189       .method("setSetGeometryFunc", &NasalWidget::setSetGeometryFunc)
190       .method("setMinimumHeightForWidthFunc",
191                                     &NasalWidget::setMinimumHeightForWidthFunc)
192       .method("setHeightForWidthFunc", &NasalWidget::setHeightForWidthFunc)
193       .method("setSizeHint", &NasalWidget::setSizeHint)
194       .method("setMinimumSize", &NasalWidget::setMinimumSize)
195       .method("setMaximumSize", &NasalWidget::setMaximumSize);
196
197     nasal::Hash widget_hash = ns.createHash("Widget");
198     widget_hash.set("new", &f_makeNasalWidget);
199   }
200
201   //----------------------------------------------------------------------------
202   int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
203                                            int w ) const
204   {
205     if( hfw.empty() )
206       return -1;
207
208     naContext c = naNewContext();
209     try
210     {
211       return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
212     }
213     catch( std::exception const& ex )
214     {
215       SG_LOG(
216         SG_GUI,
217         SG_WARN,
218         "NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
219       );
220     }
221     naFreeContext(c);
222
223     return -1;
224   }
225
226   //----------------------------------------------------------------------------
227   SGVec2i NasalWidget::sizeHintImpl() const
228   {
229     return _size_hint;
230   }
231
232   //----------------------------------------------------------------------------
233   SGVec2i NasalWidget::minimumSizeImpl() const
234   {
235     return _min_size;
236   }
237
238   //----------------------------------------------------------------------------
239   SGVec2i NasalWidget::maximumSizeImpl() const
240   {
241     return _max_size;
242   }
243
244 } // namespace canvas
245 } // namespace simgear