NCBI C++ ToolKit
save_images_setup_dlg.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 
2 #include <ncbi_pch.hpp>
7 
9 
10 #include <util/image/image.hpp>
11 
12 #include <wx/utils.h>
13 #include <wx/stattext.h>
14 #include <wx/statbox.h>
15 #include <wx/bmpbuttn.h>
16 #include <wx/checkbox.h>
17 #include <wx/radiobox.h>
18 #include <wx/slider.h>
19 #include <wx/combobox.h>
20 #include <wx/intl.h>
21 #include <wx/sizer.h>
22 #include <wx/cmndata.h>
23 #include <wx/dirdlg.h>
24 #include <wx/msgdlg.h>
25 #include <wx/artprov.h>
26 
27 
28 #if wxUSE_STATLINE
29  #include <wx/statline.h>
30 #endif
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 // ----------------------------------------------------------------------------
36 // Generic page setup dialog
37 // ---------------------------------------------------------------------------
38 
40 
42 DEFINE_EVENT_TYPE(wxEVT_TILE_PREVIEW)
43 
44 BEGIN_EVENT_TABLE(CSaveImagesSetupDlg, CPreviewSetupDlg)
45  EVT_BUTTON(ePrintIDSetup, CSaveImagesSetupDlg::OnPrinter)
46  EVT_BUTTON(eDirSelectID, CSaveImagesSetupDlg::OnDirSelect)
47  EVT_BUTTON(wxID_OK, CSaveImagesSetupDlg::OnSave)
48  EVT_BUTTON(ePreviewID, CSaveImagesSetupDlg::OnPreview)
49  EVT_COMBOBOX(eImageTypeID, CSaveImagesSetupDlg::OnImageTypeChange)
50  EVT_TEXT(eFileRootNameID, CSaveImagesSetupDlg::OnFileTextChange)
51  EVT_COMBOBOX(eNumberingID, CSaveImagesSetupDlg::OnFileTextChange)
52  EVT_COMBOBOX(eSizeRatioID, CSaveImagesSetupDlg::OnFileTextChange)
53  EVT_COMMAND(wxID_ANY, wxEVT_TILE_PREVIEW, CSaveImagesSetupDlg::OnTilePreview)
55 
56 static const string kSaveImagesBaseKey("GBPlugins.SaveImagesDialog");
57 
58 // Image sizes for smallest, us letter, and a4
59 const float CSaveImagesSetupDlg::s_ImageAspectRatios[3] =
60 { -1.0f, 215.9f/279.4f, 210.0f/297.0f};
61 
63  IImageGrabber* img_saver,
64  wxWindow *parent)
65  : CPreviewSetupDlg( img, parent)
66  , m_Directory(NULL)
67  , m_DirSelectButton(NULL)
68  , m_FileRootName(NULL)
69  , m_ImageFormat(NULL)
70  , m_NumberingFormat(NULL)
71  , m_SizeRatio(NULL)
72  , m_ImageSizes(NULL)
73  , m_ImageSaver(img_saver)
74 {
75  // Layout all the controls
76  x_InitDialog(img);
77  SetTitle(wxT("Save Images"));
78 
79  // Change names of default ok and cancel buttons to save and close.
80  wxWindowList& children = this->GetChildren();
81 
82  wxWindowList::compatibility_iterator node = children.GetFirst();
83  while (node)
84  {
85  wxWindow *child = node->GetData();
86 
87  if (child->GetId() == GetAffirmativeId()) {
88  child->SetLabel(wxT("Save"));
89  child->Refresh();
90  }
91  else if (child->GetId() == wxID_CANCEL) {
92  child->SetLabel(wxT("Close"));
93  child->Refresh();
94  }
95  // Printer shows up on GTK version only...
96  else if (child->GetLabel() == wxT("Printer...")) {
97  child->Hide();
98  child->Refresh();
99  }
100 
101  node = node->GetNext();
102  }
103 }
104 
106 {
107 }
108 
109 void CSaveImagesSetupDlg::x_Init(wxBoxSizer* mainsizer, int widget_width)
110 {
111  int dir_width = 160;
112  int fname_width = 60;
113 
114  // Directory and File Choice
115  ///////////////////////////////////////////////////////////////////////////
116 
117  wxBoxSizer *file_sizer = new wxBoxSizer(wxHORIZONTAL);
118  file_sizer->Add(new wxStaticText(this,
119  wxID_ANY,
120  wxT("Directory:")),
121  0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER,5);
122  m_Directory = new wxTextCtrl(this,
123  wxID_ANY,
124  wxEmptyString,
125  wxDefaultPosition,
126  wxSize(dir_width, wxDefaultCoord));
127  file_sizer->Add( m_Directory, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER, 5 );
128 
129  m_DirSelectButton = new wxBitmapButton(this,
130  eDirSelectID,
131  wxArtProvider::GetBitmap(wxT("menu::open")),
132  wxDefaultPosition,
133  wxDefaultSize,
134  wxBU_AUTODRAW);
135 
136  file_sizer->Add( m_DirSelectButton, 0, wxTOP|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER, 5 );
137 
138  file_sizer->Add(new wxStaticText(this,
139  wxID_ANY,
140  wxT("File Name:")),
141  0,wxTOP|wxBOTTOM|wxALIGN_CENTER,5);
142  m_FileRootName = new wxTextCtrl(this,
144  wxT("img"),
145  wxDefaultPosition,
146  wxSize(fname_width, wxDefaultCoord));
147 
148  file_sizer->Add(m_FileRootName, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER, 5);
149  m_FileRootName->SetValue(wxT("img"));
150 
151  file_sizer->Add(new wxStaticText(this,
152  wxID_ANY,
153  wxT("Numbering:")),
154  1,wxTOP|wxBOTTOM|wxALIGN_CENTER,5);
155 
156  int numbering_count = 2;
157  wxString* num_choices = new wxString[numbering_count];
158  num_choices[0] = wxT("Sequential");
159  num_choices[1] = wxT("Tile Index");
160 
161  m_NumberingFormat = new wxComboBox(this,
162  eNumberingID,
163  _("Sequential"),
164  wxDefaultPosition,
165  wxSize(100, wxDefaultCoord),
166  numbering_count, num_choices);
167  file_sizer->Add(m_NumberingFormat, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER, 5);
168 
169 
170  mainsizer->Add( file_sizer, 0, wxALIGN_CENTER);
171  wxBoxSizer *image_opt_sizer = new wxBoxSizer(wxHORIZONTAL);
172 
173  image_opt_sizer->Add(new wxStaticText(this,
174  wxID_ANY,
175  wxT("Image Type:")),
176  1,wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER,5);
177 
178  // gif and tiff don't seem to work on the mac. Since they won't play
179  // nicely with everybody, they can't play at all.
180  int format_count = 3;
181  wxString* choices = new wxString[format_count];
182  choices[0] = wxT("jpeg");
183  choices[1] = wxT("png");
184  //choices[2] = wxT("gif");
185  //choices[3] = wxT("tiff");
186 
187  m_ImageFormat = new wxComboBox(this,
188  eImageTypeID,
189  _("png"),
190  wxDefaultPosition,
191  wxSize(80, wxDefaultCoord),
192  format_count, choices);
193  image_opt_sizer->Add(m_ImageFormat, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER, 5);
194 
195  // See what image sizes are available and put those into a drop-down
196  // box
197  std::vector<int> sizes;
199  wxString* size_choices = NULL;
200  int default_idx = 0;
201 
202  if (sizes.size() > 0) {
203  size_choices = new wxString[sizes.size()];
204  for (size_t i=0; i<sizes.size(); ++i) {
205  char buf[128];
206  sprintf(buf,"%5d", sizes[i]);
207  size_choices[i] = wxString(buf, wxConvUTF8);
208  }
209  if (size_choices->size() > 1U)
210  default_idx = 1;
211  }
212  else {
213  // This will probably fail when the image is saved, but the user
214  // will get a nice-ish message at that time.
215  sizes.push_back(256);
216  size_choices = new wxString[sizes.size()];
217  char buf[128];
218  sprintf(buf,"%5d", sizes[0]);
219  size_choices[0] = wxString(buf, wxConvUTF8);
220  }
221 
222  image_opt_sizer->Add(new wxStaticText(this,
223  wxID_ANY,
224  wxT("Image Size:")),
225  1,wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER,5);
226  m_ImageSizes = new wxComboBox(this,
227  eImageSizeID,
228  size_choices[default_idx],
229  wxDefaultPosition,
230  wxSize(80, wxDefaultCoord),
231  (int)sizes.size(), size_choices);
232  image_opt_sizer->Add(m_ImageSizes, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER, 5);
233 
234  image_opt_sizer->Add(new wxStaticText(this,
235  wxID_ANY,
236  wxT("Proportions:")),
237  1,wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER,5);
238 
239  int ratio_count = 3;
240  wxString* ratio_choices = new wxString[ratio_count];
241 
242  /// Should match names in print_media.hpp:
243  ratio_choices[0] = wxT("Smallest"); // -1.0f (let class compute best-fit)
244  ratio_choices[1] = wxT("Letter"); // 215.9 279.4 mm
245  ratio_choices[2] = wxT("A4"); // 210 × 297 mm
246 
247  m_SizeRatio = new wxComboBox(this,
248  eSizeRatioID,
249  _("Smallest"),
250  wxDefaultPosition,
251  wxSize(100, wxDefaultCoord),
252  ratio_count, ratio_choices);
253  image_opt_sizer->Add(m_SizeRatio, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER, 5);
254  m_SizeRatio->SetSelection(0);
255 
256  mainsizer->Add( image_opt_sizer, 0, wxALIGN_CENTER);
257 
258  // Check registry for default values for fields (values are saved between
259  // invocations of the dialog)
260 
263 
264  std::string reg_value;
265 
266  reg_value = view.GetString("ImageDirectory");
267  if (!reg_value.empty())
268  m_Directory->SetValue(wxString(reg_value.c_str(), wxConvUTF8));
269 
270  reg_value = view.GetString("FileRootName");
271  if (!reg_value.empty())
272  m_FileRootName->SetValue(wxString(reg_value.c_str(), wxConvUTF8));
273 
274  reg_value = view.GetString("ImageFormat");
275  if (!reg_value.empty())
276  m_ImageFormat->SetValue(wxString(reg_value.c_str(), wxConvUTF8));
277 
278 
279  reg_value = view.GetString("NumberingFormat");
280  if (!reg_value.empty())
281  m_NumberingFormat->SetValue(wxString(reg_value.c_str(), wxConvUTF8));
282 
283  reg_value = view.GetString("SizeRatio");
284  wxString wx_reg_value = wxString(reg_value.c_str(), wxConvUTF8);
285  if (!reg_value.empty())
286  m_SizeRatio->SetValue(wx_reg_value);
287  for (int j=0; j<ratio_count; ++j) {
288  if (wx_reg_value == ratio_choices[j]) {
289  m_SizeRatio->SetSelection(j);
290  break;
291  }
292  }
293 
294 
295  // Initialize value in image widget
296  wxCommandEvent dummy_evt;
297 
298  OnFileTextChange(dummy_evt);
299  OnImageTypeChange(dummy_evt);
300 }
301 
303 {
304  float ratio = s_ImageAspectRatios[m_SizeRatio->GetCurrentSelection()];
305 
306  if (ratio == -1.0f) return ratio;
307 
308  float target_ratio =
311 
312  if ((ratio < 1.0f && target_ratio > 1.0f) || (ratio > 1.0f && target_ratio < 1.0f))
313  return 1.0f/ratio;
314 
315  return ratio;
316 }
317 
318 
320 {
322 
323  return true;
324 }
325 
327 {
329 
330  return true;
331 }
332 
334 {
336 
338 }
339 
340 void CSaveImagesSetupDlg::OnDirSelect(wxCommandEvent& event)
341 {
342  wxDirDialog dlg(this);
343 
344  if (dlg.ShowModal() == wxID_OK) {
345  m_Directory->SetValue(dlg.GetPath());
346 
347  // After changing names, if any images were saved, flag them
348  // as not being saved anymore.
350  }
351 }
352 
353 void CSaveImagesSetupDlg::OnFileTextChange(wxCommandEvent& evt)
354 {
355  // Check that dialog is constructed first. This function is used
356  // to update the preview widget regardless of what (related) data
357  // item changed.
358  if (NULL != m_FileRootName &&
359  NULL != m_SizeRatio &&
360  NULL != m_NumberingFormat &&
362  wxString name = m_FileRootName->GetValue();
363 
364  std::string str = (const char*)name.mb_str(wxConvUTF8);
365 
368 
369  if (GetNumberingFormat() == "Sequential")
371  else
373 
374  // Call set partitions too, since that can change if the size-ratio changes
375  // (the number of partions in x and y may change, not the total number)
376  int pos = m_PageCountSlider->GetValue();
378 
379  // After changing names, if any images were saved, flag them
380  // as not being saved anymore.
382  }
383 }
384 
385 void CSaveImagesSetupDlg::OnImageTypeChange(wxCommandEvent& event)
386 {
387  // After changing image type, if any images were saved, flag them
388  // as not being saved anymore (since images to save now have
389  // a different name).
391 
392  if (NULL != m_ImageFormat) {
393  string image_type = std::string( (const char*)m_ImageFormat->GetValue().mb_str(wxConvUTF8));
394 
395  if (NULL != m_NumberingFormat)
396  m_NumberingFormat->Enable();
397  if (NULL != m_SizeRatio)
398  m_SizeRatio->Enable();
399  if (NULL != m_PageCountSlider)
400  m_PageCountSlider->Enable();
401  if (NULL != m_PageCount)
402  m_PageCount->Enable();
403  if (NULL != m_ImageSizes)
404  m_ImageSizes->Enable();
405  }
406 }
407 
408 
409 void CSaveImagesSetupDlg::OnPrinter(wxCommandEvent& WXUNUSED(event))
410 {
412 }
413 
414 void CSaveImagesSetupDlg::OnSave(wxCommandEvent& event)
415 {
417 
418  // Set cursor to hourglass cursor since user can't do anything until save
419  // is over
420  SetCursor(*wxHOURGLASS_CURSOR);
421 
422  // Save values so if user brings dialog up again, they can see
423  // previously selected values.
426  view.Set("ImageDirectory", GetDirectoryName());
427  view.Set("FileRootName", GetFileRootName());
428  view.Set("ImageFormat", GetImageFormat());
429  view.Set("NumberingFormat", GetNumberingFormat());
430  view.Set("SizeRatio", GetOutputFormat());
431 
432 
434 
437  GetFileRootName(),
438  GetImageFormat());
439 
440  if (GetNumberingFormat() == "Sequential")
442  else
444 
448  if (m_GuidesRadioBox->GetSelection() == 0)
450  else
452 
453  long img_size = 0;
454  m_ImageSizes->GetValue().ToLong(&img_size);
455 
456  // Force preview widget to be current context, since the rendering to the background will
457  // be interspersed with rendering to widget to show progress.
458  m_PreviewSetupWidget->Update();
459 
460  res = m_ImageSaver->GrabImages(static_cast<int>(img_size), m_PreviewSetupWidget);
461 
462 
463  // Set the cursor to its value prior to the save:
464  SetCursor(*wxSTANDARD_CURSOR);
465 
466  if (res == IImageGrabber::eOpenGLError) {
467  wxMessageBox(wxT("Graphics system does not support in-memory image save feature"),
468  wxT("Error Saving"), wxOK);
469  }
470  else if (res == IImageGrabber::eFileError) {
471  wxMessageBox(wxT("File error occured during save. Make sure file and directory names are valid."),
472  wxT("Error Saving"), wxOK);
473  }
474 }
475 
476 
477 void CSaveImagesSetupDlg::OnTilePreview(wxCommandEvent& event)
478 {
480 
481  if (m_ImageSaver == NULL)
482  return;
483 
484  // Set cursor to hourglass cursor since user can't do anything until save
485  // is over
486  SetCursor(*wxHOURGLASS_CURSOR);
487 
490  GetFileRootName(),
491  GetImageFormat());
492 
493  if (GetNumberingFormat() == "Sequential")
495  else
497 
501  if (m_GuidesRadioBox->GetSelection() == 0)
503  else
505 
506  long img_size = 0;
507  m_ImageSizes->GetValue().ToLong(&img_size);
508 
509  // Force preview widget to be current context, since the rendering to the background will
510  // be interspersed with rendering to widget to show progress.
511  m_PreviewSetupWidget->Update();
512 
513  // x and y tile coordinates were stored in int/long values of event
514  m_ImageSaver->GrabImage(static_cast<int>(img_size),
515  CVect2<int>(event.GetInt(), static_cast<int>(event.GetExtraLong())),
517 
518  // Set the cursor to its value prior to the save:
519  SetCursor(*wxSTANDARD_CURSOR);
520 }
521 
522 void CSaveImagesSetupDlg::OnPreview(wxCommandEvent& event)
523 {
525 
526  if (m_ImageSaver == NULL)
527  return;
528 
529  // Set cursor to hourglass cursor since user can't do anything until save
530  // is over
531  SetCursor(*wxHOURGLASS_CURSOR);
532 
535  GetFileRootName(),
536  GetImageFormat());
537 
538  if (GetNumberingFormat() == "Sequential")
540  else
542 
546  if (m_GuidesRadioBox->GetSelection() == 0)
548  else
550 
551  long img_size = 0;
552  m_ImageSizes->GetValue().ToLong(&img_size);
553 
554  // Force preview widget to be current context, since the rendering to the background will
555  // be interspersed with rendering to widget to show progress.
556  m_PreviewSetupWidget->Update();
557 
558  m_ImageSaver->PreviewImages(static_cast<int>(img_size),
559  m_PreviewSetupWidget->GetSize().GetWidth(),
560  m_PreviewSetupWidget->GetSize().GetHeight(),
562 
563  // Set the cursor to its value prior to the save:
564  SetCursor(*wxSTANDARD_CURSOR);
565 }
566 
567 
569 {
570  if (NULL != m_Directory)
571  return std::string( (const char*)m_Directory->GetValue().mb_str(wxConvUTF8));
572  else return std::string("");
573 }
574 
576 {
577  if (NULL != m_FileRootName)
578  return std::string( (const char*)m_FileRootName->GetValue().mb_str(wxConvUTF8));
579  else return std::string("");
580 }
581 
583 {
584  if (NULL != m_ImageFormat)
585  return std::string( (const char*)m_ImageFormat->GetValue().mb_str(wxConvUTF8));
586  else return std::string("");
587 }
588 
590 {
591  if (NULL != m_NumberingFormat)
592  return std::string( (const char*)m_NumberingFormat->GetValue().mb_str(wxConvUTF8));
593  else return std::string("");
594 }
595 
597 {
598  if (NULL != m_SizeRatio)
599  return std::string( (const char*)m_SizeRatio->GetValue().mb_str(wxConvUTF8));
600  else return std::string("");
601 }
602 
603 
604 
605 
#define static
static std::vector< int > checkFramebufferAvailability(int start_size, int count)
Return an arrray of valid image output sizes.
void RefreshImage(int x_idx, int y_idx)
Updated number of images saved and refresh the image.
void SetImageBaseName(const std::string &n)
Set the name to assign to the image(s).
int GetImageWidth() const
Get width and height of image.
void SetNumberingFormat(IImageGrabber::eImageNumberingFormat fmt)
Set numbering format for image names, e.g. img{x_y} vs img{1..n}.
void SetPartitions(int p)
Set the number of partitions for display on the widget.
void SetAspectRatio(float r)
Set/Get desired width/height ratio for image when it is subdivided.
CRegistryWriteView GetWriteView(const string &section)
get a read-write view at a particular level.
Definition: registry.cpp:462
static CGuiRegistry & GetInstance()
access the application-wide singleton
Definition: registry.cpp:400
CRegistryReadView GetReadView(const string &section) const
get a read-only view at a particular level.
Definition: registry.cpp:428
void x_InitDialog(CRef< CImage > img)
Layout all controls owned by this class.
virtual void UpdateMargins()
virtual bool TransferDataFromWindow()
CVect2< int > GetPartitions() const
Get the number of image partitions in x and y.
wxStaticText * m_PageCount
wxSlider * m_PageCountSlider
CGlPreviewSetupWidget * m_PreviewSetupWidget
wxRadioBox * m_GuidesRadioBox
virtual bool TransferDataToWindow()
class CRegistryReadView provides a nested hierarchical view at a particular key.
Definition: reg_view.hpp:58
string GetString(const string &key, const string &default_val=kEmptyStr) const
Definition: reg_view.cpp:246
void Set(const string &key, int val)
access a named key at this level, with no recursion
Definition: reg_view.cpp:533
void OnPreview(wxCommandEvent &event)
void OnPrinter(wxCommandEvent &event)
void OnFileTextChange(wxCommandEvent &evt)
Called to update image on screen.
wxTextCtrl * m_Directory
Directory in which to save the image.
wxComboBox * m_SizeRatio
Size ratio derived from ouput format - US Letter, A4, ...
void OnImageTypeChange(wxCommandEvent &event)
wxComboBox * m_ImageSizes
Output size (this will be the size of larger dimension in output images)
std::string GetOutputFormat() const
std::string GetDirectoryName() const
void OnDirSelect(wxCommandEvent &event)
std::string GetNumberingFormat() const
std::string GetImageFormat() const
void OnSave(wxCommandEvent &event)
virtual void x_Init(wxBoxSizer *mainsizer, int widget_width)
Provide virtual hook for subclasses to add their own controls below the main controls.
wxTextCtrl * m_FileRootName
Part of file name before image number.
void OnTilePreview(wxCommandEvent &event)
wxComboBox * m_ImageFormat
Image save format (jpeg, png...)
virtual bool TransferDataFromWindow()
virtual bool TransferDataToWindow()
wxComboBox * m_NumberingFormat
How the numbers are included in filenames, e.g. img_{1..n} or img_x_y;.
CSaveImagesSetupDlg(CRef< CImage > img, IImageGrabber *img_saver, wxWindow *parent=NULL)
std::string GetFileRootName() const
static const float s_ImageAspectRatios[3]
Aspect ratios for image sizes (w/h)
void SetPartitions(const CVect2< int > &p)
Set number of desired image partitions.
void SetImageAspectRatio(float ar)
Set aspect ratio for image as a whole.
eCaptureResult PreviewImages(int tex_size, int ref_img_width, int ref_img_height, IImageGrabberProgress *p=NULL)
Grab images to update the on-screen image to approximate final output.
virtual eCaptureResult GrabImages(int tex_size, IImageGrabberProgress *p=NULL)
Grab the requested images.
void SetNumberingFormat(eImageNumberingFormat fmt)
Set the numbering format for sequential image names.
void SetPrintingGuidesEnabled(bool b)
Set to true to put cutting/printing guides on output images.
eCaptureResult GrabImage(int tex_size, CVect2< int > img_idx, IImageGrabberProgress *p=NULL)
Grab a single image for preview purposes.
void SetOutputInfo(const std::string &dir, const std::string &base_name, const std::string &img_format)
Set file output information.
void SetTileAspectRatio(float ar)
Set aspect ratio tiles captured.
#define _(proto)
Definition: ct_nlmzip_i.h:78
IMPLEMENT_CLASS(CFloatingFrame, CFloatingFrameBaseClass) const static long kFloatFrameStyle
CFloatingFrame.
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
END_EVENT_TABLE()
char * buf
int i
#define wxT(x)
Definition: muParser.cpp:41
static const string kSaveImagesBaseKey("GBPlugins.SaveImagesDialog")
static static static wxID_ANY
static const char * str(char *buf, int n)
Definition: stats.c:84
static void SetTitle(CRef< CSeq_entry > entry, string title)
#define const
Definition: zconf.h:230
Modified on Tue Nov 28 02:22:41 2023 by modify_doxy.py rev. 669887