my own uncrustify run
[xonotic/netradiant.git] / radiant / feedback.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 //-----------------------------------------------------------------------------
23 //
24 // DESCRIPTION:
25 // classes used for describing geometry information from q3map feedback
26 //
27
28 #include "feedback.h"
29
30 #include "debugging/debugging.h"
31
32 #include "igl.h"
33 #include "iselection.h"
34
35 #include <gtk/gtktreeview.h>
36 #include <gtk/gtktreeselection.h>
37 #include <gtk/gtkliststore.h>
38 #include <gtk/gtkcellrenderertext.h>
39 #include <gtk/gtkwindow.h>
40 #include <gtk/gtkscrolledwindow.h>
41
42 #include "map.h"
43 #include "dialog.h"
44 #include "mainframe.h"
45
46
47 CDbgDlg g_DbgDlg;
48
49 void Feedback_draw2D( VIEWTYPE viewType ){
50         g_DbgDlg.draw2D( viewType );
51 }
52
53 void CSelectMsg::saxStartElement( message_info_t *ctx, const xmlChar *name, const xmlChar **attrs ){
54         if ( string_equal( reinterpret_cast<const char*>( name ), "select" ) ) {
55                 // read the message
56                 ESelectState = SELECT_MESSAGE;
57         }
58         else
59         {
60                 // read the brush
61                 ASSERT_MESSAGE( string_equal( reinterpret_cast<const char*>( name ), "brush" ), "FEEDBACK PARSE ERROR" );
62                 ASSERT_MESSAGE( ESelectState == SELECT_MESSAGE, "FEEDBACK PARSE ERROR" );
63                 ESelectState = SELECT_BRUSH;
64                 globalOutputStream() << message.c_str() << '\n';
65         }
66 }
67
68 void CSelectMsg::saxEndElement( message_info_t *ctx, const xmlChar *name ){
69         if ( string_equal( reinterpret_cast<const char*>( name ), "select" ) ) {
70         }
71 }
72
73 void CSelectMsg::saxCharacters( message_info_t *ctx, const xmlChar *ch, int len ){
74         if ( ESelectState == SELECT_MESSAGE ) {
75                 message.write( reinterpret_cast<const char*>( ch ), len );
76         }
77         else
78         {
79                 brush.write( reinterpret_cast<const char*>( ch ), len );
80         }
81 }
82
83 IGL2DWindow* CSelectMsg::Highlight(){
84         GlobalSelectionSystem().setSelectedAll( false );
85         int entitynum, brushnum;
86         if ( sscanf( reinterpret_cast<const char*>( brush.c_str() ), "%i %i", &entitynum, &brushnum ) == 2 ) {
87                 SelectBrush( entitynum, brushnum );
88         }
89         return 0;
90 }
91
92 void CPointMsg::saxStartElement( message_info_t *ctx, const xmlChar *name, const xmlChar **attrs ){
93         if ( string_equal( reinterpret_cast<const char*>( name ), "pointmsg" ) ) {
94                 // read the message
95                 EPointState = POINT_MESSAGE;
96         }
97         else
98         {
99                 // read the brush
100                 ASSERT_MESSAGE( string_equal( reinterpret_cast<const char*>( name ), "point" ), "FEEDBACK PARSE ERROR" );
101                 ASSERT_MESSAGE( EPointState == POINT_MESSAGE, "FEEDBACK PARSE ERROR" );
102                 EPointState = POINT_POINT;
103                 globalOutputStream() << message.c_str() << '\n';
104         }
105 }
106
107 void CPointMsg::saxEndElement( message_info_t *ctx, const xmlChar *name ){
108         if ( string_equal( reinterpret_cast<const char*>( name ), "pointmsg" ) ) {
109         }
110         else if ( string_equal( reinterpret_cast<const char*>( name ), "point" ) ) {
111                 sscanf( point.c_str(), "%g %g %g", &( pt[0] ), &( pt[1] ), &( pt[2] ) );
112                 point.clear();
113         }
114 }
115
116 void CPointMsg::saxCharacters( message_info_t *ctx, const xmlChar *ch, int len ){
117         if ( EPointState == POINT_MESSAGE ) {
118                 message.write( reinterpret_cast<const char*>( ch ), len );
119         }
120         else
121         {
122                 ASSERT_MESSAGE( EPointState == POINT_POINT, "FEEDBACK PARSE ERROR" );
123                 point.write( reinterpret_cast<const char*>( ch ), len );
124         }
125 }
126
127 IGL2DWindow* CPointMsg::Highlight(){
128         return this;
129 }
130
131 void CPointMsg::DropHighlight(){
132 }
133
134 void CPointMsg::Draw2D( VIEWTYPE vt ){
135         int nDim1 = ( vt == YZ ) ? 1 : 0;
136         int nDim2 = ( vt == XY ) ? 1 : 2;
137         glPointSize( 4 );
138         glColor3f( 1.0f,0.0f,0.0f );
139         glBegin( GL_POINTS );
140         glVertex2f( pt[nDim1], pt[nDim2] );
141         glEnd();
142         glBegin( GL_LINE_LOOP );
143         glVertex2f( pt[nDim1] - 8, pt[nDim2] - 8 );
144         glVertex2f( pt[nDim1] + 8, pt[nDim2] - 8 );
145         glVertex2f( pt[nDim1] + 8, pt[nDim2] + 8 );
146         glVertex2f( pt[nDim1] - 8, pt[nDim2] + 8 );
147         glEnd();
148 }
149
150 void CWindingMsg::saxStartElement( message_info_t *ctx, const xmlChar *name, const xmlChar **attrs ){
151         if ( string_equal( reinterpret_cast<const char*>( name ), "windingmsg" ) ) {
152                 // read the message
153                 EPointState = WINDING_MESSAGE;
154         }
155         else
156         {
157                 // read the brush
158                 ASSERT_MESSAGE( string_equal( reinterpret_cast<const char*>( name ), "winding" ), "FEEDBACK PARSE ERROR" );
159                 ASSERT_MESSAGE( EPointState == WINDING_MESSAGE, "FEEDBACK PARSE ERROR" );
160                 EPointState = WINDING_WINDING;
161                 globalOutputStream() << message.c_str() << '\n';
162         }
163 }
164
165 void CWindingMsg::saxEndElement( message_info_t *ctx, const xmlChar *name ){
166         if ( string_equal( reinterpret_cast<const char*>( name ), "windingmsg" ) ) {
167         }
168         else if ( string_equal( reinterpret_cast<const char*>( name ), "winding" ) ) {
169                 const char* c = winding.c_str();
170                 sscanf( c, "%i ", &numpoints );
171
172                 int i = 0;
173                 for (; i < numpoints; i++ )
174                 {
175                         c = strchr( c + 1, '(' );
176                         if ( c ) { // even if we are given the number of points when the cycle begins .. don't trust it too much
177                                 sscanf( c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2] );
178                         }
179                         else{
180                                 break;
181                         }
182                 }
183                 numpoints = i;
184         }
185 }
186
187 void CWindingMsg::saxCharacters( message_info_t *ctx, const xmlChar *ch, int len ){
188         if ( EPointState == WINDING_MESSAGE ) {
189                 message.write( reinterpret_cast<const char*>( ch ), len );
190         }
191         else
192         {
193                 ASSERT_MESSAGE( EPointState == WINDING_WINDING, "FEEDBACK PARSE ERROR" );
194                 winding.write( reinterpret_cast<const char*>( ch ), len );
195         }
196 }
197
198 IGL2DWindow* CWindingMsg::Highlight(){
199         return this;
200 }
201
202 void CWindingMsg::DropHighlight(){
203 }
204
205 void CWindingMsg::Draw2D( VIEWTYPE vt ){
206         int i;
207
208         int nDim1 = ( vt == YZ ) ? 1 : 0;
209         int nDim2 = ( vt == XY ) ? 1 : 2;
210         glColor3f( 1.0f,0.f,0.0f );
211
212         glPointSize( 4 );
213         glBegin( GL_POINTS );
214         for ( i = 0; i < numpoints; i++ )
215                 glVertex2f( wt[i][nDim1], wt[i][nDim2] );
216         glEnd();
217         glPointSize( 1 );
218
219         glEnable( GL_BLEND );
220         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
221         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
222         glColor4f( 0.133f,0.4f,1.0f,0.5f );
223         glBegin( GL_POLYGON );
224         for ( i = 0; i < numpoints; i++ )
225                 glVertex2f( wt[i][nDim1], wt[i][nDim2] );
226         glEnd();
227         glDisable( GL_BLEND );
228 }
229
230 // triggered when the user selects an entry in the feedback box
231 static void feedback_selection_changed( GtkTreeSelection* selection, gpointer data ){
232         g_DbgDlg.DropHighlight();
233
234         GtkTreeModel* model;
235         GtkTreeIter selected;
236         if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
237                 GtkTreePath* path = gtk_tree_model_get_path( model, &selected );
238                 g_DbgDlg.SetHighlight( gtk_tree_path_get_indices( path )[0] );
239                 gtk_tree_path_free( path );
240         }
241 }
242
243 void CDbgDlg::DropHighlight(){
244         if ( m_pHighlight != 0 ) {
245                 m_pHighlight->DropHighlight();
246                 m_pHighlight = 0;
247                 m_pDraw2D = 0;
248         }
249 }
250
251 void CDbgDlg::SetHighlight( gint row ){
252         ISAXHandler *h = GetElement( row );
253         if ( h != NULL ) {
254                 m_pDraw2D = h->Highlight();
255                 m_pHighlight = h;
256         }
257 }
258
259 ISAXHandler *CDbgDlg::GetElement( std::size_t row ){
260         return static_cast<ISAXHandler *>( g_ptr_array_index( m_pFeedbackElements, gint( row ) ) );
261 }
262
263 void CDbgDlg::Init(){
264         DropHighlight();
265
266         // free all the ISAXHandler*, clean it
267         while ( m_pFeedbackElements->len )
268         {
269                 static_cast<ISAXHandler *>( g_ptr_array_index( m_pFeedbackElements, 0 ) )->Release();
270                 g_ptr_array_remove_index( m_pFeedbackElements, 0 );
271         }
272
273         if ( m_clist != NULL ) {
274                 gtk_list_store_clear( m_clist );
275         }
276 }
277
278 void CDbgDlg::Push( ISAXHandler *pHandler ){
279         // push in the list
280         g_ptr_array_add( m_pFeedbackElements, (void *)pHandler );
281
282         if ( GetWidget() == 0 ) {
283                 Create();
284         }
285
286         // put stuff in the list
287         gtk_list_store_clear( m_clist );
288         for ( std::size_t i = 0; i < static_cast<std::size_t>( m_pFeedbackElements->len ); ++i )
289         {
290                 GtkTreeIter iter;
291                 gtk_list_store_append( m_clist, &iter );
292                 gtk_list_store_set( m_clist, &iter, 0, GetElement( i )->getName(), -1 );
293         }
294
295         ShowDlg();
296 }
297
298 GtkWindow* CDbgDlg::BuildDialog(){
299         GtkWindow* window = create_floating_window( "Q3Map debug window", MainFrame_getWindow() );
300
301         GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL );
302         gtk_widget_show( scr );
303         gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( scr ) );
304         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
305         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
306
307         {
308                 GtkListStore* store = gtk_list_store_new( 1, G_TYPE_STRING );
309
310                 GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
311                 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
312
313                 {
314                         GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
315                         GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "", renderer, "text", 0, NULL );
316                         gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
317                 }
318
319                 {
320                         GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
321                         gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
322                         g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( feedback_selection_changed ), NULL );
323                 }
324
325                 gtk_widget_show( view );
326
327                 gtk_container_add( GTK_CONTAINER( scr ), view );
328
329                 g_object_unref( G_OBJECT( store ) );
330
331                 m_clist = store;
332         }
333
334         return window;
335 }