KiCad PCB EDA Suite
lib_control.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program 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 this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <fctsys.h>
26 #include <kiway.h>
27 #include <sch_painter.h>
28 #include <tool/tool_manager.h>
29 #include <tools/ee_actions.h>
30 #include <tools/lib_control.h>
31 #include <eeschema_id.h>
32 #include <lib_edit_frame.h>
33 #include <viewlib_frame.h>
35 #include <gestfich.h>
36 #include <project.h>
37 #include <confirm.h>
38 
39 
41 {
42  m_frame = getEditFrame<SCH_BASE_FRAME>();
45 
46  if( m_isLibEdit )
47  {
48  CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
49  LIB_EDIT_FRAME* editFrame = getEditFrame<LIB_EDIT_FRAME>();
50 
51  auto libSelectedCondition = [ editFrame ] ( const SELECTION& aSel ) {
52  LIB_ID sel = editFrame->GetTreeLIBID();
53  return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
54  };
55  auto symbolSelectedCondition = [ editFrame ] ( const SELECTION& aSel ) {
56  LIB_ID sel = editFrame->GetTreeLIBID();
57  return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
58  };
59 
62  ctxMenu.AddItem( ACTIONS::save, libSelectedCondition );
63  ctxMenu.AddItem( ACTIONS::saveAs, libSelectedCondition );
64  ctxMenu.AddItem( ACTIONS::revert, libSelectedCondition );
65 
66  ctxMenu.AddSeparator();
68  ctxMenu.AddItem( EE_ACTIONS::editSymbol, symbolSelectedCondition );
69 
70  ctxMenu.AddSeparator();
71  ctxMenu.AddItem( ACTIONS::save, symbolSelectedCondition );
72  ctxMenu.AddItem( ACTIONS::saveCopyAs, symbolSelectedCondition );
73  ctxMenu.AddItem( EE_ACTIONS::duplicateSymbol, symbolSelectedCondition );
74  ctxMenu.AddItem( EE_ACTIONS::deleteSymbol, symbolSelectedCondition );
75  ctxMenu.AddItem( ACTIONS::revert, symbolSelectedCondition );
76 
77  ctxMenu.AddSeparator();
78  ctxMenu.AddItem( EE_ACTIONS::cutSymbol, symbolSelectedCondition );
79  ctxMenu.AddItem( EE_ACTIONS::copySymbol, symbolSelectedCondition );
81 
82  ctxMenu.AddSeparator();
84  ctxMenu.AddItem( EE_ACTIONS::exportSymbol, symbolSelectedCondition );
85  }
86 
87  return true;
88 }
89 
90 
91 int LIB_CONTROL::AddLibrary( const TOOL_EVENT& aEvent )
92 {
93  bool createNew = aEvent.IsAction( &ACTIONS::newLibrary );
94 
96  static_cast<LIB_EDIT_FRAME*>( m_frame )->AddLibraryFile( createNew );
97 
98  return 0;
99 }
100 
101 
103 {
105  {
106  LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
107  int unit = 0;
108  LIB_ID partId = editFrame->GetTreeLIBID( &unit );
109 
110  editFrame->LoadPart( partId.GetLibItemName(), partId.GetLibNickname(), unit );
111  }
112 
113  return 0;
114 }
115 
116 
117 int LIB_CONTROL::AddSymbol( const TOOL_EVENT& aEvent )
118 {
120  {
121  LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
122 
123  if( aEvent.IsAction( &EE_ACTIONS::newSymbol ) )
124  editFrame->CreateNewPart();
125  else if( aEvent.IsAction( &EE_ACTIONS::importSymbol ) )
126  editFrame->ImportPart();
127  }
128 
129  return 0;
130 }
131 
132 
133 int LIB_CONTROL::Save( const TOOL_EVENT& aEvt )
134 {
136  {
137  LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
138 
139  if( aEvt.IsAction( &EE_ACTIONS::save ) )
140  editFrame->Save();
141  else if( aEvt.IsAction( &EE_ACTIONS::saveAs ) || aEvt.IsAction( &EE_ACTIONS::saveCopyAs ) )
142  editFrame->SaveAs();
143  else if( aEvt.IsAction( &EE_ACTIONS::saveAll ) )
144  editFrame->SaveAll();
145  }
146 
147  return 0;
148 }
149 
150 
151 int LIB_CONTROL::Revert( const TOOL_EVENT& aEvent )
152 {
154  static_cast<LIB_EDIT_FRAME*>( m_frame )->Revert();
155 
156  return 0;
157 }
158 
159 
161 {
163  static_cast<LIB_EDIT_FRAME*>( m_frame )->ExportPart();
164 
165  return 0;
166 }
167 
168 
170 {
172  {
173  LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
174 
176  editFrame->CopyPartToClipboard();
177 
179  editFrame->DeletePartFromLibrary();
180  }
181 
182  return 0;
183 }
184 
185 
187 {
189  {
190  LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
191  editFrame->DuplicatePart( aEvent.IsAction( &EE_ACTIONS::pasteSymbol ) );
192  }
193 
194  return 0;
195 }
196 
197 
199 {
200  int convert = aEvent.IsAction( &EE_ACTIONS::showDeMorganStandard ) ?
201  LIB_ITEM::LIB_CONVERT::BASE : LIB_ITEM::LIB_CONVERT::DEMORGAN;
202 
204  {
207 
208  LIB_EDIT_FRAME* libEditFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
209  libEditFrame->SetConvert( convert );
210 
212  libEditFrame->RebuildView();
213  }
215  {
216  LIB_VIEW_FRAME* libViewFrame = static_cast<LIB_VIEW_FRAME*>( m_frame );
217  libViewFrame->SetUnitAndConvert( libViewFrame->GetUnit(), convert );
218  }
219 
220  return 0;
221 }
222 
223 
225 {
227  {
228  wxCommandEvent dummy;
229  static_cast<LIB_EDIT_FRAME*>( m_frame )->OnToggleSearchTree( dummy );
230  }
231 
232  return 0;
233 }
234 
235 
237 {
239 
240  // Update canvas
243  m_frame->GetCanvas()->Refresh();
244 
245  return 0;
246 }
247 
248 
250 {
251  if( !m_isLibEdit )
252  return 0;
253 
254  LIB_EDIT_FRAME* editFrame = getEditFrame<LIB_EDIT_FRAME>();
255  editFrame->m_SyncPinEdit = !editFrame->m_SyncPinEdit;
256 
257  return 0;
258 }
259 
260 
262 {
263  if( !m_isLibEdit )
264  return 0;
265 
266  LIB_EDIT_FRAME* editFrame = getEditFrame<LIB_EDIT_FRAME>();
267  LIB_PART* part = editFrame->GetCurPart();
268 
269  if( !part )
270  {
271  wxMessageBox( _( "No symbol to export" ) );
272  return 0;
273  }
274 
275  wxString file_ext = wxT( "png" );
276  wxString mask = wxT( "*." ) + file_ext;
277  wxFileName fn( part->GetName() );
278  fn.SetExt( "png" );
279 
280  wxString projectPath = wxPathOnly( m_frame->Prj().GetProjectFullName() );
281 
282  wxFileDialog dlg( editFrame, _( "Image File Name" ), projectPath, fn.GetFullName(),
283  PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
284 
285  if( dlg.ShowModal() == wxID_OK && !dlg.GetPath().IsEmpty() )
286  {
287  // calling wxYield is mandatory under Linux, after closing the file selector dialog
288  // to refresh the screen before creating the PNG or JPEG image from screen
289  wxYield();
290 
291  if( !SaveCanvasImageToFile( editFrame, dlg.GetPath(), wxBITMAP_TYPE_PNG ) )
292  {
293  wxMessageBox( wxString::Format( _( "Can't save file \"%s\"." ), dlg.GetPath() ) );
294  }
295  }
296 
297  return 0;
298 }
299 
300 
302 {
303  if( !m_isLibEdit )
304  return 0;
305 
306  LIB_EDIT_FRAME* editFrame = getEditFrame<LIB_EDIT_FRAME>();
307  LIB_PART* part = editFrame->GetCurPart();
308 
309  if( !part )
310  {
311  wxMessageBox( _( "No symbol to export" ) );
312  return 0;
313  }
314 
315  wxString file_ext = wxT( "svg" );
316  wxString mask = wxT( "*." ) + file_ext;
317  wxFileName fn( part->GetName() );
318  fn.SetExt( file_ext );
319 
320  wxString pro_dir = wxPathOnly( m_frame->Prj().GetProjectFullName() );
321 
322  wxString fullFileName = EDA_FILE_SELECTOR( _( "Filename:" ), pro_dir, fn.GetFullName(),
323  file_ext, mask, m_frame, wxFD_SAVE, true );
324 
325  if( !fullFileName.IsEmpty() )
326  {
327  PAGE_INFO pageSave = editFrame->GetScreen()->GetPageSettings();
328  PAGE_INFO pageTemp = pageSave;
329 
330  wxSize componentSize = part->GetUnitBoundingBox( editFrame->GetUnit(),
331  editFrame->GetConvert() ).GetSize();
332 
333  // Add a small margin to the plot bounding box
334  pageTemp.SetWidthMils( int( componentSize.x * 1.2 ) );
335  pageTemp.SetHeightMils( int( componentSize.y * 1.2 ) );
336 
337  editFrame->GetScreen()->SetPageSettings( pageTemp );
338  editFrame->SVG_PlotComponent( fullFileName );
339  editFrame->GetScreen()->SetPageSettings( pageSave );
340  }
341 
342  return 0;
343 }
344 
345 
347 {
348  LIB_PART* part = nullptr;
349  LIB_ID libId;
350  int unit, convert;
351 
352  if( m_isLibEdit )
353  {
354  LIB_EDIT_FRAME* editFrame = getEditFrame<LIB_EDIT_FRAME>();
355 
356  part = editFrame->GetCurPart();
357  unit = editFrame->GetUnit();
358  convert = editFrame->GetConvert();
359 
360  if( part )
361  libId = part->GetLibId();
362  }
363  else
364  {
365  LIB_VIEW_FRAME* viewFrame = getEditFrame<LIB_VIEW_FRAME>();
366 
367  if( viewFrame->IsModal() )
368  {
369  // if we're modal then we just need to return the symbol selection; the caller is
370  // already in a EE_ACTIONS::placeSymbol coroutine.
371  viewFrame->FinishModal();
372  return 0;
373  }
374  else
375  {
376  part = viewFrame->GetSelectedSymbol();
377  libId = viewFrame->GetSelectedAlias()->GetLibId();
378  unit = viewFrame->GetUnit();
379  convert = viewFrame->GetConvert();
380  }
381  }
382 
383  if( part )
384  {
385  SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH, false );
386 
387  if( !schframe ) // happens when the schematic editor is not active (or closed)
388  {
389  DisplayErrorMessage( m_frame, _( "No schematic currently open." ) );
390  return 0;
391  }
392 
393  SCH_COMPONENT* comp = new SCH_COMPONENT( *part, libId,g_CurrentSheet, unit, convert );
394 
395  // Be sure the link to the corresponding LIB_PART is OK:
396  comp->Resolve( *m_frame->Prj().SchSymbolLibTable() );
397 
398  if( schframe->GetAutoplaceFields() )
399  comp->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
400 
401  schframe->Raise();
402  schframe->GetToolManager()->RunAction( EE_ACTIONS::placeSymbol, true, comp );
403  }
404 
405  return 0;
406 }
407 
408 
410 {
416 
417  Go( &LIB_CONTROL::Save, ACTIONS::save.MakeEvent() );
418  Go( &LIB_CONTROL::Save, ACTIONS::saveAs.MakeEvent() ); // for libraries
419  Go( &LIB_CONTROL::Save, ACTIONS::saveCopyAs.MakeEvent() ); // for symbols
420  Go( &LIB_CONTROL::Save, ACTIONS::saveAll.MakeEvent() );
421  Go( &LIB_CONTROL::Revert, ACTIONS::revert.MakeEvent() );
422 
432 
435 
439 }
static bool ShowAlways(const SELECTION &aSelection)
Function ShowAlways The default condition function (always returns true).
void SVG_PlotComponent(const wxString &aFullFileName)
Creates the SVG print file for the current edited component.
KIGFX::SCH_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
void DuplicatePart(bool aFromClipboard)
Inserts a duplicate part.
Definition: libedit.cpp:570
int AddLibrary(const TOOL_EVENT &aEvent)
Definition: lib_control.cpp:91
LIB_PART * GetSelectedSymbol() const
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
int EditSymbol(const TOOL_EVENT &aEvent)
void SetUnitAndConvert(int aUnit, int aConvert)
Set unit and convert, and set flag preventing them from automatically resetting to 1.
static TOOL_ACTION pasteSymbol
Definition: ee_actions.h:171
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:258
This file is part of the common library TODO brief description.
int GetConvert() const
bool SaveCanvasImageToFile(EDA_DRAW_FRAME *aFrame, const wxString &aFileName, wxBitmapType aBitmapType)
Save the current view as an image file.
Definition: bitmap.cpp:195
Model changes (required full reload)
Definition: tool_base.h:82
This file is part of the common library.
int ToggleSyncedPinsMode(const TOOL_EVENT &aEvent)
LIB_ID GetLibId() const override
static TOOL_ACTION duplicateSymbol
Definition: ee_actions.h:167
int AddSymbol(const TOOL_EVENT &aEvent)
bool Resolve(PART_LIBS *aLibs)
Assigns the current LIB_PART from aLibs which this symbol is based on.
void LoadPart(const wxString &aLibrary, const wxString &aPart, int Unit)
Definition: libedit.cpp:717
int ShowElectricalTypes(const TOOL_EVENT &aEvent)
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
int GetUnit() const
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
void UpdateAllItems(int aUpdateFlags)
Updates all items in the view according to the given flags.
Definition: view.cpp:1444
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
void CopyPartToClipboard()
Definition: libedit.cpp:545
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:114
KIGFX::SCH_RENDER_SETTINGS * GetRenderSettings()
int ExportView(const TOOL_EVENT &aEvent)
Schematic editor (Eeschema) main window.
void SetShowElectricalType(bool aShow)
static TOOL_ACTION showComponentTree
Definition: ee_actions.h:191
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
int ExportSymbol(const TOOL_EVENT &aEvent)
bool GetAutoplaceFields() const
static TOOL_ACTION showDeMorganAlternate
Definition: ee_actions.h:129
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:113
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
Symbol library viewer main window.
Definition: viewlib_frame.h:43
int GetConvert() const
static TOOL_ACTION saveCopyAs
Definition: actions.h:56
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:63
void Save()
Saves the selected part or library.
Definition: libedit.cpp:351
LIB_ID GetTreeLIBID(int *aUnit=nullptr) const
Return the LIB_ID of the library or symbol selected in the symbol tree.
void SaveAs()
Saves the selected part or library to a new name and/or location.
Definition: libedit.cpp:373
static TOOL_ACTION editSymbol
Definition: ee_actions.h:166
Item is being added to the view.
Definition: view_item.h:60
int GetUnit() const
SCH_SHEET_PATH * g_CurrentSheet
With the new connectivity algorithm, many more places than before want to know what the current sheet...
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:321
void DeletePartFromLibrary()
Definition: libedit.cpp:524
void SaveAll()
Saves all modified parts and libraries.
Definition: libedit.cpp:266
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
Definition: page_info.h:54
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
static TOOL_ACTION save
Definition: actions.h:54
int Save(const TOOL_EVENT &aEvt)
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Class TOOL_EVENT.
Definition: tool_event.h:168
const LIB_ID & GetLibId() const
wxString EDA_FILE_SELECTOR(const wxString &aTitle, const wxString &aPath, const wxString &aFileName, const wxString &aExtension, const wxString &aWildcard, wxWindow *aParent, int aStyle, const bool aKeepWorkingDirectory, const wxPoint &aPosition, wxString *aMruPath)
Function EDA_FILE_SELECTOR.
Definition: gestfich.cpp:82
static TOOL_ACTION deleteSymbol
Definition: ee_actions.h:168
Define a library symbol object.
static TOOL_ACTION cutSymbol
Definition: ee_actions.h:169
Definition of file extensions used in Kicad.
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Function ResetTools() Resets all tools (i.e.
static TOOL_ACTION addLibrary
Definition: actions.h:52
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:140
static TOOL_ACTION importSymbol
Definition: ee_actions.h:172
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:58
static TOOL_ACTION placeSymbol
Definition: ee_actions.h:79
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:96
static TOOL_ACTION addSymbolToSchematic
Definition: ee_actions.h:162
int AddSymbolToSchematic(const TOOL_EVENT &aEvent)
bool IsModal()
Definition: kiway_player.h:163
void setTransitions() override
Sets up handlers for various events.
#define _(s)
static TOOL_ACTION newLibrary
Definition: actions.h:51
static TOOL_ACTION showDeMorganStandard
Definition: ee_actions.h:128
static TOOL_ACTION showElectricalTypes
Definition: ee_actions.h:190
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
static TOOL_ACTION exportSymbolView
Definition: ee_actions.h:194
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
wxString PngFileWildcard()
void AddSeparator(int aOrder=ANY_ORDER)
Function AddSeparator()
void ImportPart()
Definition: lib_export.cpp:36
static TOOL_ACTION newSymbol
Definition: ee_actions.h:165
static TOOL_ACTION exportSymbol
Definition: ee_actions.h:173
static TOOL_ACTION copySymbol
Definition: ee_actions.h:170
int CutCopyDelete(const TOOL_EVENT &aEvent)
int Revert(const TOOL_EVENT &aEvent)
The symbol library editor main window.
bool m_SyncPinEdit
Set to true to synchronize pins at the same position when editing symbols with multiple units or mult...
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual)
Automatically orient all the fields in the component.
bool IsType(FRAME_T aType) const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static TOOL_ACTION saveAs
Definition: actions.h:55
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
LIB_ALIAS * GetSelectedAlias() const
const wxString & GetName() const
void FinishModal()
Send the selected symbol back to the caller.
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
const EDA_RECT GetUnitBoundingBox(int aUnit, int aConvert) const
Get the bounding box for the symbol.
void CreateNewPart()
Creates a new part in the selected library.
Definition: libedit.cpp:274
void SetConvert(int aConvert)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:73
static TOOL_ACTION toggleSyncedPinsMode
Definition: ee_actions.h:184
int ExportSymbolAsSVG(const TOOL_EVENT &aEvent)
static TOOL_ACTION saveAll
Definition: actions.h:57
int DuplicateSymbol(const TOOL_EVENT &aEvent)
static TOOL_ACTION exportSymbolAsSVG
Definition: ee_actions.h:195
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
Definition: lib_control.cpp:40
int ShowComponentTree(const TOOL_EVENT &aEvent)
static TOOL_ACTION revert
Definition: actions.h:58
int OnDeMorgan(const TOOL_EVENT &aEvent)
bool GetShowElectricalType()
Allow some frames to show/hide pin electrical type names.
bool empty() const
Definition: utf8.h:108