]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/layout/NasalWidget.cxx
cppbind: helper to call Nasal methods on NasalWidget.
[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/NasalContext.hxx>
23 #include <simgear/nasal/cppbind/Ghost.hxx>
24
25 namespace simgear
26 {
27 namespace canvas
28 {
29
30   //----------------------------------------------------------------------------
31   NasalWidget::NasalWidget(naRef impl):
32     Object(impl),
33     _layout_size_hint(32, 32),
34     _layout_min_size(16, 16),
35     _layout_max_size(MAX_SIZE),
36     _user_size_hint(0, 0),
37     _user_min_size(0, 0),
38     _user_max_size(MAX_SIZE)
39   {
40
41   }
42
43   //----------------------------------------------------------------------------
44   NasalWidget::~NasalWidget()
45   {
46     onRemove();
47   }
48
49   //----------------------------------------------------------------------------
50   void NasalWidget::invalidate()
51   {
52     LayoutItem::invalidate();
53     _flags |= LAYOUT_DIRTY;
54   }
55
56   //----------------------------------------------------------------------------
57   void NasalWidget::setGeometry(const SGRect<int>& geom)
58   {
59     if( _geometry != geom )
60     {
61       _geometry = geom;
62       _flags |= LAYOUT_DIRTY;
63     }
64
65     if( !_set_geometry || !(_flags & LAYOUT_DIRTY) )
66       return;
67
68     try
69     {
70       nasal::Context c;
71       _set_geometry(nasal::to_nasal(c, this), geom);
72       _flags &= ~LAYOUT_DIRTY;
73     }
74     catch( std::exception const& ex )
75     {
76       SG_LOG(
77         SG_GUI,
78         SG_WARN,
79         "NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
80       );
81     }
82   }
83
84   //----------------------------------------------------------------------------
85   void NasalWidget::onRemove()
86   {
87     try
88     {
89       callMethod<void>("onRemove");
90     }
91     catch( std::exception const& ex )
92     {
93       SG_LOG(
94         SG_GUI,
95         SG_WARN,
96         "NasalWidget::onRemove: callback error: '" << ex.what() << "'"
97       );
98     }
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     invalidate();
112   }
113
114   //----------------------------------------------------------------------------
115   void NasalWidget::setMinimumHeightForWidthFunc(const HeightForWidthFunc& func)
116   {
117     _min_height_for_width = func;
118     invalidate();
119   }
120
121   //----------------------------------------------------------------------------
122   void NasalWidget::setSizeHint(const SGVec2i& s)
123   {
124     if( _user_size_hint == s )
125       return;
126
127     _user_size_hint = s;
128
129     // TODO just invalidate size_hint? Probably not a performance issue...
130     invalidate();
131   }
132
133   //----------------------------------------------------------------------------
134   void NasalWidget::setMinimumSize(const SGVec2i& s)
135   {
136     if( _user_min_size == s )
137       return;
138
139     _user_min_size = s;
140     invalidate();
141   }
142
143   //----------------------------------------------------------------------------
144   void NasalWidget::setMaximumSize(const SGVec2i& s)
145   {
146     if( _user_max_size == s )
147       return;
148
149     _user_max_size = s;
150     invalidate();
151   }
152
153   //----------------------------------------------------------------------------
154   void NasalWidget::setLayoutSizeHint(const SGVec2i& s)
155   {
156     if( _layout_size_hint == s )
157       return;
158
159     _layout_size_hint = s;
160     invalidate();
161   }
162
163   //----------------------------------------------------------------------------
164   void NasalWidget::setLayoutMinimumSize(const SGVec2i& s)
165   {
166     if( _layout_min_size == s )
167       return;
168
169     _layout_min_size = s;
170     invalidate();
171   }
172
173   //----------------------------------------------------------------------------
174   void NasalWidget::setLayoutMaximumSize(const SGVec2i& s)
175   {
176     if( _layout_max_size == s )
177       return;
178
179     _layout_max_size = s;
180     invalidate();
181   }
182
183   //----------------------------------------------------------------------------
184   bool NasalWidget::hasHeightForWidth() const
185   {
186     return !_height_for_width.empty() || !_min_height_for_width.empty();
187   }
188
189   //----------------------------------------------------------------------------
190   int NasalWidget::heightForWidth(int w) const
191   {
192     return callHeightForWidthFunc( _height_for_width.empty()
193                                  ? _min_height_for_width
194                                  : _height_for_width, w );
195   }
196
197   //----------------------------------------------------------------------------
198   int NasalWidget::minimumHeightForWidth(int w) const
199   {
200     return callHeightForWidthFunc( _min_height_for_width.empty()
201                                  ? _height_for_width
202                                  : _min_height_for_width, w );
203   }
204
205   //----------------------------------------------------------------------------
206   static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
207   {
208     return ctx.to_nasal(NasalWidgetRef(
209       new NasalWidget( ctx.requireArg<naRef>(0) )
210     ));
211   }
212
213   //----------------------------------------------------------------------------
214   void NasalWidget::setupGhost(nasal::Hash& ns)
215   {
216     nasal::Ghost<NasalWidgetRef>::init("canvas.Widget")
217       .bases<LayoutItemRef>()
218       .bases<nasal::ObjectRef>()
219       .method("setSetGeometryFunc", &NasalWidget::setSetGeometryFunc)
220       .method("setMinimumHeightForWidthFunc",
221                                     &NasalWidget::setMinimumHeightForWidthFunc)
222       .method("setHeightForWidthFunc", &NasalWidget::setHeightForWidthFunc)
223       .method("setSizeHint", &NasalWidget::setSizeHint)
224       .method("setMinimumSize", &NasalWidget::setMinimumSize)
225       .method("setMaximumSize", &NasalWidget::setMaximumSize)
226       .method("setLayoutSizeHint", &NasalWidget::setLayoutSizeHint)
227       .method("setLayoutMinimumSize", &NasalWidget::setLayoutMinimumSize)
228       .method("setLayoutMaximumSize", &NasalWidget::setLayoutMaximumSize);
229
230     nasal::Hash widget_hash = ns.createHash("Widget");
231     widget_hash.set("new", &f_makeNasalWidget);
232   }
233
234   //----------------------------------------------------------------------------
235   int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
236                                            int w ) const
237   {
238     if( hfw.empty() )
239       return -1;
240
241     naContext c = naNewContext();
242     try
243     {
244       return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
245     }
246     catch( std::exception const& ex )
247     {
248       SG_LOG(
249         SG_GUI,
250         SG_WARN,
251         "NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
252       );
253     }
254     naFreeContext(c);
255
256     return -1;
257   }
258
259   //----------------------------------------------------------------------------
260   SGVec2i NasalWidget::sizeHintImpl() const
261   {
262     return SGVec2i(
263       _user_size_hint.x() > 0 ? _user_size_hint.x() : _layout_size_hint.x(),
264       _user_size_hint.y() > 0 ? _user_size_hint.y() : _layout_size_hint.y()
265     );
266   }
267
268   //----------------------------------------------------------------------------
269   SGVec2i NasalWidget::minimumSizeImpl() const
270   {
271     return SGVec2i(
272       _user_min_size.x() > 0 ? _user_min_size.x() : _layout_min_size.x(),
273       _user_min_size.y() > 0 ? _user_min_size.y() : _layout_min_size.y()
274     );
275   }
276
277   //----------------------------------------------------------------------------
278   SGVec2i NasalWidget::maximumSizeImpl() const
279   {
280     return SGVec2i(
281       _user_max_size.x() < MAX_SIZE.x() ? _user_max_size.x()
282                                         : _layout_max_size.x(),
283       _user_max_size.y() < MAX_SIZE.y() ? _user_max_size.y()
284                                         : _layout_max_size.y()
285     );
286   }
287
288 } // namespace canvas
289 } // namespace simgear