001package org.vishia.gral.cfg;
002
003import java.text.ParseException;
004
005import org.vishia.gral.base.GralButton;
006import org.vishia.gral.base.GralPos;
007import org.vishia.gral.base.GralWidget;
008import org.vishia.gral.base.GralMng;
009import org.vishia.gral.base.GralWindow;
010import org.vishia.gral.ifc.GralColor;
011import org.vishia.gral.ifc.GralMng_ifc;
012import org.vishia.gral.ifc.GralRectangle;
013import org.vishia.gral.ifc.GralUserAction;
014import org.vishia.gral.ifc.GralWidget_ifc;
015import org.vishia.gral.ifc.GralWindow_ifc;
016import org.vishia.msgDispatch.LogMessage;
017import org.vishia.util.KeyCode;
018
019public class GralCfgDesigner
020{
021  
022  /**Version, history and license.
023   * <ul>2015-27-01 Hartmut new: Now a text field can be set editable. Usage of a boolean {@link GralCfgData#editable} 
024   * instead changing the type of a text field from 'S' to 'T', but in {@link GralCfgWriter#writeShowField(org.vishia.gral.cfg.GralCfgData.GuiCfgShowField)}
025   *  it is written as a "InputTextline(...". It means next read of the config reads it as editable. 
026   * <li>2011-12-03 Hartmut chg: Now the current widget is stored by left-mouse-release in the field
027   *   {@link #widggForDialog}. Editing of Led works. sFormat is regarded. 
028   * <li>2011-09-30 Hartmut chg: rename pressedRightMouseDownForDesign(...) to {@link #editFieldProperties(GralWidget, GralRectangle)}.
029   *     because it isn't called as mouse action.
030   * <li>2011-09-23 Hartmut corr: Use the new windows concept with {@link GralWindow}.
031   * <li>2011-07-07 Hartmut new: Improve dialog, edit all fields of the {@link GralWidget} inclusive positions.
032   * <li>2011-05-24 Created. The configuration of fields of a GUI are edit-able now in the GUI itself without any other tool.
033   * </ul>
034   *
035   * <b>Copyright/Copyleft</b>:<br>
036   * For this source the LGPL Lesser General Public License,
037   * published by the Free Software Foundation is valid.
038   * It means:
039   * <ol>
040   * <li> You can use this source without any restriction for any desired purpose.
041   * <li> You can redistribute copies of this source to everybody.
042   * <li> Every user of this source, also the user of redistribute copies
043   *    with or without payment, must accept this license for further using.
044   * <li> But the LPGL is not appropriate for a whole software product,
045   *    if this source is only a part of them. It means, the user
046   *    must publish this part of source,
047   *    but doesn't need to publish the whole source of the own product.
048   * <li> You can study and modify (improve) this source
049   *    for own using or for redistribution, but you have to license the
050   *    modified sources likewise under this LGPL Lesser General Public License.
051   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
052   * </ol>
053   * If you intent to use this source without publishing its usage, you can get
054   * a second license subscribing a special contract with the author. 
055   * 
056   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
057   */
058  public static final String version = "2015-01-27";
059  
060  protected final LogMessage log;
061
062  private final GralMng mng;
063  
064  private final GralCfgBuilder cfgBuilder;
065
066  /**A Panel which contains the table to select some projectPaths. */
067  //private GuiShellMngBuildIfc dialogWindowProps;
068  private GralWindow dialogWindowProps;
069
070  /**Some dialog widget elements. */
071  GralWidget dialogFieldName, dialogFieldDatapath, dialogFieldText, dialogFieldFormat
072    , dialogFieldShow, dialogFieldAction, dialogFieldPrompt, dialogFieldHelp, dialogFieldPromptPos 
073    , dialogFieldLine, dialogFieldColumn, dialogFieldHeight, dialogFieldWidth;
074  
075  GralButton dialogBtnEditable;
076  
077  private GralWidget dialogButtonOk, dialogButtonEsc;
078  
079  /**Coordinates while left mouse pressed. */
080  private int xMouse0, yMouse0;
081  
082  /**Coordinates while mouse moved, capture on release button. */
083  private int xMouse, yMouse;
084  
085  private boolean bWidgetMoving = false;
086  
087  /**The widget which properties are edit yet or null. */
088  GralWidget widgdInDialog = null;
089  
090  /**The widget which was marked (with left mouse up). This widget will be used for design-edit
091   * if the next action is {@link #editFieldProperties(GralWidget, GralRectangle)}.
092   */
093  GralWidget widggForDialog;
094  
095  public GralCfgDesigner(GralCfgBuilder cfgBuilder, GralMng mng, LogMessage log)
096  { this.cfgBuilder = cfgBuilder;
097    this.log = log;
098    this.mng = mng;
099  }
100
101  
102  /**Initializes the dialog box of the field properties. 
103   * It should be called in the GUI-Thread.
104   */
105  public void setToPanel()
106  {
107    assert(dialogWindowProps == null); //check call only one time.
108    mng.selectPanel("primaryWindow");
109    mng.setPosition(-38, GralPos.size +38, -40, GralPos.size +40, 1, 'r');
110    dialogWindowProps = mng.createWindow("widgetEdit", "Widget Properties", GralWindow.windConcurrently);
111    
112    mng.setPositionSize(1, 0, 3, 34, 'd');
113    dialogFieldName = mng.addTextField("name", true, "name", "t");
114    dialogFieldDatapath = mng.addTextField("dataPath", true, "data", "t");
115    dialogFieldText = mng.addTextField("text", true, "text", "t");
116    dialogFieldFormat = mng.addTextField("format", true, "format", "t");
117    dialogFieldShow = mng.addTextField("show", true, "show method", "t");
118    dialogFieldAction = mng.addTextField("action", true, "action method", "t");
119    dialogFieldHelp = mng.addTextField("help", true, "help", "t");
120    dialogFieldPrompt = mng.addTextField("prompt", true, "prompt", "t");
121    //mng.setPositionSize(GralGridPos.same, GralGridPos.same, GralGridPos.next, 2, 'r');
122    mng.setPositionSize(27, 2, 3, 5, 'r');
123    dialogFieldLine = mng.addTextField("line", true, "pos-y", "t");
124    //mng.addText(", ", 'B', 0);
125    dialogFieldColumn = mng.addTextField("column", true, "pos-x", "t");
126    //mng.addText("   ", 'B', 0);
127    dialogFieldHeight = mng.addTextField("height", true, "size-y", "t");
128    //mng.addText(" x ", 'B', 0);
129    dialogFieldWidth = mng.addTextField("width", true, "size-x", "t");
130    dialogFieldPromptPos = mng.addTextField("promptPos", true, "promptPos", "t");
131    dialogBtnEditable = mng.addSwitchButton("editable", "view", "edit", GralColor.getColor("wh"), GralColor.getColor("or"));
132    mng.setPositionSize(31, 2, 3, 8, 'r');
133    dialogButtonEsc = mng.addButton("esc", actionEsc, null, null, "esc");
134    dialogButtonOk = mng.addButton("del", actionDel, null, null, "del");
135    dialogButtonOk = mng.addButton("OK", actionOk, null, null, "OK");
136  }
137  
138  
139
140  public void pressedLeftMouseDownForDesign(GralWidget widgd, GralRectangle xy)
141  {
142    xMouse0 = xy.x;
143    yMouse0 = xy.y;
144    bWidgetMoving = true;
145  }
146  
147
148  public void markWidgetForDesign(GralWidget widgg)
149  {
150    widggForDialog = widgg;
151  }
152  
153  
154  public void releaseLeftMouseForDesign(GralWidget widgd, GralRectangle xy, boolean bCopy)
155  {
156    if(bWidgetMoving){
157      bWidgetMoving = false;
158      int dxPixel = xy.x - xMouse0;
159      int dyPixel = xy.y - yMouse0;
160      
161      float dxGridf = (float)dxPixel / mng.propertiesGui.xPixelUnit();
162      float dyGridf = (float)dyPixel / mng.propertiesGui.yPixelUnit();
163      
164      int dxGrid = (int)(dxGridf >0 ? dxGridf + 0.5f : dxGridf - 0.5f);
165      int dyGrid = (int)(dyGridf >0 ? dyGridf + 0.5f : dyGridf - 0.5f);
166      
167      GralCfgElement cfge = (GralCfgElement)widgd.getCfgElement();
168      if(cfge !=null){
169        String sPanel = cfge.getPanel();  //Note: The cloned Object maybe empty here before buildWidget() is called
170        int xPosAct = cfge.get_xPos();
171        int yPosAct = cfge.get_yPos();
172        if(bCopy){
173          GralCfgElement cfgn = cfge.clone(); //cfgBuilder.newCfgElement(cfge);
174          cfge = cfgn;
175        }
176        if(cfge.positionString !=null) {
177          
178        } else {
179          cfge.positionInput.xPos = xPosAct + dxGrid; 
180          cfge.positionInput.yPos = yPosAct + dyGrid; 
181        }
182        if(!bCopy){
183          widgd.remove();
184          //mng.remove(widgd);  //remove the widget.
185        }
186        mng.selectPanel(sPanel);
187        try{ cfgBuilder.buildWidget(cfge);
188        } catch(ParseException exc) {
189          System.err.println("GralCfgDesigner - setPos, " + exc.getMessage());
190        }
191      }
192      
193    }
194    
195  }
196
197  
198  public void editFieldProperties(GralWidget widgd, GralRectangle xy)
199  { //widgd = widgdInDialog = widggForDialog;
200    widgdInDialog = widggForDialog = widgd;
201    if(widgdInDialog != null){
202      //widgd = widgdInDialog;
203      GralCfgElement cfge = (GralCfgElement)widgd.getCfgElement();
204      String sName, sDataPath, sText, sFormat, sShowMethod,  sActionMethod;
205      String sPrompt, sPromptPos;
206      String sLine, sColumn, sWidth, sHeight;
207      if(cfge !=null){
208        sName = cfge.widgetType.name;
209        sDataPath = cfge.widgetType.data;
210        sText = cfge.widgetType.text;
211        sFormat = cfge.widgetType.format;
212        sShowMethod = cfge.widgetType.showMethod;
213        sActionMethod = cfge.widgetType.userAction;
214        sPrompt = cfge.widgetType.prompt;
215        sPromptPos = cfge.widgetType.promptPosition;
216        
217        sLine = (cfge.positionInput.yPosRelative ? "&" : "") + cfge.positionInput.yPos + (cfge.positionInput.yPosFrac !=0 ? "." + cfge.positionInput.yPosFrac : "");
218        sColumn = (cfge.positionInput.xPosRelative ? "&" : "") + cfge.positionInput.xPos + (cfge.positionInput.xPosFrac !=0 ? "." + cfge.positionInput.xPosFrac : "");
219        sHeight = "" + cfge.positionInput.ySizeDown + (cfge.positionInput.ySizeFrac !=0 ? "." + cfge.positionInput.ySizeFrac : "");
220        sWidth = "" + cfge.positionInput.xWidth + (cfge.positionInput.xSizeFrac !=0 ? "." + cfge.positionInput.xSizeFrac : "");
221        dialogFieldName.setText(sName ==null ? "" : sName);
222        dialogFieldDatapath.setText( sDataPath == null ? "" : sDataPath);
223        dialogFieldText.setText(sText ==null ? "" : sText);
224        dialogFieldFormat.setText( sFormat ==null ? "" : sFormat);
225        dialogFieldShow.setText( sShowMethod ==null ? "" : sShowMethod);
226        dialogFieldAction.setText( sActionMethod ==null ? "" : sActionMethod);
227        dialogFieldHelp.setText(cfge.widgetType.help !=null ? cfge.widgetType.help : "");
228        dialogFieldPrompt.setText( sPrompt ==null ? "" : sPrompt);
229        dialogFieldPromptPos.setText( sPromptPos ==null ? "" : sPromptPos);
230        dialogFieldLine.setText( sLine);
231        dialogFieldColumn.setText( sColumn);
232        dialogFieldHeight.setText( sHeight);
233        dialogFieldWidth.setText( sWidth);
234        dialogBtnEditable.setValue(cfge.widgetType.editable ? 1 : 0);
235      } else {
236        dialogFieldName.setText( "ERROR cfge");
237      }
238    }
239    //dialogWindowProps.posWindow.setPosition(widgd.pos, widgd.pos.y +2, GralGridPos.size+30, widgd.pos.x, GralGridPos.size+40, 1, 'r' );
240    //dialogWindowProps.setWindowVisible(true);
241    //use manager to position.
242    dialogWindowProps.setFocus(); //Visible(true);
243    //dialogWindowProps.chgPos(dialogWindowProps.pos());
244    //mng.setWindowsVisible(dialogWindowProps, dialogWindowProps.pos());
245  }
246  
247  private final GralUserAction actionOk = new GralUserAction("actionOk")
248  { @Override public boolean exec(int key, GralWidget_ifc widgd, Object... params)
249    { //note widgd is the OK-button!
250      if(KeyCode.isControlFunctionMouseUpOrMenu(key) && widgdInDialog !=null){
251        String sName = dialogFieldName.getValue();
252        String sDataPath = dialogFieldDatapath.getValue();
253        String sText = dialogFieldText.getValue();
254        String sFormat = dialogFieldFormat.getValue();
255        String sShowMethod = dialogFieldShow.getValue();
256        String sActionMethod = dialogFieldAction.getText();
257        String sHelp = dialogFieldHelp.getValue();
258        String sPrompt = dialogFieldPrompt.getValue();
259        String sPromptPos = dialogFieldPromptPos.getValue();
260        String sLine = dialogFieldLine.getValue();
261        String sColumn = dialogFieldColumn.getValue();
262        String sWidth = dialogFieldWidth.getValue();
263        String sHeight = dialogFieldHeight.getValue();
264        boolean editable = dialogBtnEditable.isOn();
265        
266        GralCfgElement cfge = (GralCfgElement)widgdInDialog.getCfgElement();
267        if(cfge !=null){
268          String sPanel = cfge.getPanel();  //Note: The cloned Object maybe empty here before buildWidget() is called
269            /*if(sName.trim().length() >0) { cfge.widgetType.name = sName; }
270          if(sDataPath.trim().length() >0) { cfge.widgetType.info = sDataPath; }
271          if(sText.trim().length() >0) { cfge.widgetType.text = sText; }
272          if(sFormat.trim().length() >0) { cfge.widgetType.format = sFormat; }
273          */
274          cfge.widgetType.editable = editable;
275          cfge.widgetType.name = sName.trim().length() >0 ? sName : null;
276          cfge.widgetType.data = sDataPath.trim().length() >0 ? sDataPath : null;
277          cfge.widgetType.text = sText.trim().length() >0 ? sText : null;
278          cfge.widgetType.format = sFormat.trim().length() >0 ? sFormat : null;
279          cfge.widgetType.showMethod = sShowMethod.trim().length() >0 ? sShowMethod : null;
280          cfge.widgetType.help = sHelp.trim().length() >0 ? sHelp.trim(): null;
281          
282          String sUserAction = sActionMethod.trim().length() >0 ? sActionMethod : null;
283          if(editable) { 
284            //set userAction to "syncVariableOnFocus" if other is not given.
285            cfge.widgetType.userAction = sUserAction != null ? sUserAction :  "syncVariableOnFocus";
286          } else {
287            //clear the userAction if "syncVariableOnFocus" was given before.
288            cfge.widgetType.userAction = sUserAction !=null && sUserAction.equals("syncVariableOnFocus") ? null : sUserAction;
289          }
290          cfge.widgetType.prompt = sPrompt.trim().length() >0 ? sPrompt : null;
291          cfge.widgetType.promptPosition = sPromptPos.trim().length() >0 ? sPromptPos : null;
292          boolean bOk;
293          bOk = cfge.positionInput.setPosElement('y', sLine.trim());          
294          bOk = bOk && cfge.positionInput.setPosElement('x', sColumn.trim());          
295          bOk = bOk && cfge.positionInput.setPosElement('h', sHeight.trim());          
296          bOk = bOk && cfge.positionInput.setPosElement('w', sWidth.trim());
297          if(!bOk)
298            stop();
299          mng.remove(widgdInDialog);  //remove the widget.
300          mng.selectPanel(sPanel);
301          try{ cfgBuilder.buildWidget(cfge);
302          } catch(ParseException exc) {
303            //show the exception in the dialog box!
304          }
305        }
306        dialogWindowProps.setWindowVisible(false);
307        widgdInDialog = null;
308      }
309      return true;
310    }
311    
312  };
313
314  
315  
316  
317  private final GralUserAction actionDel = new GralUserAction("actionDel")
318  { @Override public boolean exec(int key, GralWidget_ifc widgd, Object... params)
319    { //note widgd is the OK-button!
320      if(KeyCode.isControlFunctionMouseUpOrMenu(key) && widgdInDialog !=null){
321        //widgdInDialog.remove();
322        mng.remove(widgdInDialog);  //remove the widget.
323        dialogWindowProps.setWindowVisible(false);
324        widgdInDialog = null;
325        return true;
326      } else {
327        return false;
328      }
329    }
330    
331  };
332
333  
334  
335  
336  
337  
338  
339  private final GralUserAction actionEsc = new GralUserAction("actionEsc")
340  { @Override public boolean exec(int key, GralWidget_ifc widgd, Object... params)
341    { if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
342        dialogWindowProps.setWindowVisible(false);
343        widgdInDialog = null;
344      }
345      return true;
346    }
347    
348  };
349
350  
351  void stop(){}
352
353}