diff --git a/.gitignore b/.gitignore index afdbbcdf61..51612ac868 100644 --- a/.gitignore +++ b/.gitignore @@ -66,9 +66,13 @@ environment_log.txt # Documentation # ################# -Documentation/html_viewer/resources/data/api/*.js +Documentation/html_viewer/resources/data/api*/*.js Documentation/html_viewer/resources/data/guide/*.js # Additional externals # ######################## Ext/ + +# Edition file # +################ +edition.txt diff --git a/.mention-bot b/.mention-bot new file mode 100644 index 0000000000..1c94340c51 --- /dev/null +++ b/.mention-bot @@ -0,0 +1,3 @@ +{ + "requiredOrgs": ["livecode"] +} diff --git a/Documentation/dictionary/datagrid.lcdoc b/Documentation/dictionary/datagrid.lcdoc index 11c8298382..3d81fcf7cd 100644 --- a/Documentation/dictionary/datagrid.lcdoc +++ b/Documentation/dictionary/datagrid.lcdoc @@ -1,19 +1,15 @@ -Name: Datagrid +Library: Datagrid Type: object -Syntax: Datagrid - Summary: An object for forms or tables Description: The Data Grid enables you to integrate powerful tables and forms into your LiveCode projects. Data grids combine LiveCode groups and behaviors to provide you with a simple, yet flexible means of displaying your data -in just about any way you want. See -http://lessons.livecode.com/m/datagrid/l/7301-what-is-the-data-grid for -full documentation, lessons, and tutorials. - +in just about any way you want. See [the datagrid lessson](http://lessons.livecode.com/m/datagrid/l/7301-what-is-the-data-grid) +for full documentation, lessons, and tutorials. Name: Datagrid General Properties @@ -1686,23 +1682,40 @@ false then each item of each line in pText will be named "Label X" When retrieving the dgText property, setting the pIncludeColumnNames to true will cause the column names to be included in the first line. -Name: dgHilitedIndexes synonyms: dgHilitedIndex type: property + +Name: dgHilitedIndexes + +synonyms: dgHilitedIndex + +type: property + Associations: datagrid -syntax: set the dgHilitedIndexes of group "DataGrid" to pIndex summary: -Returns a comma delimited list of the indexes that are currently -selected. Description: +syntax: set the dgHilitedIndexes of group "DataGrid" to pIndex + +summary: Returns a comma delimited list of the indexes that are currently +selected. + +Description: Returns a comma delimited list of the indexes that are currently selected. -Name: dgHilitedLines synonyms: dgHilitedLine type: property +Name: dgHilitedLines + +synonyms: dgHilitedLine + +type: property + Associations: datagrid -syntax: set the dgHilitedLines of group "DataGrid" to pLine summary: -Returns a comma delimited list of the line numbers that are currently -selected. Description: +syntax: set the dgHilitedLines of group "DataGrid" to pLine + +summary: Returns a comma delimited list of the line numbers that are currently +selected. + +Description: Returns a comma delimited list of the line numbers that are currently selected. @@ -1768,12 +1781,60 @@ Syntax: put the dgIndexOfLine[pLine] of group "DataGrid" Summary: Returns the index associated with the given line. - Description: Returns the index associated with the given line. +Name: dgRectOfIndex + +Type: property + +Associations: datagrid + +Syntax: get the dgRectOfIndex[pIndex] of group "DataGrid" + +Summary: Get/set the rect of the control associated with the given index + +Description: + +Returns the rect of the control connected with pIndex. Rect +is relative to this group but takes into account the current vScroll. +This may not prove very useful if you don't have control caching on. + + +Name: dgRectOfLine + +Type: property + +Associations: datagrid + +Syntax: get the dgRectOfLine[pLine] of group "DataGrid" + +Summary: Get/set the rect of the control associated with the given line + +Description: + +Returns the rect of the control connected with pLine. Rect +is relative to this group but takes into account the current vScroll. +This may not prove very useful if you don't have control caching on. + + + +Name: dgLineOfIndex + +Type: property + +Associations: datagrid +Syntax: put the dgLineOfIndex[pIndex] of group "DataGrid" + +Summary: Returns the line associated with the given index. + + +Description: + +Returns the line associated with the given index. + Name: dgVScroll @@ -1895,8 +1956,6 @@ the data will be added to the end of the existing data. Name: DeleteIndex -Synonyms: DeleteIndexes - Type: command Associations: datagrid, datagrid commands @@ -1907,13 +1966,27 @@ Summary: Deletes the specified indexes from the data grid. Description: +Deletes the specified indexes from the data grid. pIndex is an +integer. + + +Name: DeleteIndexes + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "DeleteIndexes" to group "DataGrid" with pIndexes + +Summary: Deletes the specified indexes from the data grid. + +Description: + Deletes the specified indexes from the data grid. pIndexes is a comma delimited list of integers. -Name: DeleteLine - -Synonyms: DeleteLines +Name: DeleteLine Type: command @@ -1923,6 +1996,21 @@ Syntax: dispatch "DeleteLine" to group "DataGrid" with pLine Summary: Deletes the specified lines from the data grid. +Description: +Deletes the specified line from the data grid. pLine is an +integer. + + +Name: DeleteLines + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "DeleteLine" to group "DataGrid" with pLines + +Summary: Deletes the specified lines from the data grid. + Description: Deletes the specified lines from the data grid. pLines is a comma delimited list of integers. @@ -2470,13 +2558,13 @@ Type: message Associations: datagrid, Datagrid Template Custom Properties & Messages -Syntax: on LayoutControl pControlRect +Syntax: on LayoutControl pControlRect, pWorkingRect Summary: The EditValue message is sent to a table column control when EditCell or EditCellOfIndex is called. Example: -on LayoutControl pControlRect +on LayoutControl pControlRect, pWorkingRect set the rect of field "FirstName" to pControlRect end LayoutControl @@ -2487,9 +2575,11 @@ position all of the controls. pControlRect is the rectangle that the data grid has resized your control to. This is useful for knowing the left (item 1 of pControlRect), top (item 2 of pControlRect), right (item 3 of pControlRect) and bottom (item 4 of pControlRect) bounds you can -position controls at. Note that if you have a data grid form that does -not have fixed height set to true then you can ignore the botom (item 4 -of pControlRect) and make your control as tall as you need. +position controls at. pWorkingRect is the rectangle within which you can safely +position your controls without overlapping with any edit mode controls. Note +that if you have a data grid form that does not have fixed height set to true +then you can ignore the bottom (item 4 of pControlRect) and make your control as +tall as you need. Name: dgLine @@ -2600,3 +2690,922 @@ Description: This property is set by the data grid to set the highlighted state of the row or column control. If the value is "true" then the control should be highlighted. If "false" then it should not be. + + +Name: dgEditMode + +Type: property + +Associations: datagrid + +syntax: set the dgEditMode of group "DataGrid" to {true | false} + +Summary: Take the data grid into or out of edit mode. + +Description: + +Use the property to put the data grid into or take it out of edit +mode. When in edit mode, the data grid displays an action control of the left +hand side of each row (as defined by ) and a reorder +control on the right. The appearance and behavior of these controls can be +customized. + +Only data grids form type data grids with can be put into +edit mode. + +Related: edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: animate actions + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["animate actions"] of group "Data Grid" to {true | false} + +Summary: Turn animations on or off for the data grid. + +Description: + +When is set to true, the data grid will animate the deleting +of rows, entering and exiting edit mode, row reordering, showing and hiding of +action controls and row drag and swipe actions. + +To prevent these actions from being animated, set to false. + +Name: enable swipe + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["enable swipe"] of group "Data Grid" to {true | false} + +Summary: Turn drag and swipe actions on or off for the data grid. + +Description: + +When is set to true, users can drag and swipe rows of form style +data grids left and right, gradually revealing controls at either side of the +row. The default appearance of the revealed controls and the behavior of the +swipe actions can be customized. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), +RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), RowSwipedLeft +(message), RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked +(message), RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden +(message), RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: edit mode action control + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["edit mode action control"] of group "Data Grid" to +the long id of + +Summary: Set the action control to display when the data grid is in edit mode. + +Description: + +Use to specify the action control to display when the +data grid is in edit mode. This defaults to a red delete button. Set to empty to +prevent the action control from being displayed. + +Related: dgEditMode(property), edit mode action select control (property), +edit mode reorder control (property), EditModeShowActionControlForIndex (command), +EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: edit mode action select control + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["edit mode action select control"] of group "Data Grid" +to the long id of + +Summary: Set the action select control to display when the data grid is in edit +mode. + +Description: + +Use to specify the action select control to +display when the data grid is in edit mode. This defaults to a red stop icon. +Set to empty to prevent the action select control from being displayed. + +Related: dgEditMode(property), edit mode action control (property), +edit mode reorder control (property), EditModeShowActionControlForIndex (command), +EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), EditModeActionControlClicked (message), +EditModeActionControlHidden (message), GetEditModeActionControl (message), +GetEditModeActionSelectControl (message), GetEditModeReorderControl (message) + + +Name: edit mode reorder control + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["edit mode reorder control"] of group "Data Grid" to +the long id of + +Summary: Set the reorder control to display when the data grid is in edit mode. + +Description: + +Use to specify the reorder control to display when +the data grid is in edit mode. This defaults to a grey reorder icon. Set to +empty to prevent the reorder control from being displayed, turning dynamic +reordering off for the data grid. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: left swipe control + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["left swipe control"] of group "Data Grid" to the long +id of + +Summary: Set the control to display when a data grid row is dragged to the right. + +Description: + +Use to specify the control to display when when a data grid +row is dragged to the right. This defaults to a trash icon on a red background. +Set to empty to prevent drags and swipes to the right. + +Related: enable swipe (property), right swipe control (property), +RowSwipeShowControlForIndexAndSide (command), RowSwipeHideControl (message), +RowSwipedRight (message), RowSwipedLeft (message), +RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowRightSwipeControlClicked (message), +RowLeftSwipeControlHidden (message), RowRightSwipeControlHidden (message), +GetLeftSwipeControl (message), GetRightSwipeControl (message) + + +Name: right swipe control + +Type: property + +Associations: datagrid, datagrid general properties + +Syntax: set the dgProp["right swipe control"] of group "Data Grid" to the long +id of + +Summary: Set the control to display when a data grid row is dragged to the left. + +Description: + +Use to specify the control to display when when a data +grid row is dragged to the left. This defaults to a trash icon on a red +background. Set to empty to prevent drags and swipes to the left. + +Related: enable swipe (property), left swipe control (property), +RowSwipeShowControlForIndexAndSide (command), RowSwipeHideControl (message), +RowSwipedRight (message), RowSwipedLeft (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: EditModeShowActionControlForIndex + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "EditModeShowActionControlForIndex" to group "DataGrid" with + + +Summary: Display the action control for the data grid row with the given index. + +Description: + +Display the action control for the data grid row with the given index. The data +grid must be in edit mode for the action control to be displayed. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: EditModeHideActionControl + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "EditModeHideActionControl" to group "DataGrid" with {true | false} + +Summary: Hide any visible data grid action control. + +Description: + +Hide any visible data grid action control. Passing true as the first parameter +will prevent the hide from being animated. This is useful if you wish to hide +the row instantly, for example when deleting, but don't want to turn off +animations globally. + +Related: dgEditMode(property), edit mode action control (property), edit mode +action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeActionSelectControlClicked +(message), EditModeActionControlClicked (message), EditModeActionControlHidden +(message), GetEditModeActionControl (message), GetEditModeActionSelectControl +(message), GetEditModeReorderControl (message) + + +Name: RowSwipeShowControlForIndexAndSide + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "RowSwipeShowControlForIndexAndSide" to group "DataGrid" with +, {"left" | "right"} + +Summary: Display the data grid swipe control on the given side of the row with +the given index. + +Description: + +Display the data grid swipe control on the given side of the row with the given +index. must be true for swipe controls to be displayed. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeHideControl (message), +RowSwipedRight (message), RowSwipedLeft (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowSwipeHideControl + +Type: command + +Associations: datagrid, datagrid commands + +Syntax: dispatch "RowSwipeHideControl" to group "DataGrid" with {true | false} + +Summary: Hide any visible data grid swipe control. + +Description: + +Hide any visible data grid swipe control. Passing true as the first parameter +will prevent the hide from being animated. This is useful if you wish to hide +the row instantly, for example when deleting, but don't want to turn off +animations globally. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipedRight (message), RowSwipedLeft (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: EditModeActionSelectControlClicked + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on EditModeActionSelectControlClicked pTarget + +Summary: Sent when a user clicks on a data grid edit mode action select control. + +Example: +on EditModeActionSelectControlClicked pTarget + switch the name of the target + case "show" + dispatch "EditModeShowActionControlForIndex" to group "DataGrid" with the dgIndex of me + break + default + set the dgEditMode of group "DataGrid" to false + break + end switch +end EditModeActionSelectControlClicked + +Parameters: +pTarget: The target of the click. Use this to determine where in the action +select control the user clicked. + +Description: + + is sent to your data grid's custom row +template when the user clicks on a row's action select control. Handle + if you wish to perform a custom behavior. + +The default behavior is to show the edit mode action control. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: EditModeActionControlClicked + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on EditModeActionControlClicked pTarget + +Summary: Sent when a user clicks on a data grid edit mode action control. + +Example: +on EditModeActionControlClicked pTarget + answer "Confirm delete" with "Yes" and "No" + if it is "Yes" then + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me + else + dispatch "EditModeHideActionControl" to group "DataGrid" with the dgIndex of me. + end if +end EditModeActionControlClicked + +on EditModeActionControlClicked pTarget + switch the name of the target + case "show" + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me + break + case "archive" + dispatch "EditModeHideActionControl" to group "DataGrid" + break + end switch +end EditModeActionControlClicked + +Parameters: +pTarget: The target of the click. Use this to determine where in the action +control the user clicked. + +Description: + + is sent to your data grid's custom row template +when the user clicks on a row's action control. Handle + if you wish to perform a custom behavior. + +The default behavior is to delete the current row. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: EditModeActionControlHidden + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on EditModeActionControlHidden + +Summary: Sent when the datagrid's edit mode action control is hidden. + +Description: + + is sent to your data grid's custom row template +when an action control is visible and the user clicks on the data grid, +resulting in the action control being hidden. Handle + to perform a custom action on hide. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), EditModeActionControlClicked (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: RowSwipedRight + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowSwipedRight + +Summary: Sent when the user swipes a data grid row right. + +Example: +on RowSwipedRight + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me +end RowSwipedRight + +Description: + + is sent to your data grid's custom row template when the user +swipes a row of the data grid right. Handle if you want to +perform a custom action on a right swipe. + +The default action is to show the left swipe control. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedLeft (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowSwipedLeft + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowSwipedLeft + +Summary: Sent when the user swipes a data grid row left. + +Example: +on RowSwipedLeft + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me +end RowSwipedLeft + +Description: + + is sent to your data grid's custom row template when the user +swipes a row of the data grid left. Handle if you want to +perform a custom action on a left swipe. + +The default action is to show the right swipe control. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowLeftSwipeControlClicked + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowLeftSwipeControlClicked pTarget + +Summary: Sent when the left hand side data grid swipe control is clicked. + +Example: +on RowLeftSwipeControlClicked + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me +end RowLeftSwipeControlClicked + +on RowLeftSwipeControlClicked pTarget + switch the name of the target + case "show" + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me + break + case "archive" + dispatch "RowSwipeHideControl" to group "DataGrid" + break + end switch +end RowLeftSwipeControlClicked + +Parameters: +pTarget: The target of the click. Use this to determine where in the swipe +control the user clicked. + +Description: + + is sent to your data grid's custom row template +when the user clicks on the left hand side swipe control. Handle + if you want to perform a custom action on click. + +The default action is to delete the current row. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowRightSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowRightSwipeControlClicked + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowRightSwipeControlClicked pTarget + +Summary: Sent when the right hand side data grid swipe control is clicked. + +Example: +on RowRightSwipeControlClicked + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me +end RowRightSwipeControlClicked + +on RowRightSwipeControlClicked pTarget + switch the name of the target + case "show" + dispatch "DeleteIndex" to group "DataGrid" with the dgIndex of me + break + case "archive" + dispatch "RowSwipeHideControl" to group "DataGrid" + break + end switch +end RowRightSwipeControlClicked + +Parameters: +pTarget: The target of the click. Use this to determine where in the action +control the user clicked. + +Description: + + is sent to your data grid's custom row template +when the user clicks on the right hand side swipe control. Handle + if you want to perform a custom action on click. + +The default action is to delete the current row. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowLeftSwipeControlHidden (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowLeftSwipeControlHidden + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowLeftSwipeControlHidden + +Summary: Sent when the left hand side data grid swipe control is hidden. + +Description: + + is sent to your data grid's custom row template when +an left hand side swipe control is visible and the user clicks on the data grid, +resulting in the swipe control being hidden. Handle +to perform a custom action on hide. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowRightSwipeControlClicked (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: RowRightSwipeControlHidden + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on RowRightSwipeControlHidden + +Summary: Sent when the right hand side data grid swipe control is hidden. + +Description: + + is sent to your data grid's custom row template +when an right hand side swipe control is visible and the user clicks on the data +grid, resulting in the swipe control being hidden. Handle + to perform a custom action on hide. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowRightSwipeControlClicked (message), +RowRightSwipeControlHidden (message), GetLeftSwipeControl (message), +GetRightSwipeControl (message) + + +Name: GetEditModeActionControl + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on GetEditModeActionControl + +Summary: Handle this message to specify a custom data grid action control. + +Example: +on GetEditModeActionControl + return group "my custom action control" +end GetEditModeActionControl + +on GetEditModeActionControl + -- Hide for the data grid row number 5 + if the dgIndex of me is 5 then + return empty + end if + pass GetEditModeActionControl +end GetEditModeActionControl + +Description: + + is sent to your data grid's custom row template. +Handle if you want to specify a custom action +control. Return the id of the control you want to display. Returning empty will +result in no control being displayed. + +Handing this message will override the property. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionSelectControl (message), GetEditModeReorderControl (message) + + +Name: GetEditModeActionSelectControl + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on GetEditModeActionSelectControl + +Summary: Handle this message to specify a custom data grid action select control. + +Example: +on GetEditModeActionSelectControl + return group "my custom action select control" +end GetEditModeActionSelectControl + +on GetEditModeActionSelectControl + -- Hide for the data grid row number 5 + if the dgIndex of me is 5 then + return empty + end if + pass GetEditModeActionSelectControl +end GetEditModeActionSelectControl + +on GetEditModeActionSelectControl + -- Turn action select off + return empty +end GetEditModeActionSelectControl + +Description: + + is sent to your data grid's custom row +template. Handle if you want to specify a +custom action select control. Return the id of the control you want to display. +Returning empty will result in no control being displayed. + +Handing this message will override the +property. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), EditModeActionControlClicked (message), +EditModeActionControlHidden (message), GetEditModeActionControl (message), +GetEditModeReorderControl (message) + + +Name: GetEditModeReorderControl + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on GetEditModeReorderControl + +Summary: Handle this message to specify a custom data grid action select +control. + +Example: +on GetEditModeReorderControl + return group "my custom reorder control" +end GetEditModeReorderControl + +on GetEditModeReorderControl + -- Hide for the data grid row number 5 + if the dgIndex of me is 5 then + return empty + end if + pass GetEditModeReorderControl +end GetEditModeReorderControl + +on GetEditModeReorderControl + -- Turn reordering off + return empty +end GetEditModeReorderControl + +Description: + + is sent to your data grid's custom row template. +Handle if you want to specify a custom reorder +control. Return the id of the control you want to display. Returning empty will +result in no control being displayed. + +Handing this message will override the property. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message) + + +Name: GetLeftSwipeControl + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on GetLeftSwipeControl + +Summary: Handle this message to specify a custom data grid left hand side swipe +control. + +Example: +on GetLeftSwipeControl + return group "my custom left swipe control" +end GetLeftSwipeControl + +on GetLeftSwipeControl + -- Hide for the data grid row number 5 + if the dgIndex of me is 5 then + return empty + end if + pass GetLeftSwipeControl +end GetLeftSwipeControl + +on GetLeftSwipeControl + -- Turn right drags and swipes off + return empty +end GetLeftSwipeControl + +Description: + + is sent to your data grid's custom row template. Handle + if you want to specify a custom left hand side swipe +control. Return the id of the control you want to display. Returning empty will +result in no control being displayed. + +Handing this message will override the property. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowRightSwipeControlClicked (message), +RowLeftSwipeControlHidden (message), RowRightSwipeControlHidden (message), +GetRightSwipeControl (message) + + +Name: GetRightSwipeControl + +Type: message + +Associations: datagrid, Datagrid Template Custom Properties & Messages + +Syntax: on GetRightSwipeControl + +Summary: Handle this message to specify a custom data grid right hand side swipe +control. + +Example: +on GetRightSwipeControl + return group "my custom right swipe control" +end GetRightSwipeControl + +on GetRightSwipeControl + -- Hide for the data grid row number 5 + if the dgIndex of me is 5 then + return empty + end if + pass GetRightSwipeControl +end GetRightSwipeControl + +on GetRightSwipeControl + -- Turn left drags and swipes off + return empty +end GetRightSwipeControl + +Description: + + is sent to your data grid's custom row template. Handle + if you want to specify a custom right hand side swipe +control. Return the id of the control you want to display. Returning empty will +result in no control being displayed. + +Handing this message will override the property. + +Related: enable swipe (property), left swipe control (property), +right swipe control (property), RowSwipeShowControlForIndexAndSide (command), +RowSwipeHideControl (message), RowSwipedRight (message), +RowSwipedLeft (message), RowLeftSwipeControlClicked (message), +RowLeftSwipeControlClicked (message), RowRightSwipeControlClicked (message), +RowLeftSwipeControlHidden (message), RowRightSwipeControlHidden (message), +GetLeftSwipeControl (message) + + +Name: EditModeReorderStarted + +Type: message + +Associations: datagrid + +Syntax: EditModeReorderStarted pIndex, pLineNo + +Summary: Sent when a user starts a dynamic reordering of a data grid. + +Parameters: +pIndex: The index of the row being reordered. +pLineNo: The line sequence number of the row within the data grid. + +Description: + + is sent to your data grid when a user starts a dynamic +reordering. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), +EditModeActionControlClicked (message), EditModeActionControlHidden (message), +GetEditModeActionControl (message), GetEditModeActionSelectControl (message), +GetEditModeReorderControl (message) + + +Name: EditModeReorderCompleted + +Type: message + +Associations: datagrid + +Syntax: EditModeReorderCompleted pIndex, pStartLineNo, pNewLineNo + +Summary: Sent when a user completes a dynamic reordering of a data grid. + +Parameters: +pIndex: The index of the reordered row. +pStartLineNo: The original line sequence number of the row within the data grid. +pNewLineNo: The new line sequence number of the row within the data grid. + +Description: + + is sent to your data grid when a user completes a +dynamic reordering. + +Related: dgEditMode(property), edit mode action control (property), +edit mode action select control (property), edit mode reorder control (property), +EditModeShowActionControlForIndex (command), EditModeHideActionControl (command), +EditModeActionSelectControlClicked (message), EditModeActionControlClicked (message), +EditModeActionControlHidden (message), GetEditModeActionControl (message), +GetEditModeActionSelectControl (message), GetEditModeReorderControl (message) + diff --git a/Documentation/guides/Deploying Your Application.md b/Documentation/guides/Deploying Your Application.md index 1ab4bda41a..167663e828 100644 --- a/Documentation/guides/Deploying Your Application.md +++ b/Documentation/guides/Deploying Your Application.md @@ -7,14 +7,11 @@ group: deployment With LiveCode, it is easy to deploy your application to anyone. -Using the standalone building capability in LiveCode you can create a native desktop +Using the standalone building capability in LiveCode you can create a native application for each operating system you want to support. Users who do not have LiveCode can run these applications like any other application they download and install. -Standalone applications can have their own identity as true applications, include a -desktop icon, document associations and more. - -You can also create applications for iOS, android, and HTML5. Please consult the separate -guides for information on how to deploy to these platforms. +Standalone applications can have their own identity as true applications, include +icons, document associations and more. ## Building a Standalone Application @@ -24,13 +21,37 @@ All of LiveCode's feature set is available for use in a standalone application, exception that you cannot set scripts on objects. The builder itself will let you build standalone applications for any platform it supports, -from any platform it supports (for example you can build a Windows standalone on a Mac OS -X machine). However, you may wish to check that your application looks and behaves correctly +from any platform it supports with the exception that iOS standalones must be +built on Mac OS X. For example you can build a Windows standalone on a Mac OS X +machine. However, you may wish to check that your application looks and behaves correctly on each platform you intend to support. Please note it is inherently harder to debug an application that has been built as a standalone, so you should test your application as thoroughly as possible before building it. -### Standalone Applications Settings +Related lessons: + +* [Building Standalone Applications](http://lessons.livecode.com/m/4603/l/44282-building-standalone-applications) +* [How do I Develop Cross-Platform in LiveCode?](http://lessons.livecode.com/m/4069/l/28092-how-do-i-develop-cross-platform-in-livecode) + +### Step by step + +Deploying an app to standalone is straightforward: + +1) Open your stack in the LiveCode IDE + +2) Select **File → Standalone Application Settings...** from the menu bar + +3) Select the settings for your app + +4) Make sure that checkboxes for each platform you wish to build for are checked + +5) Close the standalone settings window + +6) Select **File → Save as Standalone Application...** from the menu bar + +Your application will be packaged up and placed in the selected output folder. + +## Standalone Applications Settings The Standalone Applications Setting dialog allows you to create settings for your standalone application. This dialog can be found in the File menu. The settings you enter @@ -38,6 +59,12 @@ are applied to the current front most editable stack and are saved with the stac means you only need to enter the settings once for each application you create. The same settings will apply if you do another build in the future. +Related lessons: + +* [The Standalone Application Settings](http://lessons.livecode.com/m/4603/l/685074-the-standalone-application-settings) + +## General Settings + ![](images/standalone-settings-general.png) Figure 1 – Standalone Settings – General Tab @@ -75,6 +102,8 @@ user. | **Include profiles and the profile library** | Include the profile library and allow switching between profiles in the standalone application. You can choose whether to include specific profiles or all profiles. | +#### Including Additional Stacks + ![](images/standalone-settings-stacks.png) Figure 2 – Standalone Settings – Stacks Tab @@ -101,6 +130,12 @@ component stacks, or to save changes to them. You may also want to consider crea preference files in the appropriate location on your end user's system (see the `specialFolderPath`function and query/setRegistry functions for more information). +> **Note:** Adding additional stacks to the stacks tab is not supported for iOS, +Android or HTML5 standalones. Additional stacks may be included via the Copy +Files tab. + +#### Including Additional Files + ![](images/standalone-settings-copy-files.png) Figure 3 – Standalone Settings – Copy Files @@ -110,7 +145,8 @@ Figure 3 – Standalone Settings – Copy Files | **Non-stack files in the application** | List other files to be included in the standalone. Use this feature to include help documents, read me files and other resources that you want to include with your standalone each time you build. | | **Copy Referenced Files** | Loops over all image and player objects in stacks and copies any files referenced in the `fileName`property of these objects into the standalone. Then automatically sets the `fileName`property to reference these files in the standalone using referenced file paths. | | **Destination folder** | Create a subfolder within your standalone to copy the image and movie files to. | -| **Extensions** | Select the extensions you wish to include in the standalone. + +#### Including Additional Resources ![](images/standalone-settings-inclusions.png) @@ -136,7 +172,6 @@ The following built-in resources are available by default: | **PDF Printer** | This option is required if your application uses the "open printing to pdf" command. | | **Print Dialog** | This option is required if your application uses LiveCode's built-in print or page setup dialogs (e.g. for use on Linux without GTK installed). It is not required if you only display the system printer and page setup dialogs. It copies the stack "print dialog" and "page setup" into your standalone. | | **SSL & Encryption** | This option is required if your application uses any SSL or encryption related commands | -| **Video Grabber** | This option is required if your application uses any video capture commands | | **XML** | This option is required if your application uses any `revXML` commands | @@ -161,14 +196,16 @@ The following database drivers are available by default: - SQLite - PostgreSQL +## Mac Deployment Settings + ![](images/standalone-settings-mac.png) Figure 5 – Standalone Settings – Mac |  |  | |-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Build for Mac OS X 32-bit** | Build a standalone that will run natively on Mac OS X Intel machines. This standalone will not run at all under PowerPC. | -| **Build for Mac OS X 64-bit (EXPERIMENTAL)** | Build a standalone that will run natively on Mac OS X Intel machines. This standalone will not run at all under PowerPC. | +| **Build for Mac OS X 32-bit** | Build a standalone that includes a 32 bit slice. | +| **Build for Mac OS X 64-bit** | Build a standalone that includes a 64 bit slice. | | **Application Icon** | Choose an application icon to represent the application in the Finder. The icon should be in icns format. | | **Document Icon** | Choose a document icon to represent your application's documents in the Finder. The icon should be in icns format. | | **Icons for ask / answer dialogs** | Choose an icon to display whenever you use the ask or answer commands to display a dialog. On Mac OS X, the convention is that these dialogs should display your application icon. The icon should be stored in your stack as an image, or selected from LiveCode's built-in icons. If you have used a built-in icon, be sure to select the relevant inclusion on the General tab (if you are selecting inclusions manually). | @@ -179,17 +216,26 @@ Figure 5 – Standalone Settings – Mac | **Copyright notice** | The copyright notice for your application. | | **Bundle identifier** | A unique identifier for your application used by Mac OS X to identify your application. | +Related lessons: + +* [Signing and Uploading apps to the Mac App Store](http://lessons.livecode.com/m/4071/l/876834-signing-and-uploading-apps-to-the-mac-app-store) + +## Windows Deployment Settings + ![](images/standalone-settings-windows.png) Figure 6 – Standalone Settings – Windows |  |  | -|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Build for Windows** | Build a standalone for the Microsoft Windows OS. | -| **Application icon** | Choose an application icon to represent the application in Windows. The icon should be in .ico format. | -| **Document icon** | Choose a document icon to represent your application's documents in Windows. The icon should be in .ico format. | -| **Version information** | The version information to be stored as part of your application and displayed in the Windows property inspector and dialogs. | -| **UAC Execution Level** | Select the user account control level that applies to your application. For more information, consult [MSDN](https://msdn.microsoft.com/en-us/library/bb384608.aspx) | +|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Build for Windows x86** | Build a 32-bit standalone for the Microsoft Windows OS. | +| **Build for Windows x86_64** | Build a 64-bit standalone for the Microsoft Windows OS. | +| **Application icon** | Choose an application icon to represent the application in Windows. The icon should be in .ico format. | +| **Document icon** | Choose a document icon to represent your application's documents in Windows. The icon should be in .ico format. | +| **Version information** | The version information to be stored as part of your application and displayed in the Windows property inspector and dialogs. | +| **UAC Execution Level** | Select the user account control level that applies to your application. For more information, consult [MSDN](https://msdn.microsoft.com/en-us/library/bb384608.aspx) | + +## Linux Deployment Settings ![](images/standalone-settings-linux.png) @@ -199,12 +245,382 @@ Figure 7 – Standalone Settings – Linux |---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Build for Linux** | Build a standalone for 32-bit Linux | | **Build for Linux x64** | Build a standalone for 64-bit Linux | -| **Build for Linux ARMv6-HF** | Build a standalone for Linux ARMv6 HF (including Raspberry Pi) | | **Include** | Select built-in LiveCode dialogs to include. These dialogs are useful if your application may be run on a system that does not include these dialogs as part of the OS. You do not need to include these dialogs if you are running a recent version of GTK. | +## iOS Deployment Settings + +![](images/standalone-settings-ios-basic.png) + +Figure 8 – Standalone Settings – iOS Basic Settings + +|  |  | +|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Build for iOS iPod, iPhone and iPad** | Build a standalone iOS iPod, iPhone and iPad | +| **Build for iOS iPod and iPhone** | Build a standalone iOS iPod and iPhone | +| **Build for iOS iPad** | Build a standalone iOS iPad | +| **Minimum version** | Choose the minimum version of iOS that your application should run on | +| **Build 32-bit slice only** | Only include the 32 bit slice in the standalone instead of both the 32 bit and 64 bit slice | +| **Display Name** | The name of the application | +| **Version** | The version number of the application | +| **Beta version** | Enable Test Flight distribution | +| **Build No.** | The build number of the application | +| **Internal App ID** | The application identifier for your application. This should begin with a reverse domain name of a domain you own. | +| **Profile** | The provisioning profile to sign the application with. | +| **iPhone Status Bar** | Choose whether to show or hide the status bar while the application is running on iPhone | +| **iPad Status Bar** | Choose whether to show or hide the status bar while the application is running on iPad | +| **Status Bar Style** | Set the style of the status bar while the application is running | +| **iPhone Initial Orientation** | Set the orientation on iPhone of the application on the screen when it initialy starts | +| **iPad Supported Initial Orientation** | Set the possible orientations on iPad of the application on the screen when it initialy starts | +| **Custom URL Scheme** | Add a custom url scheme to the application so that it will launch when a url is opened that uses the scheme | +| **Mapping file** | Set a font name mapping file which should contain lines of `=` | +| **Telephony** | Choose whether telephony is required, prohibited or not applicable in order for the application to function | +| **Peer-Peer** | Choose whether peer to peer is required, prohibited or not applicable in order for the application to function | +| **SMS** | Choose whether SMS is required, prohibited or not applicable in order for the application to function | +| **Still Camera** | Choose whether a still camera is required, prohibited or not applicable in order for the application to function | +| **Auto-focus Camera** | Choose whether an auto-focus camera is required, prohibited or not applicable in order for the application to function | +| **Front-facing Camera** | Choose whether a front-facing camera is required, prohibited or not applicable in order for the application to function | +| **Accelerometer** | Choose whether an accelerometer is required, prohibited or not applicable in order for the application to function | +| **Location Services** | Choose whether location services is required, prohibited or not applicable in order for the application to function | +| **GPS** | Choose whether GPS is required, prohibited or not applicable in order for the application to function | +| **Magnetometer** | Choose whether a magnetometer is required, prohibited or not applicable in order for the application to function | +| **Microphone** | Choose whether a microphone is required, prohibited or not applicable in order for the application to function | +| **Game-Kit** | Choose whether Game-Kit is required, prohibited or not applicable in order for the application to function | +| **WiFi** | Choose whether WiFi is required, prohibited or not applicable in order for the application to function | +| **Magnetometer** | Choose whether a magnetometer is required, prohibited or not applicable in order for the application to function | +| **OpenGL ES 1.1** | Choose whether OpenGL ES 1.1 is required, prohibited or not applicable in order for the application to function | +| **OpenGL ES 2.0** | Choose whether OpenGL ES 2.0 is required, prohibited or not applicable in order for the application to function | + +![](images/standalone-settings-ios-requirements.png) + +Figure 9 – Standalone Settings – iOS Requirements + +|  |  | +|---------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Location Authorization Type** | Choose whether to authorize location services for just when the application is in use or for background use also | +| **Persistent WiFi** | Indicate the application requires persistent WiFi in order to function | +| **File Sharing** | Indicate the application uses file sharing | +| **Local Notifications** | Indicate the application sends local notifications | +| **Push Notifications** | Indicate the application sends push notifications | +| **Disable ATS** | Disabling ATS allows your application to load insecure websites (not recommended). | +| **Enable Background Execution** | By default LiveCode applications will exit when the user suspends them. This option allows the applications to remain open while in the background. | +| **Background Audio** | Enable if the application plays audio while in the background. | +| **Location Update** | Enable if the application recieves location updates while in the background. | +| **VoIP** | Enable if the application handles VoIP calls while in the background. | +| **Newsstand Downloads** | Enable if the application recieves newsstand downloads while in the background. | +| **External Accessory Communication** | Enable if the application communicates with external accessories while in the background. | +| **Use Bluetooth Low Energy Accessories** | Enable if the application communicates with bluetooth low energy accessories while in the background. | +| **Acts as Bluetooth Low Energy Accessory** | Enable if the application acts as a bluetooth low energy accessory while in the background. | +| **Background Fetch** | Enable if the application fetches data while in the background. | +| **Remote Notifications** | Enable if the application handles remote notifications while in the background. | +| **App URL Query Whitelist** | Specify a list of url schemes the application needs to query to determine if there is an application on the device capable of handling the scheme. | + +![](images/standalone-settings-ios-icons.png) + +Figure 10 – Standalone Settings – iOS Icons + +|  |  | +|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Prerendered Icon** | Indicate the icons are prerendered for display | +| **AppStore** | Choose a 1024x1024 pixel png image | +| **iPhone** | Choose a 57x57 pixel png image | +| **Hi-Res iPhone** | Choose a 114x114 pixel png image | +| **iOS 7 Hi-Res iPhone** | Choose a 120x120 pixel png image | +| **iPhone 6 Plus** | Choose a 160x160 pixel png image | +| **iPhone X** | Choose a 180x180 pixel png image | +| **iPad** | Choose a 72x72 pixel png image | +| **Hi-Res iPad** | Choose a 144x144 pixel png image | +| **iOS 7 iPad** | Choose a 76x76 pixel png image | +| **iOS 7 Hi-Res iPad** | Choose a 152x152 pixel png image | +| **iPad Pro 12.9** | Choose a 167x167 pixel png image | + +![](images/standalone-settings-ios-splash.png) + +Figure 11 – Standalone Settings – iOS Splash + +|  |  | +|-------------------------------------------------|-------------------------------------------------------------------------------------------------------------| +| **Launch Image** | Choose a png image. This will be centered on screen. | +| **2x Launch Image** | Choose a png image. This will be centered on screen. | +| **3x Launch Image** | Choose a png image. This will be centered on screen. | +| **Dark Mode Launch Image** | Choose a png image for use in dark mode. This will be centered on screen. | +| **Dark Mode 2x Launch Image** | Choose a png image for use in dark mode. This will be centered on screen. | +| **Dark Mode 3x Launch Image** | Choose a png image for use in dark mode. This will be centered on screen. | +| **Background Color** | Choose a background color for transparent areas and/or areas of the screen the launch image does not cover. | +| **Use system background color** | Use the system background color instead of a chosen color. This will use a dark color in dark mode and light color in light mode. | + +Related lessons: + +* [How do I Become an iOS Developer?](http://lessons.livecode.com/m/4069/l/565715-how-do-i-become-an-ios-developer) +* [How do I build an iOS application?](http://lessons.livecode.com/m/4069/l/565713-how-do-i-build-an-ios-application) + +## Android Deployment Settings + +![](images/standalone-settings-android.png) + +Figure 12 – Standalone Settings – Android + +|  |  | +|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Build for Android armv7** | Include armv7 binaries in the Android standalone | +| **Build for Android arm64** | Include arm64 binaries in the Android standalone | +| **Build for Android x86** | Include x86 binaries in the Android standalone | +| **Build for Android x86_64** | Include x86_64 binaries in the Android standalone | +| **Label** | The application name | +| **Identifier** | The application identifier for your application. This should begin with a reverse domain name of a domain you own. | +| **Version Name** | The version number of your application | +| **Version Code** | The build number of your application | +| **Icon** | The application icon | +| **Splash** | The application splash screen (applicable to the Educational Personal license only) | +| **Signing** | Choose to sign for development, with your own key or not to sign. | +| **Key** | Choose a Java keystore file to sign with. | +| **Install Location** | Allow installation onto external storage. | +| **Custom URL Scheme** | Add a custom url scheme to the application so that it will launch when a url is opened that uses the scheme. | +| **Push Sender ID** | The project number from Google's Cloud Messaging API. See the [How do I use Push Notifications with Android?](http://lessons.livecode.com/m/4069/l/59312-how-do-i-use-push-notifications-with-android) lesson. | +| **Status Bar Icon** | The icon shown in the status bar for a notification | +| **Hardware Accelerated** | Enable hardware acceleration of the application | +| **Initial Orientation** | The orientation on the device when the application initially launches | +| **Status Bar** | Set the visibility of the status bar | +| **In App Purchasing** | Specify the store used for the in-app purchasing API | +| **Minimum Android Version** | Choose the minimum version of Android the application should run on | +| **Camera** | Choose whether a camera is required, prohibited or not applicable in order for the application to function | +| **Camera Autofocus** | Choose whether camera autofocus is required, prohibited or not applicable in order for the application to function | +| **Camera Flash** | Choose whether a camera flash is required, prohibited or not applicable in order for the application to function | +| **Front Camera** | Choose whether a front camera is required, prohibited or not applicable in order for the application to function | +| **Accelerometer** | Choose whether an accelerometer is required, prohibited or not applicable in order for the application to function | +| **Telephony** | Choose whether telephony is required, prohibited or not applicable in order for the application to function | +| **Telephony CDMA** | Choose whether CDMA telephony is required, prohibited or not applicable in order for the application to function | +| **Telephony GSM** | Choose whether GSM telephony is required, prohibited or not applicable in order for the application to function | +| **Fake Touch** | Choose whether fake touch is required, prohibited or not applicable in order for the application to function | +| **Touchscreen** | Choose whether a touchscreen is required, prohibited or not applicable in order for the application to function | +| **Multitouch** | Choose whether multitouch is required, prohibited or not applicable in order for the application to function | +| **Multitouch Distinct** | Choose whether multitouch distinct is required, prohibited or not applicable in order for the application to function | +| **Multitouch Jazzhand** | Choose whether multitouch jazzhand is required, prohibited or not applicable in order for the application to function | +| **Write External Storage** | Request permission to write to external storage | +| **Internet** | Request permission to for internet access | +| **Camera** | Request permission to access the camera | +| **Read Contacts** | Request permission to read the user's contact data | +| **Write Contacts** | Request permission to write to the user's contact data | +| **NFC Tag Reading** | Request permission to read NFC tags | +| **Fine Location** | Request permission to access the device's fine location | +| **Course Location** | Request permission to access the device's course location | +| **Vibration** | Request permission to vibrate the device | +| **Idle Timer** | Request permission for the idle timer | +| **Ad Support** | Request permission for ad support | + +Related lessons: + +* [LiveCode and Android Studio](http://lessons.livecode.com/m/4069/l/985962-livecode-and-android-studio) +* [The Basics: How do I Create Hello World on Android?](http://lessons.livecode.com/m/4069/l/27733-the-basics-how-do-i-create-hello-world-on-android) + +## HTML5 Deployment Settings + +![](images/standalone-settings-html5.png) + +Figure 13 – Standalone Settings – HTML5 + +|  |  | +|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Build for HTML5** | Build a standalone for HTML5 | + +Almost every Internet-connected device has a web browser. If your application +can run in a browser, your app can be used anywhere and by anyone, without any +need to download or install it. + +Related lessons: + +* [How Do I Put My First App On the Web](http://lessons.livecode.com/m/4071/l/800867-how-do-i-put-my-first-app-on-the-web) + +##### Supported browsers + +The following browsers are supported: + +* [Mozilla Firefox](https://www.mozilla.org/firefox/new/) 40.0 (or newer) +* [Google Chrome](https://www.google.com/chrome/) 44 (or newer) +* [Safari for Mac](https://support.apple.com/HT204416) 9.0 (or newer) + +##### HTML5 engine features + +The HTML5 engine in this release of LiveCode has a limited range of features. +You can: + +* deploy single or multiple stack applications with embedded resources. Stacks +other than the main stack will open in their own floating container windows. +* use most of the engine's built-in controls and graphics capabilities. +* read and write temporary files in a special virtual filesystem (which is +erased when the user navigates away from the page) +* use LiveCode Builder widgets and extensions +* interact with JavaScript code in the web page using `do + +##### Engine download + +The engine is quite a large JavaScript file, so it's downloaded asynchronously +in order to let the rest of the page finish loading and start being displayed. + +Quite straightforwardly: + + + +Make sure to replace `` as appropriate. + +##### Bringing it all together + +Here's the complete skeleton web page for an HTML5 standalone: + + + +
+ +
+ + + + + + +##### Advanced: Speeding up engine download + +Currently, the engine files are almost 30 MB, which is a lot to download before +the engine can start. It is possible to speed up the download by enabling +deflate compression in the web server configuration. + +Enabling deflate compression reduces the total download size to around 6.3 MB. +It's recommended to pre-compress the engine with `gzip`, and then configure your +web server to serve the pre-compressed files. + +* For the Apache web server, configure `mod_deflate` to serve [pre-compressed content](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html#precompressed) +* For the NGINX web server, add [`gzip_static on;`](https://www.nginx.com/resources/admin-guide/compression-and-decompression/#send) +to your configuration. + +##### Advanced: Customizing the Module object + +There are a number of LiveCode-specific `Module` attributes that you can modify +to affect how the engine behaves: + +* `Module.livecodeStandalone`: the filename of the standalone archive (default +`standalone.zip`) +* `Module.livecodeStandalonePrefixURL`: Prepended to the standalone archive +filename to construct its full URL (default empty) +* `Module.livecodeStandaloneRequest`: If you assign a network request to this +attribute (before the engine runs), then it will use that request for the +standalone archive instead of automatically starting a download for you. This +means that you can, in your HTML, fire off a request for the standalone before +the engine script actually arrives. For this to work, the network request +should be an `XMLHttpRequest` with its `responseType` set to `arraybuffer`. + +See also Emscripten's [Module object documentation](https://kripken.github.io/emscripten-site/docs/api_reference/module.html). + +#### Bug Reports + ![](images/standalone-settings-bug-reports.png) -Figure 8 – Standalone Settings – Bug Reports +Figure 14 – Standalone Settings – Bug Reports |  |  | |---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -213,4 +629,34 @@ Figure 8 – Standalone Settings – Bug Reports | **Dialog icon** | The icon to display in the error dialog. This should be stored as an image in your stack. | | **Allow user to enter comments** | Display a box for the user to give you more information. This information will be included in the report. | | **Allow user to save report to file** | Allow the user to save the report to a file. Select this option if you want users to save an error report and send it to you. | -| **Allow user to email report** | Allow the user to email the report. Select this option if you want the user to be able to send you or your technical support department details of the error. This option loads up the system default email client and populates the email with the contents of the error report and the user's comments. The To: field is sent to the email address specified in the email address field. | \ No newline at end of file +| **Allow user to email report** | Allow the user to email the report. Select this option if you want the user to be able to send you or your technical support department details of the error. This option loads up the system default email client and populates the email with the contents of the error report and the user's comments. The To: field is sent to the email address specified in the email address field. | + +## Testing Your Application + +Testing an app is straightforward: + +1) Open your stack in the LiveCode IDE + +2) Select **File → Standalone Application Settings...** from the menu bar + +3) Select the settings for your app + +4) Make sure that checkboxes for each platform you wish to build for are checked +as the chosen platforms will govern which test targets are available. + +5) Close the standalone settings window + +6) Choose **Development → Test Target → _Your Target_** from the menu bar to +select the target to test deployment to + +7) Click the **Test** button or choose **Development → Test** from the menu bar + +8) The standalone will be built and deployed to the target and launched. In +LiveCode Business Edition the remote debugger will detect any execution errors +and present them. + +> **Note:** iOS devices connected via USB are detected as test targets in +LiveCode Business Edition and apps will be installed on them, however, they will +not be automatically launched. + + diff --git a/Documentation/guides/Extending LiveCode.md b/Documentation/guides/Extending LiveCode.md index ff37181840..b413e9b77f 100644 --- a/Documentation/guides/Extending LiveCode.md +++ b/Documentation/guides/Extending LiveCode.md @@ -5,111 +5,121 @@ group: advanced ## Introduction -LiveCode 8.0 is the most exciting release in the history of the technology. It provides a -simple way to extend the functionality or control set of LiveCode. - -Our focus in LiveCode 8.0 is extensibility. You can now build and share widgets (custom -controls) and libraries that are treated by LiveCode as engine level elements. - -LiveCode 8.0 can be thought of as a version 7.0 with a new module allowing extensions to -be plugged into the engine. As a result, 8.0 should be as functional and stable as -LiveCode 7.0. - -This guide will take you through the process of installing and using these new widgets and -libraries and for the adventurous among you, provide a guide to building and sharing your -own extensions. +LiveCode has a simple way to extend the functionality or control set of +your app using separately compiled modules. This guide will take you +through the process of installing and using these new widgets and +libraries and for the adventurous among you, provide a guide to building +and sharing your own extensions. ## LiveCode Builder Extensions -To make it possible to create extensions and plug them into the LiveCode engine we've -created a new flavour of our language called ***LiveCode Builder***. LiveCode Builder -looks a lot like LiveCode Script so should feel familiar for any seasoned LiveCode -developer. There is lots of new syntax which exposes parts of the LiveCode engine that -were only previously available to those who were skilled c/c++ developers. +To make it possible to create extensions and plug them into the LiveCode +engine we've created a new flavor of our language called ***LiveCode +Builder***. LiveCode Builder looks a lot like LiveCode Script so should +feel familiar for any seasoned LiveCode developer. There is lots of new +syntax which exposes parts of the LiveCode engine that were only +previously available to those who were skilled c/c++ developers. To learn more about LiveCode Builder and creating extensions, read on. > *Warning:* It is important to stress right at the start that -***no aspect of LiveCode Builder should be considered final***. -***Every piece of syntax in LiveCode Builder is subject to change***. +> ***no aspect of LiveCode Builder should be considered final***. +> ***Every piece of syntax in LiveCode Builder is subject to change***. ### Creating LiveCode Builder Extensions -We have provided a new "Extension Builder" stack to help make development and packaging of -extensions as easy as possible. +The IDE provides an "Extension Builder" tool to help make development +and packaging of extensions as easy as possible. -> **Note:** LiveCode Builder is a different flavour of LiveCode so it is not possible to -edit LiveCode Builder scripts in the main LiveCode Script IDE. +> **Note:** LiveCode Builder is a different flavor of LiveCode so it is +> not possible to edit LiveCode Builder scripts in the main LiveCode +> Script IDE. ### Extension Builder Open the "Extension Builder" from the tools menu: -``` -Tools > Widget Builder -``` + Tools > Extension Builder -![enter image description here](images/extensions-plugin-overview.png) +![Extension Builder plugin](images/extensions-plugin-overview.png) -1. Select the extension you wish the develop or click the "open" icon in the header back to locate an extension you've not loaded before. All LiveCode authored widgets in the application package at: /contents/extensions/. To play with one of these extensions we recommend copying the folder from the application package to your desktop and loading it from there. Changing the extension id in the source code will also mean it doesn't conflict with the existing extension. +1. Shows the currently selected extension. 2. Data that the builder was able to parse from the directory such as icons, resources, API's the user guides. 3. Console: Shows status, error and log messages. 4. Test: Creates a stack, compiles the extensions and creates an instance. 5. Script: Opens the lcb script in an external default editor. -6. Insall: Installs the extension into the IDE +6. Install: Installs the extension into the IDE 7. Uninstall: Uninstalls the extension from the IDE 8. Package: Creates a .lce package which can uploaded to the extension store. It is placed in the extension directory -> **Note:** A great way to get started is to tweak the script of one of our widgets examples. -> +> **Note:** A great way to get started is to tweak the script of one of +> our widget examples. -### Create your Own Simple Widget -A widget and a library are identical, except that a widget draws to a canvas. As a result, -the authoring process is much the same for both extension types. +Using the selection dropdown (1), you can select the extension you wish +to develop or click the "open" icon in the header back to locate an +extension you've not loaded before. + +### Create your own simple widget +The main difference between widgets and libraries is that a widget draws +to a pre-existing canvas. Apart from that, the authoring process is much +the same for both extension types. #### Create a .lcb file -We recommend using the Atom text editor, available at https://atom.io/. A LiveCode package -is available which provides some colorization as well as indentation. -If you prefer to use TextWrangler, there is a colorising script [here](https://github.com/livecode/livecode/tree/develop/contrib/TextWrangler). +We recommend using the Atom text editor, available at https://atom.io/. +A LiveCode package is available which provides some colorization as well +as indentation. +If you prefer to use TextWrangler, there is a colorizing script +[here](https://github.com/livecode/livecode/tree/develop/contrib/TextWrangler). It should be placed in /Application Support/TextWrangler/Language Modules/ -Start by creating a plain text file in a new directory and save it to disk with the -extension "lcb": +Start by creating a plain text file in a new directory and save it to +disk with the extension "lcb": -``` -/Desktop/widgettest/main.lcb -``` + /Desktop/widgettest/main.lcb -> **Note:** The extension builder currently relies on there being only one ***.lcb*** file -in a given directory. +> **Note:** The extension builder currently relies on there being only +> one main module file in a given directory. #### Declare Type and Identifier -Start by declaring the type of extension, either "widget" or "library" followed by your -identifier (See "Select A Developer ID" below). -``` -widget community.livecode.beaumont.pinkCircle - ## Code for your widget -end widget -``` -This is the unique identifier by which your extension will be referred to by the LiveCode -Engine. - -#### Declare Meta Data -Next, provide meta data to help LiveCode display your product correctly in product and in -the online portal. - -``` -widget community.livecode.beaumont.pinkCircle - -metadata title is "My Pink Circle" -metadata author is "Benjamin Beaumont" -metadata version is "1.0.0" - -end widget -``` +Start by declaring the type of extension, either "widget" or "library" +followed by your identifier (See "Select A Developer ID" below). + + widget community.livecode.beaumont.pinkCircle + ## Code for your widget + end widget + +This is the unique identifier by which your extension will be referred +to by the LiveCode Engine. + +> **Note:** All LiveCode authored widgets are in the application package +> at /Tools/Extensions/. To play with one of these extensions we +> recommend copying the folder from the application package to your +> desktop and loading it from there. Changing the extension identifier +> in the source code will ensure it doesn't conflict with the existing +> extension. + +#### Declare Metadata +Next, provide metadata to help LiveCode display your widget correctly +in the IDE and in the online portal. + + widget community.livecode.beaumont.pinkCircle + + metadata title is "My Pink Circle" + metadata author is "Benjamin Beaumont" + metadata version is "1.0.0" + metadata platforms is "desktop,mobile" + + end widget + +> **Note:** If the module makes use of external code that is only +> available on specific Operating Systems or Platforms, use the "os" +> and/or "platforms" metadata keys. The values are the same as can be +> found in the LiveCode Documentation Format Reference. This data will +> also appear in the dictionary. #### Importing libraries -The LiveCode builder syntax is broken down into **modules**. There are 3 classes of module: +The LiveCode builder syntax is broken down into **modules**. There are 3 +classes of module: Type|Description ---|--- @@ -126,6 +136,7 @@ com.livecode.widget|Optional|Contains syntax specific to widget building such as com.livecode.engine|Optional|Contains syntax for all extension building such as "dispatch" and "log". com.livecode.arithmetic|Default|Contains syntax for basic mathematical operations. com.livecode.array|Default|Contains syntax for operations on arrays. +com.livecode.assert|Default|Contains syntax for making assertions about program state. com.livecode.binary|Default|Contains syntax for operations on binary data. com.livecode.bitwise|Default|Contains syntax for bitwise logical operators. com.livecode.byte|Default|Contains syntax for operations on byte chunks. @@ -134,10 +145,12 @@ com.livecode.codeunit|Default|Contains syntax for operations on codeunit chunks. com.livecode.date|Default|Contains syntax for accessing the date and time. com.livecode.file|Default|Contains syntax for file I/O operations. com.livecode.foreign|Default|Provides the type bindings for foreign types. +com.livecode.java|Default|Provides helper functions and types for interfacing with Java. com.livecode.list|Default|Contains syntax for operations on lists. com.livecode.logic|Default|Contains syntax for logical operators. -com.livecode.mathfoundation|Default|Contains syntax for foundational mathematical operations. com.livecode.math|Default|Contains syntax for mathematical operations. +com.livecode.mathfoundation|Default|Contains syntax for foundational mathematical operations. +com.livecode.objc|Default|Provides helper functions and types for interfacing with Objective-C. com.livecode.sort|Default|Contains syntax for sorting operations. com.livecode.stream|Default|Contains syntax for stream I/O operations. com.livecode.string|Default|Contains syntax for operations on strings. @@ -148,28 +161,26 @@ com.livecode.unittest|Default|Contains syntax for unit testing LiveCode Builder > **Warning!** Module names are subject to change. -The new LiveCode dictionary has a full list of all available syntax as well as the module -each belongs to. As a general rule we recommend importing all three optional module -whenever developing widgets. - -``` -widget community.livecode.beaumont.pinkCircle +The LiveCode dictionary has a full list of all available syntax as +well as the module each belongs to. As a general rule we recommend +importing all three optional modules whenever developing widgets. -use com.livecode.canvas -use com.livecode.widget -use com.livecode.engine + widget community.livecode.beaumont.pinkCircle -metadata title is "My Pink Circle" -metadata author is "Benjamin Beaumont" -metadata version is "1.0.0" + use com.livecode.canvas + use com.livecode.widget + use com.livecode.engine -end widget -``` + metadata title is "My Pink Circle" + metadata author is "Benjamin Beaumont" + metadata version is "1.0.0" + end widget #### Core Handlers -There are three core handlers that any widget developer should implement: +There are several core handlers that any widget developer should +implement: Handler|Description ------|------ @@ -179,187 +190,184 @@ OnGeometryChanged| The *OnGeometryChanged* message is sent when the control is c OnSave| The *OnSave* message is sent when your widget is about to be destroyed and enables the widget to save data set on the widget. OnLoad| The *OnLoad* message is sent when your widget is created and enables the widget to retrieve data saved on the widget. -For the most basic example, only the OnPaint() handler is required. +In the first instance we are going to create a widget with no settable +properties, just using the `OnPaint` handler. -``` -widget community.livecode.beaumont.pinkCircle + widget community.livecode.beaumont.pinkCircle -metadata title is "My Pink Circle" -metadata author is "Benjamin Beaumont" -metadata version is "1.0.0" + metadata title is "My Pink Circle" + metadata author is "Benjamin Beaumont" + metadata version is "1.0.0" -public handler OnPaint() - // Draw widget -end handler + public handler OnPaint() + // Draw widget + end handler + + end widget -end widget -``` #### Draw a Pink Circle -``` -widget community.livecode.beaumont.pinkCircle + widget community.livecode.beaumont.pinkCircle -metadata title is "My Pink Circle" -metadata author is "Benjamin Beaumont" -metadata version is "1.0.0" + metadata title is "My Pink Circle" + metadata author is "Benjamin Beaumont" + metadata version is "1.0.0" -use com.livecode.canvas + use com.livecode.canvas -public handler OnPaint() - // Create a path with a radius of half the width of the canvas - // Set the paint to a solid pink color - // Fill the path - variable tCirclePath as Path - put circle path centered at point [my width / 2, my height / 2] with radius (my width/2) into tCirclePath - set the paint of this canvas to solid paint with color [1, 0, 1] - fill tCirclePath on this canvas -end handler + public handler OnPaint() + // Create a path with a radius of half the width of the canvas + variable tCirclePath as Path + put circle path centered at point [my width / 2, my height / 2] with radius (my width/2) into tCirclePath + + // Set the paint that will be used to fill the circle to a solid + // pink color + set the paint of this canvas to solid paint with color [1, 0, 1] + + // Fill the path + fill tCirclePath on this canvas + end handler -end widget -``` + end widget #### Test the Code -Now open the extension builder stack as shown above and click on the load icon to load -your ***.lcb*** file into the builder. +Now open the extension builder stack as shown above and click on the +folder icon at the top right to load your ***.lcb*** file into the +builder. ![enter image description here](images/extensions-widget-first.png) -Click test. Your widget should be displayed on the new stack. If you can't see it, check -behind the extension stack. +Click test. Your widget should be displayed on the new stack. If you +can't see it, check behind the extension stack. #### Properties -In order to make a widget useful to end users it is likely that you'll want to expose -properties that allow them to specify how your widget should behave. - -To specify a property you must provide a name and the method to get and set the property. -``` -property get set -``` - -The simplest properties to get/set are numbers or strings. So lets create a circleMargin -property that allows users to define a margin. - -``` -property circleMargin get mMargin set setMargin -``` - -In the above example, when the ***circleMargin*** property is requested, the variable -"mMargin" is returned, when set, the handler "setMargin" is called. To have LiveCode -Builder handle the getting/setting of data, provide the variable name, to take full -control over the getting/setting process define handlers. In our case we're taking a mixed -approach. - -``` -private variable mMargin as Real -``` - -We'll define a member variable to store the value for the margin. LiveCode Builder is typed -so you must also specify the type of your variable. Remember, the canvas you are drawing -to has subpixel precision so our margin can be a decimal number. As a result, we've chosen -to specify our margin as a real number. For a full list of types available in LiveCode -Builder please see the [Typing](#Typing) section of the language specification guide below. -We also suggest a naming convention for variables in the section on [variable and case sensitivity](#Case-Sensitivity). - -We also need to insatiate our circleMargin to a default value. We do this by adding an -onCreate handler which is called when the widget is first created. - -``` -public handler setMargin(in pMargin as Real) - put pMargin into mMargin - redraw all -end handler -``` - -Finally we have to implement our setMargin handler. -``` -public handler onCreate() - put 0 into mMargin -end handler -``` - -Implementing the "setter" ourselves provides us with a little more flexibility. In this -case when the property is set we want our pink circle to immediately redraw to reflect the -property change. We do this by calling "redraw all". - -To test the property click "test" and from the message box set the property. - -``` -set the cicleMargin of widget 1 to 15 -``` +In order to make a widget useful to end users it is likely that you'll +want to expose properties that allow them to specify how your widget +should behave. -**Full Example** -``` -widget community.livecode.beaumont.pinkCircle +To specify a property you must provide a name and the method to get and +set the property. + + property get set + +The simplest properties to get/set are numbers or strings. So lets +create a `circleMargin` property that allows users to define a margin. -metadata title is "My Pink Circle" -metadata author is "Benjamin Beaumont" -metadata version is "1.0.0" + property circleMargin get mMargin set setMargin -use com.livecode.canvas -use com.livecode.widget -use com.livecode.engine +In the above example, when the **circleMargin** property is requested, +the variable `mMargin` is returned; when the property is set, the +handler **setMargin** is called. To have a property linked directly to +the value of a variable, simply provide the variable name. There will be +no other side effects - notably, a redraw will not automatically be +triggered in the case that a variable name is used for a setter. To +process the value coming from and going into LiveCode Script, or to add +side-effects when getting and setting properties, provide handler names. +In our case we're defining a setter for the **circleMargin** property +because we need to trigger a redraw when it is set. -// Properties -property circleMargin get mMargin set setMargin + private variable mMargin as Real -// Local variables -private variable mMargin as Real +We'll define a member variable to store the value for the margin. +LiveCode Builder is typed so you must also specify the type of your +variable. Remember, the canvas you are drawing to has subpixel precision +so our margin is a real number rather than an integer. For a full list +of types available in LiveCode Builder please see the Typing section of +the language specification guide. -public handler onCreate() - put 0 into mMargin -end handler +We also suggest a naming convention for variables in the section on +variable and case sensitivity. -public handler OnPaint() - // Create a path with a radius of half the width of the canvas - // Set the paint to a solid pink color - // Fill the path - variable tCirclePath as Path - put circle path centered at point [my width / 2, my height / 2] with radius ((my width - mMargin)/2) into tCirclePath - set the paint of this canvas to solid paint with color [1, 0, 1] - fill tCirclePath on this canvas -end handler +Finally we have to implement our `setMargin` handler. -public handler setMargin(in pMargin as Real) - put pMargin into mMargin - redraw all -end handler + public handler setMargin(in pMargin as Real) returns nothing + put pMargin into mMargin + redraw all + end handler + +Implementing the "setter" ourselves provides us with a little more +flexibility. In this case when the property is set we want our pink +circle to immediately redraw to reflect the property change. We do this +by calling "redraw all". + +To test the property click "test" and from the message box set the +property. + + set the cicleMargin of widget 1 to 15 + +**Full Example** + + widget community.livecode.beaumont.pinkCircle + + metadata title is "My Pink Circle" + metadata author is "Benjamin Beaumont" + metadata version is "1.0.0" + + use com.livecode.canvas + use com.livecode.widget + use com.livecode.engine + + // Properties + property circleMargin get mMargin set setMargin + + // Local variables + private variable mMargin as Real + + public handler onCreate() + put 0 into mMargin + end handler + + public handler OnPaint() + // Create a path with a radius of half the width of the canvas + variable tCirclePath as Path + put circle path centered at point [my width / 2, my height / 2] with radius (my width/2) into tCirclePath + + // Set the paint that will be used to fill the circle to a solid + // pink color + set the paint of this canvas to solid paint with color [1, 0, 1] + + // Fill the path + fill tCirclePath on this canvas + end handler + + public handler setMargin(in pMargin as Real) + put pMargin into mMargin + redraw all + end handler -end widget -``` + end widget #### Loading and Saving widget data -When your widget is created you are sent an *OnSave* message. It has the following structure -and expects and array return type. You can fill this array with whatever widget data you -have. LiveCode saves this data along with instances of the widget in the stack file. - -``` -public handler OnSave(out rProperties as Array) - put the empty array into rProperties +When a stack containing a widget is saved, the widget's *OnSave* +handler is called by the engine. The *OnSave* handler has an array out +parameter - you can fill this array with whatever widget data is needed +to reconstruct the widget. LiveCode saves this data along with instances +of the widget in the stack file. + + public handler OnSave(out rProperties as Array) + put the empty array into rProperties - put mMargin into rProperties["margin"] + put mMargin into rProperties["margin"] - return rProperties -end handler -``` + return rProperties + end handler -This same array will be returned to you when the widget is next opened. +This same array is passed as a parameter to an *OnLoad* handler which is +called when the stack the widget is on is loaded. -``` -public handler OnLoad(in pProperties as Array) - put pProperties["margin"] into mMargin -end handler -``` + public handler OnLoad(in pProperties as Array) + put pProperties["margin"] into mMargin + end handler #### Understanding Error Messages -Clicking on the "test" button causes the extension builder to compile your source code -file (***.lcb***) and produce a compiled module file (***.lcm***). If an error is -encountered it is output in the "console" section of the builder: +Clicking on the "test" button causes the extension builder to compile +your source code file (***.lcb***) and produce a compiled module file +(***.lcm***). If an error is encountered it is output in the "console" +section of the builder: -``` -Error: : : : -``` + Error: : : : * *source path* - The path the .lcb file that is being compiled * *line number* - The line number in the script on which the error occurred. @@ -377,125 +385,303 @@ stack in the IDE. 3. Choose the "LiveCode Builder" API 4. The list of all the syntax available -### Creating Libraries -A extension library is written in much the same way as the above widget. The only -difference is that all the public handlers implemented are loaded into the engine on -startup. +### Hello World library +A extension library is written in much the same way as the above widget. +The only difference is that all the public handlers implemented are +inserted into the message path when the extension is loaded. + +For example, here is a simple library with one handler which simply +returns the string "Hello World!": + + library community.livecode.elanorb.helloworld + + metadata title is "Hello World Library" + metadata author is "Elanor Buchanan" + metadata version is "1.0.0" + + public handler sayHello() + return "Hello World!" + end handler + + end library + +Once this is compiled and loaded, the sayHello handler would be in the +message path, before the backscripts. LiveCode Builder library handlers +can be invoked in both command and function form: + + sayHello + put the result -- outputs "Hello World!" + + put sayHello() -- outputs "Hello World!" ### Loading and Creating Widgets Manually -To load a compiled library file call: +To load a compiled module file call: -``` -load extension -``` + load extension To create a widget from script call: -``` -create widget as + create widget as e.g. -create widget "myWidget" as "com.livecode.extensions.waddingham.clock" -``` + create widget "myWidget" as "com.livecode.extensions.waddingham.clock" + +### Extensions Course + +See the online [extensions course](https://livecode.com/topic/introduction-2/) for a thorough +introduction to LiveCode Builder, complete with examples. The following +extension examples are worked through: +* Hello World library +* Extended Hello World library +* Rotated Text widget +* Extended Rotated Text widget +* Pie Chart widget +* Modifying the Line Graph widget + +### Canvas API + +If you are drawing to the widget canvas in the `OnPaint` handler (as +opposed to [wrapping native views](#using-native-views-for-widgets)) it +is a good idea to familiarise yourself with the canvas API. It provides +a set of operations for creating, measuring, transforming and drawing +paths and text. + +#### Using path objects + +Paths corresponding to standard shapes can be created using the various +path 'constructors': + +* Line: `line path from mFrom to mTo` +* Rectangle: `rectangle path of mRect` +* Circle: `circle path centered at mCenter with radius mRadius` +* Ellips: `ellipse path centered at mPoint with radii mRadii` +* Rounded Rectangle: `rounded rectangle path of mRect with (radius mRadius | radii mRadii )` +* Arc: `arc path centered at mCenter with [ radius mRadius | radii mRadii ] from mStartAngle to mEndAngle` +* Sector: `sector path centered at mCenter with [ radius mRadius | radii mRadii ] from mStartAngle to mEndAngle` +* Segment: `segment path centered at mCenter with [ radius mRadius | radii mRadii ] from mStartAngle to mEndAngle` +* List of points: `( polygon | polyline ) path with points mPoints` + +To create a path using the path operations, start with an empty path +object: + + // Create a new empty path + variable tPath as Path + put the empty path into tPath + +Then use the canvas path syntax to build the path. Simple paths with no +subpaths (i.e. ones you can draw without lifting the pencil), can be created using the following operations: + +* Line: `line to mPoint on mPath` +* Arc: `arc through mThrough to mTo with radius mRadius on mPath` +* Curve: `curve through mThroughA [ then mThroughB ] to mTo on mPath` +* Elliptic arc:`arc to mEnd with radii mRadii rotated by mAngle [ taking ( largest | smallest ) ( clockwise | anticlockwise ) route ] on mPath` +* Close path: `close path on mPath` + +Paths made up of disjoint subpaths (i.e. ones you need to lift the +pencil for) can be created using the move operation: + +* Move: `move to mPoint on mPath` + +For example, to create a path consisting of a pair of parallel lines: + + public handler OnPaint() + // Create a new empty path + variable tPath as Path + put the empty path into tPath + + // Begin a new subpath of tPath + move to point [50, 50] on tPath + + // Add a line to tPath + line to point [100, 50] on tPath + + // Begin a new subpath of tPath + move to point [50, 100] on tPath + + // Add a line to tPath + line to point [100, 100] on tPath + + stroke tPath on this canvas + end handler + +![Path with subpaths](images/extensions_canvas_parallel_lines.png) + +The following example illustrates how the parameters to elliptic arcs +work. Take the ellipse with horizontal radius 50 and vertical radius 25. +The red and green arcs start from the same point; the red is the +smallest clockwise route to a given point, the green is the largest +anticlockwise route. Together they make up the whole ellipse: + + public handler OnPaint() + variable tSmallest as Path + put the empty path into tSmallest + + // Start at [50, 50] + move to point [50, 50] on tSmallest + + // Continue path with an arc to 100, 25 + arc to point [100, 25] with radii [50, 25] rotated by 0 taking smallest clockwise route on tSmallest + + variable tLargest as Path + put the empty path into tLargest + + // Start at [50, 50] + move to point [50, 50] on tLargest + + // Continue path with an arc to 100, 25 + arc to point [100, 25] with radii [50, 25] rotated by 0 taking largest anticlockwise route on tLargest + + set the paint of this canvas to solid paint with color [255,0,0] + stroke tSmallest on this canvas + + set the paint of this canvas to solid paint with color [0,255,0] + stroke tLargest on this canvas + end handler + +![Elliptic arcs](images/extensions_canvas_elliptic_arc.png) + +Paths may also be created using SVG instructions, for example: + + public handler OnPaint() + variable tPath as Path + put path "M10,10 L50,100 Q100,100 100,50 C75,50 50,25 50,10z" into tPath + stroke tPath on this canvas + end handler + +Produces the following: + +![SVG path](images/extensions_canvas_svgpath.png) + +#### Rendering text + +There is essentially only one piece of syntax for rendering text: + + fill text mText at (mPoint | mAlignment of mRect) on mCanvas + +for example, a widget that simply displays its name at its center would +have the following `OnPaint` handler: + + public handler OnPaint() + fill text my name at center of my bounds on this canvas + end handler + +Text can be measured using the + + measure mText on mCanvas + +syntax. This can be used for example to do text wrapping, by calculating +the widths of successive chunks of text and inserting line breaks where +appropriate. + +#### Transformations + +Both Path objects and canvases can be transformed using the standard +affine transforms - either using the specific translate, rotate or scale +syntax, or arbitrary transform matrices. ### Composed Widgets -Widgets can either be 'host' widgets, as in the previous example, created when a widget -is directly embedded in a stack, or 'child' widgets which are created when a widget is -used as a child widget within another widget. -The syntax for composed widgets is included in the com.livecode.widget module. +Widgets can either be 'host' widgets, as in the previous example, +created when a widget is directly embedded in a stack, or 'child' +widgets which are created when a widget is used as a child widget +within another widget. +The syntax for composed widgets is included in the com.livecode.widget +module. #### A simple composed widget -This composed widget example composes the clock widget and the selector widget, to create -a version of the clock widget with adjustable time zone. -![enter image description here](images/extensions-widget-first.png) -The label at the top of the widget reflects which portion of the widget the mouse is over. +This composed widget example composes the clock widget and the selector +widget, to create a version of the clock widget with adjustable time +zone. +![enter image description here](images/extensions-composed.png) +The label at the top of the widget reflects which portion of the widget +the mouse is over. -``` -widget com.livecode.extensions.example.simplecomposed + widget com.livecode.extensions.example.simplecomposed -use com.livecode.canvas -use com.livecode.widget + use com.livecode.canvas + use com.livecode.widget -metadata title is "Simple Composed Widget" -metadata author is "LiveCode" -metadata version is "1.0.0" + metadata title is "Simple Composed Widget" + metadata author is "LiveCode" + metadata version is "1.0.0" -private variable mInsideChild as String -private variable mInside as Boolean + private variable mInsideChild as String + private variable mInside as Boolean -private variable mSelector as Widget -private variable mClock as Widget + private variable mSelector as Widget + private variable mClock as Widget -public handler OnCreate() - put false into mInside - put the empty string into mInsideChild + public handler OnCreate() + put false into mInside + put the empty string into mInsideChild - put a new widget "com.livecode.extensions.livecode.selector" into mSelector - set property "numSelections" of mSelector to 6 - set annotation "Name" of mSelector to "Selector" + put a new widget "com.livecode.extensions.livecode.selector" into mSelector + set property "numSelections" of mSelector to 6 + set annotation "Name" of mSelector to "Selector" - put a new widget "com.livecode.extensions.livecode.clock" into mClock - set annotation "Name" of mClock to "Clock" + put a new widget "com.livecode.extensions.livecode.clock" into mClock + set annotation "Name" of mClock to "Clock" - place mSelector - place mClock -end handler -``` -Notice that Widget is a variable type. This widget stores references to its child widgets -in private variables. In the `OnCreate` handler, the widget objects are created, stored -in the private variables and 'placed'. Child widgets can be stored as variables and -manipulated without actually being drawn to a canvas if they are unplaced. + place mSelector + place mClock + end handler + + end widget + +Notice that Widget is a variable type. This widget stores references to +its child widgets in private variables. In the `OnCreate` handler, the +widget objects are created, stored in the private variables and +'placed'. Child widgets can be stored as variables and +manipulated without actually being drawn to a canvas if they are +unplaced. Properties implemented by child widgets can be got and set using the `property of ` syntax. -Placing a widget ensures that they are drawn, in placement order. Setting an annotation of -a child widget assigns it a tag so that when an unknown child widget is returned by an -operator, its annotation can be used to identify it. - -``` -public handler OnMouseEnter() - put true into mInside - - if the target is not nothing then - put annotation "Name" of the target into mInsideChild - end if - - redraw all -end handler - -public handler OnMouseLeave() - if the target is not nothing then - put the empty string into mInsideChild - end if - - put false into mInside - - redraw all -end handler -``` - -In the *OnMouseEnter* and *OnMouseLeave* handlers, *the target* is used to obtain a -reference to the child widget that triggered the *OnMouseEnter* and *OnMouseLeave* events, -and the previously assigned annotation put into the `mInsideChild` variable, which in turn +Placing a widget ensures that they are drawn, in placement order. +Setting an annotation of a child widget assigns it a tag so that when an +unknown child widget is returned by an operator, its annotation can be +used to identify it. + + public handler OnMouseEnter() + put true into mInside + + if the target is not nothing then + put annotation "Name" of the target into mInsideChild + end if + + redraw all + end handler + + public handler OnMouseLeave() + if the target is not nothing then + put the empty string into mInsideChild + end if + + put false into mInside + + redraw all + end handler + +In the *OnMouseEnter* and *OnMouseLeave* handlers, *the target* is used +to obtain a reference to the child widget that triggered the +*OnMouseEnter* and *OnMouseLeave* events, and the previously assigned +annotation put into the `mInsideChild` variable, which in turn is rendered to the canvas in the *OnPaint* handler. -``` -public handler OnPaint() - set the paint of this canvas to solid paint with color [0.75, 0.75, 0.75] - fill rectangle path of my bounds on this canvas - - if mInside then - set the paint of this canvas to solid paint with color [1.0, 0.0, 0.0] - set the stroke width of this canvas to 4.0 - stroke rectangle path of my bounds on this canvas - end if - - if mInsideChild is not the empty string then - set the paint of this canvas to solid paint with color [0.0, 0.0, 0.0] - fill text mInsideChild at top of my bounds on this canvas - end if -end handler -``` + public handler OnPaint() + set the paint of this canvas to solid paint with color [0.75, 0.75, 0.75] + fill rectangle path of my bounds on this canvas + + if mInside then + set the paint of this canvas to solid paint with color [1.0, 0.0, 0.0] + set the stroke width of this canvas to 4.0 + stroke rectangle path of my bounds on this canvas + end if + + if mInsideChild is not the empty string then + set the paint of this canvas to solid paint with color [0.0, 0.0, 0.0] + fill text mInsideChild at top of my bounds on this canvas + end if + end handler The rectangle of each child widget is controlled using the following syntax: * ```the rectangle of ``` - Enables manipulation of the rectangle property of a child widget. @@ -503,27 +689,1287 @@ The rectangle of each child widget is controlled using the following syntax: * ```the height of ``` - Enables manipulation of the height property of a child widget. * ```the location of ``` - Enables manipulation of the location property of a child widget. -``` -public handler OnGeometryChanged() - set the rectangle of mSelector to rectangle [ 0, 20, my width, 50 ] - set the rectangle of mClock to rectangle [ 0, 50, my width, my height ] -end handler -``` - -Finally, messages posted by child widgets can be handled in the direct parent by handling -the appropriate message (prepending 'On'). For example, the selector widget posts -*optionChanged* when one of its numbers is selected. This is handled by this composed -widget example in an *OnOptionChanged* handler. - -``` -public handler OnOptionChanged(in pIndex) - set property "timeZone" of mClock to pIndex - 1 -end handler -``` + public handler OnGeometryChanged() + set the rectangle of mSelector to rectangle [ 0, 20, my width, 50 ] + set the rectangle of mClock to rectangle [ 0, 50, my width, my height ] + end handler + +Finally, messages posted by child widgets can be handled in the direct +parent by handling the appropriate message (prepending 'On'). For +example, the selector widget posts *optionChanged* when one of its +numbers is selected. This is handled by this composed widget example in +an *OnOptionChanged* handler. + + public handler OnOptionChanged(in pIndex) + set property "timeZone" of mClock to pIndex - 1 + end handler + +### Using native APIs for libraries + +One of the most powerful features of LiveCode Builder is the foreign +function interface (FFI). It can be used to access native APIs on all +supported platforms. + +The fundamental concept involved in using the FFI is the foreign handler +binding. This is a string containing information about the native +functionality that is being bound to. + +The format of the binding string varies slightly depending on the +language of the foreign handler - for a complete specification, see the +LiveCode Builder Language Reference. + +#### C + +In order to bind to C functions from a dynamic library, there is one +essential thing to know: the signature of the function. + +>**Note:** On Windows, it is also necessary to find out the calling +> convention of the function. In the majority of cases if binding to +> functions in the Windows API, the calling convention will be +> `stdcall`. + +The declared types of the foreign handler must match the signature, so +that the FFI call can be computed correctly. For example, to bind to the +`atof` C standard library function that converts a C-string to a double, + + double atof(const char *str) + +We could use: + + foreign handler C_AToF(in pString as ZStringNative) returns CDouble \ + binds to "atof" + +See the [Language Reference](https://github.com/livecode/livecode/blob/develop/docs/guides/LiveCode%20Builder%20Language%20Reference.md#the-c-binding-string) +for more information on C binding strings. + +##### Callbacks + +When used in the context of a foreign handler definition, a foreign +handler type will cause automatic bridging of the LCB handler to a C +function pointer which can be called directly by the native code. + +The function pointers created in this fashion have lifetime +equivalent to that of the calling context. In particular, for +widgets they will last as long as the widget does, for all other +module types they will last as long as the module is loaded. + +For example, suppose you have the following function in `myLib`: + +void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) + + void c_function_with_callback(void* p_context, bool(*func)(void* p_context)) + +This can be bound to using the following: + + public foreign handler type CallbackType(in pContext as Pointer) returns CBool + + foreign handler CFunctionWithCallback(in pContext as Pointer, in pHandler as CallbackType) returns nothing \ + binds to "myLib>c_function_with_callback" + + handler MyCallback(in pContext as Pointer) returns CBool + ... + + return true + end handler + + handler CallCFunctionWithCallback(in pContext as Pointer) + CFunctionWithCallback(pContext, MyCallback) + end handler + +##### Using compiled libraries + +Extensions can include compiled libraries on which they depend. The +libraries must be compiled for each platform and architecture they are +required on and placed folders named with a platform ID in the extension +code folder. The platform ID folder names are in the form: + + -[-] + +See the [platform ID](https://github.com/livecode/livecode/blob/develop/docs/development/platform-id.md) +specification for more details. + +###### Dynamic Linking + +On all platforms with the exception of iOS devices only dynamically linked +libraries are supported. Static linking is not yet supported in iOS simulator +builds. On iOS 8+ devices dynamically linked frameworks (`.framework`) are +supported. + +###### Static Code Libraries for iOS Device Builds + +Static libraries and frameworks for iOS must be compiled into a lcext object. +Use the [build-module-lcext-ios.sh shell script](https://github.com/livecode/livecode/blob/develop/tools/build-module-lcext-ios.sh) +as an example of how to do so. + +The script has the following inputs in order: + +- The path to the module compiled to C++ with using `lc-compile` with the +`--forcebuiltins --outputauxc OUTPUTFILE` options. The output file inclues both +the module and shims for any C foreign bindings. Use a `.cpp` extension so the +compiler treats the file correctly. +- The deps file which is a text file listing required dependencies when linking +the object where each line is in the form `{library | [weak-]framework} ` +- Lcext output file path (must use the lcext extesion). +- The full name of the module. For example, `com.livecode.library.timezone`. +- The output file path for the ios module. This should be named `module.lcm` and +be next to the lcext object in the code folder. This is a dummy module we include +in standalones that is just the name to be loaded as the actual module code is +already linked into the executable. +- one or more full paths to static libraries. If linking a static framework the +static library is located at `.framework/` + +###### Java and Android Libraries + +Libraries to load on android (`.jar` & `.aar`) may be placed in the code +folder `jvm-android`. + +Java libraries to load on all platforms supporting Java may be placed in the +code folder `jvm`. + +###### Example Directory Structure + + module.lcm + manifest.xml + api.lcdoc + library.lcb + resources/image.png + code/universal-mac/library.dylib + code/x86-win/library.dll + code/x86-linux/library.so + code/x86_64-linux/library.so + code/armv6-android/library.so + code/jvm-android/library.aar + code/jvm/library.jar + code/universal-ios-iphoneos11.4/library.lcext + code/universal-ios-iphoneos11.4/module.lcm + code/universal-ios-iphonesimulator11.4/library.dylib + +#### Java + +Java bindings are currently supported on Android, Mac and Linux. On +desktop platforms the IDE will attempt to find the correct setting for +the `JAVA_HOME` environment variable. As this can vary from distro to +distro on Linux, this may fail - in this case ensure you set `JAVA_HOME` +in script or using the message box. + +##### Java Platform API + +On any of the supported platforms, it is possible to bind to methods and +fields of classes in the Java Platform API. + +For example, take the [java.util.UUID class](https://docs.oracle.com/javase/7/docs/api/java/util/UUID.html) . +Here is a simple library which uses this class to return a new +pseudo-randomly generated UUID as a string: + + // The following comment block forms the top-level documentation of + // this library + /** + This library allows the creation of a UUID using the Java Platform + API. + */ + library com.livecode.library.javauuid + + metadata title is "Java UUID" + metadata author is "LiveCode" + metadata version is "1.0.0" + + // Bind to the static randomUUID() method of the java.util.UUID class + __safe foreign handler JNI_RandomUUID() returns JObject \ + binds to "java:java.util.UUID>randomUUID()Ljava/util/UUID;!static" + + // Bind to the toString() instance method of the java.util.UUID class + __safe foreign handler JNI_UUIDToString(in pUUID as JObject) returns JString \ + binds to "java:java.util.UUID>toString()Ljava/lang/String;" + + // Library public handler - this will be accessible from LiveCode + // when this library is loaded. The following comment block will + // be used to generate the documentation + /** + Returns a new random UUID. + + Returns (String): + The string representation of a type 4 (pseudo randomly generated) + UUID. + */ + public handler GetRandomUUIDJava() returns String + // Call the static randomUUID method to return an instance of + // the UUID class + variable tUUID as JObject + put JNI_RandomUUID() into tUUID + + // Call the toString method on the UUID instance to obtain the + // (java) string representation of the UUID + variable tUUIDString as JString + put JNI_UUIDToString(tUUID) into tUUIDString + + // Convert to a LiveCode String and return + return StringFromJString(tUUIDString) + end handler + + end library + +### Other binding examples + +* Binding to a class constructor with no parameters: + + __safe foreign handler CreateJavaObject() returns JObject binds to "java:java.lang.Object>new()" + +* Binding to a class constructor with parameters: + + __safe foreign handler CreateJavaString(in pBytes as JByteArray) returns JString binds to "java:java.lang.String>new([B)" + +* Binding to a class instance method + + __safe foreign handler JavaStringIsEmpty(in pString as JString) returns JBoolean binds to "java:java.lang.String>isEmpty()Z" + +* Binding to a class static method + + __safe foreign handler CallJavaAdd(in pLeft as JInt, in pRight as JInt) returns JInt binds to "java:java.lang.Math>addExact(JJ)J!static" + +* Binding to a class field + + __safe foreign handler JavaCalendarSetTime(in pCalendar as JObject, in pTime as JLong) returns nothing binds to "java:java.util.Calendar>set.time(J)" + __safe foreign handler JavaCalendarGetTime(in pCalendar as JObject) returns JLong binds to "java:java.util.Calendar>get.time()J" + +* Binding to a class constant + + __safe foreign handler GetJavaPi() returns JDouble binds to "java:java.lang.Math>get.PI()D!static" + +##### Android API + +On Android it is possible to access the standard platform APIs using +Java FFI. + +https://github.com/livecode/livecode/blob/develop/extensions/libraries/toast/toast.lcb + +##### Third-party libraries + +The standalone builder will look for .jar files in the `code/jvm` folder +of an extension package and load them automatically on startup of a +standalone. Due to the way things currently work, testing extensions +with jar files in the IDE is not supported. However it can be done by +setting the CLASSPATH environment variable before the Java Virtual +Machine is initialized. See [Custom Java classes](#custom-java-classes) +for an example of how to do this. + +For android, the possibilities for including third-party libraries +expands substantially. The `code/jvm-android` folder of an extension +package can contain .jar and .aar files, and obviously the .jar files +can make use of the Android API. + +Classes in .jar files (either included directly, or within .aar +packages) can be accessed using Java FFI in exactly the same way as +classes in the Android API. + +.aar packages can also contain resources and AndroidManifest.xml files - +these are merged with the manifest and resources generated by LiveCode +when building an Android application. + +##### Custom Java classes + +As .jar file code resources are supported, you can write and compile +custom Java classes for use with an LCB extension. + +Assuming the current folder is the root of an extension, consider the +following java code, in a file +java/com/livecode/library/helloworldjava/HelloWorld.java: + + package com.livecode.library.helloworldjava; + + public class HelloWorld + { + public static String sayHello() + { + return "Hello World!" + } + } + +This can be compiled and packaged using java command-line tools: + + javac java/com/livecode/library/helloworldjava/HelloWorld.java + jar cvf code/jvm/HelloWorld.jar -C java . + +Now there should be a HelloWorld.jar file in the appropriate location +relative to the extension. + +In helloworld.lcb, + + library com.livecode.library.helloworldjava + + use com.livecode.foreign + use com.livecode.java + + __safe foreign handler JNI_SayHello() returns JString \ + binds to "java:com.livecode.library.helloworldjava.HelloWorld>sayHello()Ljava/lang/String;" + + public handler SayHello() returns String + return StringFromJString(JNI_SayHello()) + end handler + + end library + +A standalone including this extension would be able to execute the +script + + answer SayHello() + +to pop up an answer dialog with the text "Hello World!". Obviously that +is a rather circuitous route when you can already do + + answer "Hello World!" + +but it does open up a lot of possibilities for interoperation with Java +libraries. + +One such application would be the ability to record .wav files on +Android. The MediaPlayer class does not come equipped with this +functionality. + +This can be compiled and packaged using java command-line tools, +ensuring the appropriate android.jar is included in the dependencies +(here we assume the location of the android toolchain is standard and +the android-23 platform is downloaded): + + javac -cp ~/android/toolchain/android-sdk/platforms/android-23/android.jar java/src/com/livecode/library/androidwavrecorder/ExtAudioRecorder.java + + jar cvf code/jvm-android/AndroidWavRecorder.jar -C java/src . + +Now there should be a AndroiWavRecorder.jar file in the appropriate +location relative to the extension. + +#### Objective-C + +The types used in Objective-C foreign handler declarations are the usual +C types, plus a few special ones for handling Obj-C `id` objects. These +are: + +* `ObjcId` - an id with no implicit action on its reference count +* `ObjcRetainedId` - an id which is expected to already have been retained. (i.e. the caller or callee expects to receive it with +1 ref count) +* `ObjcAutoreleasedId` - an id which has been placed in the innermost autorelease pool before being returned to the caller + +The `ObjcObject` type is a wrapper round the raw `ObjcId` types, which +manages the lifetime of the obj-c object it contains. It should +generally be used when using obj-c objects within LCB. + +Objective-C binding strings mirror as closely as possible the structure +of method declarations in Objective-C. For example, the class +`NSSpeechSynthesizer` has methods + + - (id)initWithVoice:(NSString *)voice; + - (BOOL)startSpeakingString:(NSString *)string; + +In order to create an instance of the class, we first use the superclass +`NSObject`'s + + + (id)alloc; + +method to allocate an instance, and then call `initWithVoice:` on it: + + foreign handler Objc_NSSpeechSynthesizerAlloc() returns ObjcRetainedId \ + binds to "objc:NSSpeechSynthesizer.+alloc" + +The `+` indicates this is a class method, i.e. we don't require an +instance of the class to call the method. + + foreign handler Objc_NSSpeechSynthesizerInitWithVoice(in pSynthesizer as ObjcRetainedId, in pVoice as optional ObjcId) returns optional ObjcRetainedId \ + binds to "objc:NSSpeechSynthesizer.-initWithVoice:" + +The `-` here indicates this is an instance method, i.e. we require an +instance of the class to call the method. This is always the first +parameter. We can then create and initialize an NSSpeechSynthesizer +using the following. We pass `nothing` to `initWithVoice:` to use the +default voice. + + handler CreateSpeechSynthesizer() returns ObjcObject + variable tSynthesizer as ObjcObject + put Objc_NSSpeechSynthesizerAlloc() into tSynthesizer + + return Objc_NSSpeechSynthesizerInitWithVoice(tSynthesizer, \ + nothing) + end handler + +To speak, we would bind to the `startSpeakingString:` method: + + foreign handler Objc_NSSpeechSynthesizerStartSpeaking(in pSynthesizer as ObjcId, in pString as ObjcId) returns CBool \ + binds to "objc:NSSpeechSynthesizer.-startSpeakingString:" + +Then expose a public library handler to enable calls from LiveCode. + + private variable mSynthesizer as optional ObjcObject + public handler SynthesizeSpeech(in pString as String) returns Boolean + if mSynthesizer is nothing then + put CreateSpeechSynthesizer() into mSynthesizer + end if + + Objc_NSSpeechSynthesizerStartSpeaking(mSynthesizer, \ + StringToNSString(pString)) + end handler + +##### Callbacks + +Callbacks are usually handled by creating delegates. A class delegate +handles the events associated with that class and marshalls the +callback message. + +Objective-C delegate objects with LCB implementations of protocol +methods can be created using the `CreateObjcDelegate` and +`CreateObjcInformalDelegate` handlers, provided by the com.livecode.objc +module. + +In order to create a delegate to handle a particular protocol method, +pass in the protocol name as the first argument and the mapping from +method names to LCB handlers as the second argument. For example, to +create a selectionChanged message for an `NSTextView`, we need to create +a handler + + private handler DidChangeSelection(in pNotification as ObjcObject) returns nothing + post "selectionChanged" + end handler + +and create a `NSTextViewDelegate`: + + variable tDelegate as optional ObjcObject + put CreateObjcDelegate( \ + "NSTextViewDelegate", \ + {"textViewDidChangeSelection:": DidChangeSelection}, \ + ) into tDelegate + if tDelegate is not nothing then + put tDelegate into mTextViewDelegate + end if + +Optionally, a context parameter can be passed in at delegate creation +time: + + put CreateObjcDelegateWithContext( \ + "NSTextViewDelegate", \ + {"textViewDidChangeSelection:": DidChangeSelectionContext}, \ + tContext) into tDelegate + + if tDelegate is not nothing then + put tDelegate into mTextViewDelegate + end if + +In this case the context variable will be passed as first argument of +the corresponding LCB callback: + + private handler DidChangeSelectionContext(in pContext, in pNotification as ObjcObject) returns nothing + post "selectionChanged" with [pContext] + end handler + +Some protocols consist of purely optional methods. In this case the +information about the protocol's methods are not available from the +objective-c runtime API. For this eventuality there are also handlers +`CreateObjcInformalDelegate` and `CreateObjcInformalDelegateWithContext`. + +These handlers take a list of foreign handlers as their first argument +instead of a protocol name. The foreign handlers' information is used to +resolve incoming selectors so that the desired LCB callback is called. +For example the `NSSoundDelegate` protocol has only one method, and it +is optional, + + - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)aBool; + +So in order to create an `NSSoundDelegate`, we need to create a list of +foreign handlers, in this case just the following: + + foreign handler NSSoundDidFinishPlaying(in pSound as ObjcId, in pDidFinish as CSChar) binds to "objc:.-sound:didFinishPlaying:" + +and create the informal delegate + + handler DidSoundFinish(in pSound as ObjcId, in pDidFinish as Boolean) returns nothing + if pDidFinish then + post "soundFinished" + end if + end handler + + foreign handler Objc_SetSoundDelegate(in pSound as ObjcId, in pDelegate as ObjcId) returns nothing \ + binds to "objc:NSSound.-setDelegate:" + ... + + variable tDelegate as optional ObjcObject + put CreateObjcInformalDelegate( \ + [NSSoundDidFinishPlaying], \ + {"textViewDidChangeSelection:": DidChangeSelection}) \ + into tDelegate + end if + if tDelegate is not nothing then + put tDelegate into mSoundDelegate + Objc_SetSoundDelegate(tSound, tDelegate) + end if + +> *Note:* Delegate properties are usually 'assigned' rather than +> 'retained', so it is necessary to store them in module variables +> until they are no longer needed. Generally the pattern required is +> as follows: + + handler OnOpen() + -- Create native view and set native layer + -- Set native view delegate property + -- Store view and delegate in module vars + end handler + + handler OnClose() + -- Set native view delegate property to nothing + -- Put nothing into view and delegate module vars + -- Set native layer to nothing + end handler + +For our speech synthesizer example, suppose we want to post a message +when the speaking is finished. In NSSpeechSynthesizer.h, we can see the +definition of the `NSSpeechSynthesizerDelegate`: + + @protocol NSSpeechSynthesizerDelegate + @optional + - (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking; + ... + +The first thing to note is that the protocol methods are all optional. +This means that we have to use an informal delegate. To attach an LCB +handler to the didFinishSpeaking event, we need to define both the +foreign handler that binds to the protocol method and the LCB handler +that should be called. Again this is an instance method of the delegate +class, so the first parameter will be the delegate itself. + +Again since the protocol method is optional, it will not be found if we +bind to +`NSSpeechSynthesizerDelegate.-speechSynthesizer:didFinishSpeaking:`, so +it is necessary to use dynamic binding for the foreign handler (i.e. +simply omitting the class in the binding string): + + foreign handler Objc_SpeechSynthesizerDidFinishSpeaking(in pSynthesizerDelegate as ObjcId, in pSynthesizer as ObjcId, in pFinished as CBool) returns nothing \ + binds to "objc:.-speechSynthesizer:didFinishSpeaking:" + + handler OnDidFinishSpeaking(in pSynthesizerDelegate as ObjcId, in pSynthesizer as ObjcId, in pFinished as CBool) returns nothing + post "finishedSpeaking" + end handler + + foreign handler Objc_SpeechSynthesizerSetDelegate(in pSynthesizer as ObjcId, in pDelegate as ObjcId) returns nothing \ + binds to "objc:NSSpeechSynthesizer.-setDelegate:" + + handler SetSpeechSynthesizerDelegate() + variable tDelegate as ObjcObject + put CreateObjcInformalDelegate( \ + [Objc_SpeechSynthesizerDidFinishSpeaking], \ + { "speechSynthesizer:didFinishSpeaking:": \ + OnDidFinishSpeaking }) into tDelegate + + Objc_SpeechSynthesizerSetDelegate(mSynthesizer, tDelegate) + end handler + +### Using native views for widgets + +The key piece of syntax for creating widgets that hook into native view +objects is `my native layer`: + + set my native layer to tView + +The `tView` object is different on each platform, as is the method of +specifying LCB handlers for native view event callbacks. We will use the +example of a native button on each platform to illustrate this, where +possible. + +The native layer should be created and destroyed every time the card +the widget is on is opened and closed respectively. Therefore the +pattern that should be adopted when writing a native widget is to use +the `OnOpen` and `OnClose` messages as follows: + + private variable mNativeLayer as optional Pointer + handler OnOpen() + put CreateNativeLayer() into mNativeLayer + set my native layer to mNativeLayer + end handler + + handler OnClose() + set my native layer to nothing + put nothing into mNativeLayer + end handler + +When using a native layer, a widget's `OnPaint` handler is not called. +However it is recommended to provide some sort of placeholder `OnPaint` +method to represent the widget when the native layer is not supported +on the current platform. + +#### Android + +##### Native view + +Native views on Android are classes derived from android.view.View. +The Android button widget's native layer is an instance of the +`android.widget.Button` class: + + ↳ android.view.View + ↳ android.widget.TextView + ↳ android.widget.Button + +The following snippet shows how to bind to the button constructor and +set the native layer: + + // Bind to Android engine methods in order to fetch the application + // Context + __safe foreign handler _JNI_GetAndroidEngine() returns JObject \ + binds to "java:com.runrev.android.Engine>getEngine()Lcom/runrev/android/Engine;!static" + __safe foreign handler _JNI_GetEngineContext(in pEngine as JObject) returns JObject \ + binds to "java:android.view.View>getContext()Landroid/content/Context;" + + // Bind to the android.widget.Button constructor + __safe foreign handler _JNI_ButtonNew(in pContext as JObject) returns JObject \ + binds to "java:android.widget.Button>new(Landroid/content/Context;)?ui" + + // Store a reference to the native view + private variable mNativeView as optional JObject + + handler CreateNativeLayer() returns Pointer + // Fetch the application Context + variable tContext as JObject + put _JNI_GetEngineContext(_JNI_GetAndroidEngine()) into tContext + + // Create an instance of the android.widget.Button class + put _JNI_ButtonNew(tContext) into mNativeView + + return PointerFromJObject(mNativeView) + end handler + + handler SetNativeLayer() + set my native layer to CreateNativeLayer() + end handler + +View objects on Android always require the application Context in their +constructors. + +View objects should always be created on the UI thread. + +##### Event handlers + +A button widget is obviously not complete without an action callback. We +want a message to be received by the widget object in LiveCode whenever +the native view is clicked. + +On Android, the general procedure is to attach a `Listener` to an +object. In Java, `Listener`s are classes which implement a specified set +of callback methods defined in that listener's interface. The general +method of defining [interface callbacks on Android](#interface-proxy-callbacks) +is used to create listeners with LCB handler callbacks. + +The following snippet shows how to attach an `OnClickListener` to the +Button instance: + + // Define handler type for button click callback. This matches + // the android.view.View.OnClickListener's + // abstract void onClick(View v) + // method. + handler type ClickCallback(in pView as JObject) returns nothing + + // Bind to the interface proxy method. Since there is only one + // method to be implemented for the OnClickListener interface, + // we just pass in a handler of the appropriate type. + __safe foreign handler _JNI_OnClickListener(in pHandler as ClickCallback) returns JObject \ + binds to "java:android.view.View$OnClickListener>interface()" + + // Bind to the method used to set the OnClickListener on the + // Button object. + __safe foreign handler _JNI_SetOnClickListener(in pButton as JObject, in pListener as JObject) returns nothing \ + binds to "java:android.view.View>setOnClickListener(Landroid/view/View$OnClickListener;)V?ui" + + // Actual handler (of type ClickCallback) that will be called + // when the button is clicked + handler OnButtonClick(in pView as JObject) returns nothing + // The widget object in LiveCode will receive the posted message + post "mouseUp" + + // Ensure the engine thread is notified of a pending event + MCEngineRunloopBreakWait() + end handler + + // Store the OnClickListener object in a private variable + private variable mOnClickListener as optional JObject + + // Set the OnClickListener + handler SetOnClickListener(in pButton as JObject) returns nothing + // Pass the OnButtonClick handler in the call to create a + // listener + put _JNI_OnClickListener(OnButtonClick) into mOnClickListener + + // Set the OnClickListener on a Button instance + _JNI_SetOnClickListener(pButton, mOnClickListener) + end handler + +Sometimes listener interfaces have multiple callback methods, for +different events. In this case, you must pass an array mapping callback +method names to handlers so that the correct handler is called for each +event. This can also be done with single-method interfaces, and indeed +is the recommended style to use as it will continue to work even if +additional callback methods are added to the interface in subsequent +API levels. + +Switching to this style would require two small tweaks to the above code: + + // Bind to the interface proxy method. + __safe foreign handler _JNI_OnClickListener(in pMapping as Array) returns JObject \ + binds to "java:android.view.View$OnClickListener>interface()" + + ... + + // Set the OnClickListener + handler SetOnClickListener(in pButtonView as JObject) returns nothing + // Map the OnButtonClick handler to the onClick method + put _JNI_OnClickListener({"onClick":OnButtonClick}) \ + into mOnClickListener + + // Set the OnClickListener on a Button instance + _JNI_SetOnClickListener(pButtonView, mOnClickListener) + end handler + +##### Hooking up properties + +Properties of Android native views can be set using methods of the view +(or one of its parent classes). For example, to hook up the enabled +property of the button, we bind to the `setEnabled` method of the parent +`TextView` class: + + __safe foreign handler _JNI_SetTextViewEnabled(in pView as JObject, in pValue as JBoolean) returns nothing \ + binds to "java:android.view.View>setEnabled(Z)V?ui" + + handler SetEnabled(in pButtonView as Pointer) + _JNI_SetTextViewEnabled(pButtonView, my enabled) + end handler + +#### iOS + +##### Native view + +Native views on iOS are classes derived from UIView. The iOS button +widget's native layer is an instance of the +`UIButton` class. + +The following snippet shows how to bind to the button constructor and +set the native layer: + + // Define an alias for CULong + private type NSUInteger is CULong + + // Bind to the UIButton class method buttonWithType: + private foreign handler ObjC_UIButtonButtonWithType(in pType as NSUInteger) returns ObjcId binds to "objc:UIButton.+buttonWithType:?ui" + + // For a standard push button we need the type to be + // UIButtonTypeSystem, which is 1 + constant UIButtonTypeSystem is 1 + + // Store a reference to the native view + private variable mNativeView as optional ObjcObject + unsafe handler CreateNativeLayer() returns Pointer + // Create an instance of the UIButton class + variable tButtonInstance as ObjcObject + put ObjC_UIButtonButtonWithType(UIButtonTypeSystem) \ + into mNativeView + + // Return the pointer + return PointerFromObjcObject(mNativeView) + end handler + + handler SetNativeLayer() + set my native layer to CreateNativeLayer() + end handler + +##### Event handlers + +Views on iOS relay information about user interactions using either the +[target-action paradigm](https://developer.apple.com/library/content/documentation/General/Conceptual/Devpedia-CocoaApp/TargetAction.html) +or [delegation](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html) + +In general, simple widgets will use the target-action paradigm. In +general, refer to the documentation for the particular class you are +wrapping. According to the `UIButton` [API](https://developer.apple.com/documentation/uikit/uibutton), in the +section 'Responding to Button Taps', the `UIButton` class uses the +target-action paradigm. + +So, we can post a message to the widget script object in response to +the click action as follows: + + // Bind to the UIButton addTarget:action:forControlEvents: method + private foreign handler ObjC_UIButtonAddTargetActionForControlEvents(in pObj as ObjcId, in pTarget as ObjcId, in pAction as UIntPtr, in pControlEvents as NSUInteger) returns nothing binds to "objc:UIButton.-addTarget:action:forControlEvents:?ui" + + // Actual handler that will be called when the button is clicked + handler OnButtonClick(in pSender as ObjcObject, in pContext as optional any) returns nothing + // The widget object in LiveCode will receive the posted message + post "mouseUp" + + // Ensure the engine thread is notified of a pending event + MCEngineRunloopBreakWait() + end handler + + // Store the action proxy object in a private variable + private variable mButtonProxy as optional ObjcObject + + // The push button action type is UIControlEventTouchUpInside, + // which is 1 << 6. Constants cannot be evaluated expressions, so + // just define the bit shift + constant UIControlEventTouchUpInsideBit is 6 + + // Add the target action + unsafe handler AddTargetAction(in pButtonView as ObjcObject) returns nothing + // Create a proxy for the button object. This will receive the + // button events and call the provided callback handler + put ObjcProxyGetTarget(OnButtonClick, nothing) into mButtonProxy + + // Add the target-action to the button view + ObjC_UIButtonAddTargetActionForControlEvents(pButtonView, \ + mButtonProxy, ObjcProxyGetAction(), \ + 1 shifted left by UIControlEventTouchUpInsideBit bitwise) + end handler + +More complex views on iOS require creation of delegates. For example, +there are several different user interactions possible with then +`UITextField` view. In order to handle these interactions, we create +a `UITextFieldDelegate` - see the [API](https://developer.apple.com/documentation/uikit/uitextfielddelegate?language=objc) +for the list of events that can be handled. + +In this example we hook up `openField` and `textChanged` messages: + + // Bind to the text field's delegate property setter + private foriegn handler Objc_SetTextFieldDelegate(in pTextField as ObjcId, in pDelegate as ObjcId) returns nothing \ + binds to "objc:UITextField.-setDelegate:?ui" + + // Handler to be called when the field is opened + handler OnOpenField(in pField as ObjcId) returns nothing + // The widget object in LiveCode will receive the posted message + post "openField" + + // Ensure the engine thread is notified of a pending event + MCEngineRunloopBreakWait() + end handler + + // Define the NSRange type, one of the parameters in the + // textFieldShouldChangeCharactersInRange method + public foreign type NSRange binds to "MCAggregateTypeInfo:ff" + + // Handler to be called when the field text is changed + handler OnTextChanged(in pField as ObjcId, in pRange as NSRange, in pReplacement as ObjcId) returns CBool + // The widget object in LiveCode will receive the posted message + post "textChanged" + + // Ensure the engine thread is notified of a pending event + MCEngineRunloopBreakWait() + + // Allow the text to be changed + return true + end handler + + // Store the delegate in a private variable + private variable mTextFieldDelegate as optional ObjcObject + + // Set the delegate + unsafe handler SetTextFieldDelegate(in pTextFieldView as ObjcObject) returns nothing + // Create a delegate mapping the textFieldDidBeginEditing: + // method to OnOpenField, and the + // textFieldShouldChangeCharactersInRange: method to + // OnTextChanged + + // First define the mapping + variable tMapping as Array + put { "textFieldDidBeginEditing:": OnOpenField, \ + "textField:shouldChangeCharactersInRange:replacementString:": \ + OnTextChanged } into tMapping + + put CreateObjcDelegate("UITextFieldDelegate", tMapping) \ + into mTextFieldDelegate + + Objc_TextFieldSetDelegate(pTextFieldView, mTextFieldDelegate) + end handler + +##### Hooking up properties + +Properties of iOS native views can be set using methods of the view (or +one of its parent classes). For example, to hook up the enabled +property: + + foreign handler ObjC_UIButtonSetEnabled(in pObj as ObjcId, in pEnabled as CBool) returns nothing \ + binds to "objc:UIButton.-setEnabled:?ui" + + handler SetEnabled(in pButtonView as Pointer) + ObjC_UIButtonSetEnabled(pButtonView, my enabled) + end handler + +#### Mac + +Native views on Mac are classes derived from NSView. The Mac button +widget's native layer is an instance of the +`NSButton` class. + +The following snippet shows how to bind to the button constructor and +set the native layer: + + // Define an alias for CULong + private type NSUInteger is CULong + + // Bind to the NSButton class method to allocate a new NSButton + private foreign handler ObjC_NSButtonAlloc() returns ObjcRetainedId binds to "objc:NSButton.+alloc" + + // Bind to the NSButton instance method to initialize an NSButton + private foreign handler ObjC_NSButtonInit(in pObj as ObjcId) returns ObjcId binds to "objc:NSButton.-init" + + // Bind to NSButton instance methods setButtonType:, setBezelStyle:, + // and -setBordered: + private foreign handler ObjC_NSButtonSetButtonType(in pObj as ObjcId, in pStyle as NSUInteger) returns nothing binds to "objc:NSButton.-setButtonType:" + private foreign handler ObjC_NSButtonSetBezelStyle(in pObj as ObjcId, in pStyle as NSUInteger) returns nothing binds to "objc:NSButton.-setBezelStyle:" + private foreign handler ObjC_NSButtonSetBordered(in pObj as ObjcId, in pBordered as CBool) returns nothing binds to "objc:NSButton.-setBordered:" + + // For a standard push button we need: + // buttonType to be NSMomentaryPushInButton = 7 + // bezelStyle to be NSRoundedBezelStyle = 1 + constant kNSMomentaryPushInButton is 7 + constant kNSRoundedBezelStyle is 1 + + // Store a reference to the native view + private variable mNativeView as optional ObjcObject + + unsafe handler CreateNativeLayer() returns Pointer + // Create an instance of the NSButton class + variable tButtonInstance as ObjcObject + put ObjC_NSButtonInit(ObjC_NSButtonAlloc()) into mNativeView + + // Set the properties we need for a push button + ObjC_NSButtonSetButtonType(mNativeView, kNSMomentaryPushInButton) + ObjC_NSButtonSetBezelStyle(mNativeView, kNSRoundedBezelStyle) + ObjC_NSButtonSetBordered(mNativeView, true) + + // Return the pointer + return PointerFromObjcObject(mNativeView) + end handler + + handler SetNativeLayer() + set my native layer to CreateNativeLayer() + end handler + +Views on Mac relay information about user interactions using either the +[target-action paradigm](https://developer.apple.com/library/content/documentation/General/Conceptual/Devpedia-CocoaApp/TargetAction.html) +or [delegation](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html) + +In general, simple widgets will use the target-action paradigm. In +general, refer to the documentation for the particular class you are +wrapping. The `NSButton` uses the target-action paradigm. + +So, we can post a message to the widget script object in response to +the click action as follows: + + + private foreign handler ObjC_NSButtonSetTarget(in pObj as ObjcId, in pTarget as ObjcId) returns nothing binds to "objc:NSButton.-setTarget:" + private foreign handler ObjC_NSButtonSetAction(in pObj as ObjcId, in pAction as UIntPtr) returns nothing binds to "objc:NSButton.-setAction:" + + // Actual handler that will be called when the button is clicked + handler OnButtonClick(in pSender as ObjcObject, in pContext as optional any) returns nothing + // The widget object in LiveCode will receive the posted message + post "mouseUp" + + // Ensure the engine thread is notified of a pending event + MCEngineRunloopBreakWait() + end handler + + // Store the action proxy object in a private variable + private variable mButtonProxy as optional ObjcObject + + // Add the target action + unsafe handler AddTargetAction(in pButtonView as ObjcObject) returns nothing + put ObjcProxyGetTarget(OnButtonClick, nothing) \ + into mButtonProxy + ObjC_NSButtonSetTarget(pButtonView, mButtonProxy) + ObjC_NSButtonSetAction(pButtonView, ObjcProxyGetAction()) + end handler + +More complex views on Mac require creation of delegates. See the +discussion of delegates on iOS for more information. + +##### Hooking up properties + +Properties of Mac native views can be set using methods of the view (or +one of its parent classes). For example, to hook up the enabled +property: + + foreign handler ObjC_NSButtonSetEnabled(in pObj as ObjcId, in pEnabled as CBool) returns nothing \ + binds to "objc:NSButton.-setEnabled:" + + handler SetEnabled(in pButtonView as Pointer) + ObjC_NSButtonSetEnabled(pButtonView, my enabled) + end handler + +#### Windows + +> **Important:** It is not yet possible to write a fully functional +> native widget on Windows, as there is no method to capture events on +> the native view and pass them back to LiveCode Builder. This will be +> addressed in future releases. + +##### Native view + +Native views on Windows are HWNDs. The `CreateWindowEx` function is used +to create HWNDs with specified properties. See the +[API documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85%29.aspx) +for details on the parameters taken by `CreateWindowEx`. + +The following snippet shows how to bind to `CreateWindowEx`, and use it +to set the native layer to a button HWND: + + // Alias the types used in native calls + public type DWORD is CULong + public type WIDESTRING is ZStringUTF16 + public type HINSTANCE is Pointer + public type HMENU is Pointer + public type HWND is Pointer + + // Bind to the CreateWindowEx function. It is defined in the + // user32.dll library (hence `user32>` in the binding string). + // The CreateWindowEx function definition is preceded by the WINAPI + // macro, which means it uses the stdcall calling convention (hence + // `!stdcall` in the binding string) + foreign handler CreateWindow(in pEx as DWORD, \ + in pString as WIDESTRING, in pLabel as WIDESTRING, \ + in pStyle as DWORD, in pX as CInt, in pY as CInt, \ + in pWidth as CInt, in pHeight as CInt, in pParent as HWND, \ + in pMenu as optional HMENU, in pInstance as optional HINSTANCE, \ + in pParam as optional Pointer) \ + returns HWND binds to "user32>CreateWindowExW!stdcall" + + private variable mNativeView as optional Pointer + + // Constants for the CreateWindow style parameter. We construct the + // DWORD by taking the bitwise or of the styles that aree + // appropriate. + + // BS_DEFPUSHBUTTON is the push button style constant + constant BS_DEFPUSHBUTTON is 1 + + // WS_CHILD is the child window style constant. If this is not used + // then `CreateWindowEx` creates a new main window. + constant WS_CHILD is 1073807361 + + // CreateWindowEx requires the parent view pointer to be passed in + unsafe handler CreateNativeView(in pParentView as Pointer) + // Compute the style DWORD + variable tStyle as DWORD + put WS_CHILD bitwise or BS_DEFPUSHBUTTON into tStyle + + // Pass in the predefined BUTTON window class + variable tWindowClass as String + put "BUTTON" into tWindowClass + + // Call CreateWindow, with empty/default values for all other + // parameters + put CreateWindow(0, tWindowClass, "", tStyle, 0, 0, 0, 0, \ + pParentView, nothing, nothing, nothing) \ + into mNativeView + + return mNativeView + end handler + + unsafe handler SetNativeLayer() + // Get the parent view pointer + variable tParentView as Pointer + MCWidgetGetMyStackNativeView(tParentView) + + set my native layer to CreateNativeLayer(tParentView) + end handler + + +##### Event handlers + +As the general callback method has not yet been implemented on Windows, +unfortunately widgets that require user interaction are not yet +possible. However, native widgets can be written that have only +properties and no user interaction, such as a progress indicator or +label field. + +##### Hooking up properties + +Properties of Windows native views can be set using functions in the +user32 dll. For example, to hook up the enabled property of a Windows button: + + foreign handler EnableWindow(in pView as Pointer, in pEnable as CInt) \ + returns CInt binds to "user32>EnableWindow!stdcall" + + handler SetEnabled(in pButtonView as Pointer) + EnableWindow(pButtonView, my enabled) + end handler + +#### Linux + +> **Important:** It is not yet possible to write a fully functional +> native widget on Linux, as there are some issues with event handling +> and focus. This will be addressed in future releases. + +##### Native view + +Native views on Linux are `GtkPlug`s. A `GtkSocket` is used internally +to render the view from the process in which it is running. In most +instances you will want to embed a `GtkWidget` in a `GtkPlug`. + +The following snippet shows how to bind to `gtk_button_new_with_label`, +and use it to set the native layer to a suitable gtk plug id: + + // Bind to various useful functions in libgtk. We need to create a + // GTK plug, and GTK button, add the button to the plug and then + // show them. + foreign handler GTK_PlugNew(in pType as CUInt) returns Pointer \ + binds to "c:libgtk-x11-2.0.so>gtk_plug_new" + + foreign handler GTK_ButtonNewWithLabel(in pLabel as ZStringNative) returns Pointer binds to \ + "c:libgtk-x11-2.0.so>gtk_button_new_with_label" + + foreign handler GTK_ContainerAdd(in pContainer as Pointer, in pWidget as Pointer) returns nothing \ + binds to "c:libgtk-x11-2.0.so>gtk_container_add" + + foreign handler GTK_WidgetShow(in pWidget as Pointer) returns nothing binds to \ + "c:libgtk-x11-2.0.so>gtk_widget_show" + + // The actual native layer will be set to the plug id + foreign handler GTK_PlugGetId(in pPlug as Pointer) returns Pointer \ + binds to "c:libgtk-x11-2.0.so>gtk_plug_get_id" + + // Store references to both the plug and button + private variable mPlug as optional Pointer + private variable mNativeView as optional Pointer + + unsafe handler CreateNativeView() returns Pointer + // Create a new default plug + put GTK_PlugNew(0) into mPlug + + // Create a button with empty label + put GTK_ButtonNewWithLabel("") into mNativeView + + // Add the button to the plug + GTK_ContainerAdd(mPlug, mNativeView) + + // Ensure both button and plug are visible + GTK_WidgetShow(mNativeView) + GTK_WidgetShow(mPlug) + + // Return the plug window id + return GTK_PlugGetId(mPlug) + end handler + + unsafe handler SetNativeLayer() + set my native layer to CreateNativeLayer() + end handler + +##### Event handlers + +Event callbacks are pretty simple on Linux, as you can pass a (foreign) +handler into `g_signal_connect_data` directly: + + // Define the callback foreign handler type + public foreign handler type ClickCallback(in pWidget as Pointer, in pContext as optional Pointer) returns nothing + + // Bind to g_signal_connect_data to connect a foreign handler to + // a gtk signal + foreign handler GTK_SignalConnect(in pObj as Pointer, in pEvent as ZStringNative, \ + in pHandler as ClickCallback, in pData as optional Pointer, \ + in pNotify as optional Pointer, in pFlags as CUInt) returns CULong \ + binds to "c:libgtk-x11-2.0.so>g_signal_connect_data" + + // Actual handler that will be called when the button is clicked + handler OnButtonClick(in pWidget as Pointer, in pContext as optional Pointer) returns nothing + // The widget object in LiveCode will receive the posted message + post "mouseUp" + end handler + + unsafe handler SignalConnect(in pButtonView as Pointer) returns nothing + // Connect the foreign handler to the clicked signal. All other + // parameters are empty/default + GTK_SignalConnect(pButtonView, "clicked", OnButtonClick, \ + nothing, nothing, 0) + end handler + +##### Hooking up properties + +Properties of Linux native views can be set using the GTK Widget API. +For example, to hook up the enabled property of a Linux button (called +_sensitive_ in the GTK API: + + foreign handler GTK_WidgetSetSensitive(in pWidget as Pointer, in pValue as CBool) returns nothing \ + binds to "c:libgtk-x11-2.0.so>gtk_widget_set_sensitive" + + handler SetEnabled(in pButtonView as Pointer) + GTK_WidgetSetSensitive(pButtonView, my enabled) + end handler + +#### HTML5 + +##### Native view + +Native views on HTML5 are document elements, which can be created by +evaluating JavaScript and returning the element. + +The following snippet shows how to evaluate JavaScript using the +`EvalJavaScript` handler from the emscripten module to create a new +button element, and set the native layer of the widget. + + // Store the button element pointer + private variable mNativeView as optional Pointer + + handler CreateNativeView() returns Pointer + // Create an HTML5 button using JavaScript + put EvalJavaScript("document.createElement('button')") \ + into mNativeView + + return PointerFromJSObject(mNativeView) + end handler + + handler SetNativeLayer() returns nothing + set my native layer to CreateNativeView() + end handler + +##### Event handlers + +Event handlers can be attached to native views again by evaluating +JavaScript: + + // Utility function for adding an event listener + handler AddJSEventHandler(in pElement as JSObject, in pEvent as String, in pHandler as JSObject) + EvalJavaScriptWithArguments("arguments[0].addEventListener(arguments[1], arguments[2]);", [pElement, pEvent, pHandler]) + end handler + + // Actual handler that will be called when the button is clicked + handler OnJSClick(pEvent as JSObject) returns nothing + // The widget object in LiveCode will receive the posted message + post "mouseUp" + end handler + + // Store a reference to the JS handler + private variable mOnClickHandler as optional Pointer + + handler AttachEventHandler(in pButtonView as Pointer) + // Get a JS function that wraps the LCB callback + put HandlerAsJSFunction(OnJSClick) into mOnClickHandler + + // Add the handler to the button for the click event + AddJSEventHandler(pButtonView, "click", mOnClickHandler) + end handler + +##### Hooking up properties + +On HTML5, properties of the native view are manipulated by evaluating +JavaScript. For example, the enabled of the HTML5 button can be +implemented as follows: + + handler SetEnabled(in pButtonView as JSObject) + // Set button enabled using JavaScript + EvalJavaScriptWithArguments( \ + "arguments[0].disabled=arguments[1];", \ + [pButtonView, not my enabled]) + end handler + +## The extension package +The extension package is a zip file (with extension `.lce`) which, in +addition to the actual compiled lcb file, contains various other +components related to the extension: icons, documentation, guides, a +manifest, sample stacks, extension resources and native code. + +Packages can be uploaded to the extensions store to be shared with other +users of LiveCode. + ### Documenting Your Extension -Extensions can provide an API (Dictionary) and User Guide as part of the installed package. -They are installed and viewable through the LiveCode Dictionary stack. +Extensions can provide an API (Dictionary) and User Guide as part of the +installed package. They are installed and viewable through the LiveCode +Dictionary stack. **API (Dictionary)** @@ -544,110 +1990,174 @@ They are installed and viewable through the LiveCode Dictionary stack. 1. Click on the "Guide" tab at the top of the documentation stack 2. Select the guide you wish to view -> Note: In LiveCode 8.0 we'll be including an updated version of the LiveCode Script User -Guide. The version currently included with LiveCode has not yet been updated. - #### Adding API Markup -Any extension can include an API. To do so, either add a file called *api.lcdoc* to your -widget folder alongside the other widget files or markup your source code inline. +Any extension can include an API. To do so, either add a file called +*api.lcdoc* to your widget folder alongside the other widget files or +markup your source code inline. -Marking up your scripts is simple and follows a similar model to other documentation formats. +Marking up your scripts is simple and follows a similar model to other +documentation formats. Consider the following handler -``` -public handler myHandler(in pString as String, in pNumber as Number) - # Code -end handler -``` - -To add an entry to the API for this handler, place a formatted comment above the handler -definition: - -``` -/* -summary: Use this handler to do an action -pString: This parameter does x -pNumber: This parameter does y -description: -# Markdown Title -Here is a full description in markdown for how this function works. Once again, any GitHub -flavoured markdown is accepted. -*/ -public handler myHandler(in pString as String, in pNumber as Number) - # Code -end handler -``` - -The LiveCode API parser will combine the comment items with other data pulled directly -from your handler definition such as name, type and some parameter details. - -For a full list of acceptable documentation elements please see the LiveCode Documentation -Format guide. - -> **Important:** Documentation is only added to the LiveCode dictionary when a full -extension package is installed. Currently, this is only possible through the extension -builder. + + public handler myHandler(in pString as String, in pNumber as Number) + # Code + end handler + +To add an entry to the API for this handler, place a formatted comment +above the handler definition: + + /** + Summary: Use this handler to do an action + + Parameters: + pString: This parameter does x + pNumber: This parameter does y + + Description: + # Markdown Title + Here is a full description in markdown for how this function works. + Once again, any GitHub flavoured markdown is accepted. + */ + public handler myHandler(in pString as String, in pNumber as Number) + # Code + end handler + +The LiveCode API parser will combine the comment items with other data +pulled directly from your handler definition such as name, type and some +parameter details. + +For a full list of acceptable documentation elements please see the +LiveCode Documentation Format guide. + +> **Important:** Documentation is only added to the LiveCode dictionary +> when an extension is installed in the IDE. #### Adding a User Guide -Any extension can include a user guide. To do so, add a markdown file called *guide.md* -to your widget folder alongside the other widget files. +Any extension can include a user guide. To do so, add a markdown file +called *guide.md* to your widget folder alongside the other widget +files. All GitHub flavoured markdown is accepted. ### Packaging Extensions Packaging extensions is easy. Simply open the "Extension Builder" stack: -``` -Tools > Extension Builder -``` + Tools > Extension Builder -Load your ***.lcb*** file and click "Build Package". A new file will appears in the same -directory as your main file with the extension ***.lce***. This is your final package file -ready for upload to the extensions portal. +Load your ***.lcb*** file and click "Build Package". A new file will +appears in the same directory as your main file with the extension +***.lce***. This is your final package file ready for upload to the +extensions portal. #### Package requirements A valid package can be built from a minimum set of files: -``` -widget.lcb // Widget source file -support/icon.png // 20x40 png image -support/icon@extra-high.png // 40x80 png image -``` + widget.lcb // Widget source file + support/icon.png // 20x40 png image + support/icon@extra-high.png // 40x80 png image + +## The Extension Store + +Once you have created and packaged your extension you can make it +available to the LiveCode Community via the +[Extension Store](https://livecode.com/products/extensions), in the +[widgets](https://livecode.com/products/widgets/) section. + +### Registering as an Extension Developer + +The first step is to +[register](https://livecode.com/account/developer/register) as an +Extension Developer. + +- Log in to your LiveCode Account +- Select the Register option under the Developer section + +![enter image description here](images/extensions-developer_id.png) + +LiveCode Extensions must have unique identifiers. These identifiers use +reverse domain notation. + +You can sign up on this page for a LiveCode Community Developer ID. +Having a developer ID will allow you to use extension identifiers of the +form: `community.livecode.developerID.extensionName`. + +Choose the Developer ID you want to use here. If your chosen ID is +already in use you will be asked to choose a different one. + +### Uploading Extensions to the Store + +To upload a packaged extension to the store log in to your LiveCode +account and go to the +[Extensions](https://livecode.com/account/developer/extensions) section +of the Developer area. + +Any extensions you have uploaded will be shown here, and you have the +option to add new extensions. + +- Click the "Add New Extension" button (if available) +- Drag your packaged extension (`.lce`) file into the upload area +- When the extension has uploaded it will appear in your list + +![enter image description here](images/extensions-upload.png) + +### Activating your Extension + +When an extension is first uploaded it is not active so will not show in +the Extension Store. + +To activate your extension click "activate" under Status. At this stage +you will be warned if any information is missing and you can add it by +clicking the "Edit" button. + +![enter image description here](images/extensions-activate.png) + +Once your extension is activated its status will change to "Active". + +### The Extension Store in the Extension Manager + +You can view and downlaod extensions via the Extension Store. To see the +extensions that are available to download open the Extension Manager +from the LiveCode Tools menu and select the "Store" tab. + +![enter image description here](images/extensions-store.png) + +You can also download extensions from the [Widget +Store](https://livecode.com/products/widgets/) on the LiveCode website +then install the downloaded extension using the Extension Manager. ## Other ways to extend the Built-in Capabilities -There are many other ways to extend LiveCode. This section explains how to run shell -commands, start other applications, read and write to processes, execute AppleScript, -VBScript, send and respond to AppleEvents and communicate between multiple LiveCode-based -processes. It also tells you where to get information to create external commands and -functions (code written in lower level languages). +There are many other ways to extend LiveCode. This section explains how +to run shell commands, start other applications, read and write to +processes, execute AppleScript, VBScript, send and respond to +AppleEvents and communicate between multiple LiveCode-based +processes. It also tells you where to get information to create external +commands and functions (code written in lower level languages). ### Communicating with other process and applications #### Reading and writing to the command shell -Use the **shell** function to run shell commands and return the result. The following -example displays a directory listing on Mac OS X: +Use the **shell** function to run shell commands and return the result. +The following example displays a directory listing on Mac OS X: -``` -answer shell("ls") -``` + answer shell("ls") And this example stores a directory listing in a variable on Windows: -``` -put shell("dir") into tDirectory -``` + put shell("dir") into tDirectory -On Windows systems you can prevent a terminal window from being displayed by setting the -**hideConsoleWindows** global property to true. +On Windows systems you can prevent a terminal window from being +displayed by setting the **hideConsoleWindows** global property to true. You can choose a different shell program by setting the **shellPath** global property. By default this is set to "/bin/sh" on Mac OS X and Linux and "command.com" on Windows. -> **Tip:** The shell function blocks LiveCode until it is completed. If you want to run a -shell command in the background, write the shell script to a text file then execute it -with the `launch`command. +> **Tip:** The shell function blocks LiveCode until it is completed. If +> you want to run a shell command in the background, write the shell +> script to a text file then execute it +> with the `launch`command. #### Launching other applications @@ -655,51 +2165,54 @@ Use the **launch** command to launch other applications, documents or URLs. To l application, supply the full path to the application. The following example opens a text document with TextEdit on OS X: -``` -launch "/Users/someuser/Desktop/text document.rtf" with "/Applications/TextEdit.app" -``` + launch "/Users/someuser/Desktop/text document.rtf" with "/Applications/TextEdit.app" -> **Tip:** To get the path to an application, use the `answer file` command to select the -application then copy it into your script. Run this in the message box: -`answer file "Select an application"; put it` +> **Tip:** To get the path to an application, use the `answer file` +> command to select the application then copy it into your script. Run +> this in the message box: -To open a document with the application it is associated with use the **launch document** -command. + `answer file "Select an application"; put it` + +To open a document with the application it is associated with use the +**launch document** command. -``` -launch document "C:/My document.pdf" -``` + launch document "C:/My document.pdf" -To open a URL in the default web browser, use the **launch URL** command. +To open a URL in the default web browser, use the **launch URL** +command. -launch URL "" + launch URL "" -For more information on launching URLs and details on how to render web pages within -LiveCode, see the Transferring Information guide. +For more information on launching URLs and details on how to render web +pages within LiveCode, see the Transferring Information guide. #### Closing another application -Use the **kill process** command to send a signal to another application, to close it or -to force it to exit. For more details, see the LiveCode Dictionary. +Use the **kill process** command to send a signal to another +application, to close it or to force it to exit. For more details, see +the LiveCode Dictionary. #### Communicating with other processes -Use the **open process** command to open an application or process you want to read and -write data from. You can then read from the process with the **read from process** command -and write to it with the **write to process** command. To close a process you have opened, -use the **close process** command. The **openProcesses** returns a list of processes you -have opened and the **openProcessIDs** returns the process IDs of each one. For more -details see the *LiveCode Dictionary*. +Use the **open process** command to open an application or process you +want to read and write data from. You can then read from the process +with the **read from process** command and write to it with the **write +to process** command. To close a process you have opened, use the +**close process** command. The **openProcesses** returns a list of +processes you have opened and the **openProcessIDs** returns the process +IDs of each one. For more details see the *LiveCode Dictionary*. -#### Using AppleScript and VBScript (Open Scripting Architecture or Windows Scripting Host) +#### Using AppleScript and VBScript (Open Scripting Architecture or +Windows Scripting Host) -To execute commands using AppleScript on Mac OS or VBScript on Windows, use the **do as** -command. **do as** also allows you to use any other *Open Scripting Architecture* languages -on Mac OS or languages installed into the *Windows Scripting Host* on Windows. To retrieve -a list of the available installed languages, use the **alternateLanguages**. +To execute commands using AppleScript on Mac OS or VBScript on Windows, +use the **do as** command. **do as** also allows you to use any other +*Open Scripting Architecture* languages on Mac OS or languages installed +into the *Windows Scripting Host* on Windows. To retrieve a list of the +available installed languages, use the **alternateLanguages**. -For example, to execute an AppleScript that brings the Finder on OS X to the front, enter -the following into a field: +For example, to execute an AppleScript that brings the Finder on OS X to +the front, enter the following into a field: *tell application "Finder"* *activate* @@ -707,18 +2220,15 @@ the following into a field: Then run: -``` -do field 1 as "appleScript" -``` + do field 1 as "appleScript" -To retrieve a result from commands executed using `do as`, use `the result` function. Any -error message will also be returned in `the result`. The following example displays -`the result` of an addition performed using VBScript: +To retrieve a result from commands executed using `do as`, use `the +result` function. Any error message will also be returned in `the +result`. The following example displays `the result` of an addition +performed using VBScript: -``` -do "result = 1 + 1" as "vbscript" -answer the result -``` + do "result = 1 + 1" as "vbscript" + answer the result For more information on the do as command, see the LiveCode Dictionary. @@ -726,96 +2236,102 @@ For more information on the do as command, see the LiveCode Dictionary. To send an AppleEvent, use the **send to program** command. -If LiveCode receives an AppleEvent it will send an **appleEvent** message to the current -card. Intercept this message to perform actions such as handling a request to quit your -application or opening a document. The following example shows how you could handle a -request to quit: - -``` -on appleEvent pClass, pID, pSender - if pClass & pID is "aevtquit" then - -- call a function that prompts the user to save changes - put checkSaveChanges() into tOkToQuit - -- returns false if the user presses "cancel" - if tOkToQuit is true then quit - else exit appleEvent - end if -end appleEvent -``` +If LiveCode receives an AppleEvent it will send an **appleEvent** +message to the current card. Intercept this message to perform actions +such as handling a request to quit your application or opening a +document. The following example shows how you could handle a request to +quit: + + on appleEvent pClass, pID, pSender + if pClass & pID is "aevtquit" then + -- call a function that prompts the user to save changes + put checkSaveChanges() into tOkToQuit + -- returns false if the user presses "cancel" + if tOkToQuit is true then quit + else exit appleEvent + end if + end appleEvent To retrive additional information passed with the appleEvent use the -**request appleEvent data** command. The following example shows how you could handle a -request to open a stack: - -``` -on appleEvent pClass, pID, pSender - --appleEvent sent when stack is opened from the finder - if pClass & pID is " aevtodoc " then - -- get the file path(s) - request AppleEvent data - put it into tFilesList - repeat for each line l in tFilesList - go stack l - end repeat - end if -end appleEvent -``` +**request appleEvent data** command. The following example shows how you +could handle a request to open a stack: + + on appleEvent pClass, pID, pSender + --appleEvent sent when stack is opened from the finder + if pClass & pID is " aevtodoc " then + -- get the file path(s) + request AppleEvent data + put it into tFilesList + repeat for each line l in tFilesList + go stack l + end repeat + end if + end appleEvent For more details see the *LiveCode Dictionary*. #### Using Local sockets -If you want to communicate between local applications a common technique that can be used -without code changes on all the platforms LiveCode supports, is to open a local socket and -communicate using that. You should choose a port number that is not used by a standard -protocol – typically a high number. - -This technique is commonly used when you want to create multiple programs that run -independently but communicate with each other. It is a viable technique for running -background tasks and provides a straightforward way to create an application that behaves -as if threaded – i.e. with benefits of multiple threads. You can design your application -such that additional instances can be launched to perform processing, data transfer or -other intensive activities. Modern OSes will allocate each application to an appropriate -processor core. By using socket messaging to communicate with each one you can keep your -main application's user interface responsive and display status information. The following -example shows you how to open a socket to the local machine: - -``` -open socket to "127.0.0.1:10000" with message gotConnection -``` - -A detailed discussion of how to create a protocol using sockets can be found in the -Transferring Information guide. - -> **Tip:** To simplify communication between multiple LiveCode programs, consider writing -a simple library that sends and receives a handler name together with parameter data. To -call a handler in the other LiveCode program, send the handler name and data to the -library. The library will send the data over a socket. In the receiving program intercept -the incoming data from the socket and use it to call the appropriate message with the -parameter data received. +If you want to communicate between local applications a common technique +that can be used without code changes on all the platforms LiveCode +supports, is to open a local socket and communicate using that. You +should choose a port number that is not used by a standard protocol – +typically a high number. + +This technique is commonly used when you want to create multiple +programs that run independently but communicate with each other. It is a +viable technique for running background tasks and provides a +straightforward way to create an application that behaves as if threaded +– i.e. with benefits of multiple threads. You can design your +application such that additional instances can be launched to perform +processing, data transfer or other intensive activities. Modern OSes +will allocate each application to an appropriate processor core. By +using socket messaging to communicate with each one you can keep your +main application's user interface responsive and display status +information. The following example shows you how to open a socket to the +local machine: + + open socket to "127.0.0.1:10000" with message gotConnection + +A detailed discussion of how to create a protocol using sockets can be +found in the Transferring Information guide. + +> **Tip:** To simplify communication between multiple LiveCode programs, +> consider writing a simple library that sends and receives a handler +> name together with parameter data. To call a handler in the other +> LiveCode program, send the handler name and data to the library. The +> library will send the data over a socket. In the receiving program +> intercept the incoming data from the socket and use it to call the +> appropriate message with the parameter data received. ## Externals – code written in lower level languages -LiveCode provides an external interface which allows you to extend it using a lower level -language (often C). For example, if you have preexisting code that performs processing in -a lower level language, you can write a user interface in LiveCode and then call this -library by writing a simple wrapper around it using LiveCode's externals interface. -LiveCode supports transmitting data to and from externals, as well as drawing into image -objects within LiveCode windows, manipulating the player object, and more. - -> **Note:** Some aspects of the built in functionality are supplied in the form of -externals. These include the SSL library, the database library, the revBrowser library, -zip library, video grabber and XML libraries. These libraries can be included in a -standalone application, or excluded if they are not needed – saving disk space. +LiveCode provides an external interface which allows you to extend it +using a lower level language (often C). For example, if you have +preexisting code that performs processing in a lower level language, you +can write a user interface in LiveCode and then call this library by +writing a simple wrapper around it using LiveCode's externals interface. +LiveCode supports transmitting data to and from externals, as well as +drawing into image objects within LiveCode windows, manipulating the +player object, and more. + +> **Important:** Much of what is provided by the externals API is now +> supported by the foreign function interface in LiveCode Builder, +> where it is not necessary to write any glue code in C. Whilst the +> externals interface is still supported, LCB is now the recommended way +> to wrap native code for LiveCode. + +> **Note:** Some aspects of the built in functionality are supplied in +> the form of externals. These include the SSL library, the database +> library, the revBrowser library, zip library and XML libraries. These +> libraries can be included in a standalone application, or excluded if +> they are not needed – saving disk space. ### The Externals SDK -We provide a developer kit for writing externals which includes documentation and examples. -You may download this kit from: - - +Occasionally LiveCode Builder may not be what you need to create your extension. We provide a legacy developer kit for writing externals in C++ which includes documentation and examples. -The following newsletter articles will also help you get started: +The following newsletter articles will help you get started: * [External Writing for the Uninitiated – Part 1](http://newsletters.livecode.com/november/issue13/newsletter5.php) diff --git a/Documentation/guides/LiveCode Data Grid.md b/Documentation/guides/LiveCode Data Grid.md index 6a4c63d8bf..a655035aaf 100644 --- a/Documentation/guides/LiveCode Data Grid.md +++ b/Documentation/guides/LiveCode Data Grid.md @@ -1,11 +1,11 @@ --- group: intermediate --- -# LiveCode Data Grid # +# LiveCode Data Grid -## Introduction ## +## Introduction -### What is the Data Grid?### +### What is the Data Grid? The LiveCode Data Grid enables you to integrate powerful tables and forms into your projects. Data grids combine LiveCode groups and @@ -13,7 +13,7 @@ behaviors to provide you with a simple, yet flexible means of displaying your data in just about any way you want. -#### A Data Grid Table #### +#### A Data Grid Table ![](images/datagrid-table.gif) @@ -24,7 +24,7 @@ each column of each row. If you need to customize a column with graphics you can define your own templates for each column. A custom template can be any LiveCode control such as a graphic or group. -#### A Data Grid Form #### +#### A Data Grid Form ![](images/datagrid-form.gif) @@ -45,16 +45,16 @@ displaying lots of records. Any list where you want a rich UI and complete control over layout and processing of engine events can benefit from being displayed using a data grid form. -### Can You Show Me Some Examples?### +### Can You Show Me Some Examples? Of course we can! The areas of the screenshots highlighted in blue are instances of the data grid control. -#### Data Grid Table #### +#### Data Grid Table ![](images/datagrid-table-display-1.png) -#### Data Grid Forms #### +#### Data Grid Forms ![](images/datagrid-form-display-1.png) @@ -68,21 +68,21 @@ instances of the data grid control. ![](images/datagrid-form-display-6.png) -### How Do I Create My First Data Grid Table?### +### How Do I Create My First Data Grid Table? This lesson will show you how to create a bare bones data grid table. Data grid tables are useful when you need to display rows of data in structured columns. -#### Locate Data Grid on Tools Palette#### +#### Locate Data Grid on Tools Palette ![](images/datagrid-tools-palette.png) -#### Drag Data Grid Onto Card#### +#### Drag Data Grid Onto Card ![](images/datagrid-drag-onto-card.png) -#### Populate Data Grid Using The Property Inspector #### +#### Populate Data Grid Using The Property Inspector Data Grid tables display data in columns that you can customize the look of. You don't have to worry about customization right now though because @@ -113,7 +113,7 @@ column in the Data Grid for each column in the text you provide (2). ![](images/datagrid-table-inspector-columns-1.png) -#### Customizing Columns#### +#### Customizing Columns Now that you've populated a Data Grid Table with some data let's look at the columns in the Data Grid. @@ -128,7 +128,7 @@ the columns needed already exist you can go through and rename Note that a label for the columns (3) has also been assigned . Labels are useful for customizing the column labels in the Data Grid Table. -#### Populate Data Grid Using dgText Property#### +#### Populate Data Grid Using dgText Property Now that you have defined your columns let's look at how to populate a Data Grid Table by setting the **dgText** property. Here is an example @@ -156,7 +156,7 @@ Grid table. ![](images/datagrid-table-with-dgtext.png) -#### Populating the Data Grid Using dgData Property#### +#### Populating the Data Grid Using dgData Property Here is an example of populating the Data Grid Table by setting the **dgData** property to an array. The end result is the same as the previous @@ -177,29 +177,29 @@ step. set the dgData of group "DataGrid" to theDataA end mouseUp -### How Do I Create My First Data Grid Form?### +### How Do I Create My First Data Grid Form? This lesson will show you how to create a bare bones data grid form. Data grid forms are useful when you need a less rigid layout than columns in a table provide. A data grid form gives you complete control over the look and feel of each record you display. -#### Locate Data Grid on Tools Palette#### +#### Locate Data Grid on Tools Palette ![](images/datagrid-tools-palette.png) -#### Drag Data Grid Onto Card#### +#### Drag Data Grid Onto Card ![](images/datagrid-drag-onto-card.png) -#### Change Style to "Form" #### +#### Change Style to "Form" Select the Data Grid and open the LiveCode **Property Inspector**. Change the style to **form**. ![](images/datagrid-form-inspector-style.png) -#### Add Some Text #### +#### Add Some Text Now you can assign some text to the data grid. By default a data grid will render some basic data without you having to customize the row @@ -211,7 +211,7 @@ template. To assign some text: 2. Type or paste some line delimited text into the field. (2) -#### Result#### +#### Result That's it! The data you entered in the field will appear in the data grid. Now you are ready to customize the look and feel of your records @@ -225,37 +225,37 @@ under the hood. By using arrays you can store and display all different kinds of data in a data grid. Being able to assign the **Contents** property is merely a convenience. -### Example: Creating a List of People### +### Example: Creating a List of People This lesson provides a low level detail, step-by-step example of creating a custom data grid form. Download the attached sample stack to see the scripts. -#### Attached Files#### +#### Attached Files [datagrid_sampler.zip](http://lessons.livecode.com/s/lessons/files/13?lesson_id=7305) -#### What You Will Create #### +#### What You Will Create ![](images/media_1278008632464_display.png) This is the data grid that you will create. Each row displays a name, a title and an image. -#### Add Data Grid to Card#### +#### Add Data Grid to Card ![](images/datagrid-drag-onto-card.png) To begin, drag a data grid from the **Tools palette** onto your card. -#### Change Data Grid Style #### +#### Change Data Grid Style ![](images/media_1278011173914_display.png) Select the data grid and from the **Basic Properties** pane of the **Property Inspector** change the style of the data grid to **Form.** -#### The Data That Is Going to Be Displayed in Each Row #### +#### The Data That Is Going to Be Displayed in Each Row Now you are going to design the row template for the data grid form. The row template dictates how each record in the data grid will be @@ -273,14 +273,14 @@ access to the data stored in the *FirstName*, *LastName*, *Title* and You are now going to add UI controls to the row template in order to display the data for each of these keys. -#### Edit the Row Template #### +#### Edit the Row Template With the data grid selected, click on the **Row Template** button in the **Property Inspector** to open the card containing row template controls. ![](images/media_1278011265770_display.png) -#### Edit the Row Template Group #### +#### Edit the Row Template Group In order to customize the look you need to edit the contents of the template group. @@ -293,7 +293,7 @@ template group. 4. Click **Edit Group** in the LiveCode toolbar. -#### Rename Label Field #### +#### Rename Label Field The default template group has a field named *Label*. Click on the left side of the gray rectangle to select it.(1) @@ -307,14 +307,14 @@ the name of the field to *Name* (2). Switch to the **Contents** pane and assign ![](images/media_1278010330080_display_1.png) -#### Make Name Field Bold #### +#### Make Name Field Bold With the *Name* field still selected go the **Text Formatting** pane of the **Property Inspector** (1) and change the **Style** to **Bold**(2). ![](images/media_1278010452322_display.png) -#### Add Title Field #### +#### Add Title Field Drag a label field from the Tools palette (1). @@ -325,14 +325,14 @@ Name it *Title* (2) and assign *Title* to the content (3). ![](images/media_1278010622403_display_1.png) -#### Change Text Alignment #### +#### Change Text Alignment Change the text alignment of the field to the left side using the **Text Formatting** pane of the **Property Inspector**. ![](images/media_1278010671679_display.png) -#### Add an Image and Resize the Background Graphic #### +#### Add an Image and Resize the Background Graphic ![](images/Add_An_Image_and_Resize_The_Background_Graphic_display.png) @@ -345,7 +345,7 @@ fit within these bounds. Finally, select the **Background** graphic (5) and resize it so that it frames the other controls. In the example stack the **width** of the graphic is 214 and the **height** is 56. -#### Stop Editing the Row Template Group #### +#### Stop Editing the Row Template Group ![](images/media_1278011030380_display.png) @@ -353,7 +353,7 @@ You are now done adding the UI objects to the row template group. From the **Object** menu (1), select **Stop Editing Group**. You can then **Close** and **Save** the **row template** -#### Edit the Row Behavior #### +#### Edit the Row Behavior Now that you have designed the controls for each row you need to write the script that will move data into the controls and position them on @@ -364,7 +364,7 @@ the screen. Click on the **Edit Script** button in the **Property Inspector** under **Row Behavior** to begin editing the row behavior script. -#### The FillInData Message #### +#### The FillInData Message In the script that opens when you click the Row Behavior button you will find a command named **FillInData**. This is where you move data from @@ -399,7 +399,7 @@ data to the UI controls. set the filename of image "image" of me to pDataArray["Image URL"] end FillInData -#### The LayoutControl Message #### +#### The LayoutControl Message The **LayoutControl** message is where you position all of your controls. For this template you begin by positioning the image (1). Next @@ -433,7 +433,7 @@ rectangle. set the rect of graphic "Background" of me to pControlRect end LayoutControl -#### Set the Data of the Control #### +#### Set the Data of the Control This is an example of a handler that populates the data grid with data by setting the **dgData** property. The **dgData** property accepts a @@ -481,7 +481,7 @@ It is called by a button placed on the card **Populate Data Grid** with script end Mouseup -#### The Result #### +#### The Result After calling the **uiPopulatePeople** command the Data Grid should look something like this (1). @@ -494,7 +494,7 @@ see any of the changes made to the row template. You can send the Grid** button on the Basic Properties pane of the **Property Inspector** (2) to redraw the data using the updated template. -#### Troubleshooting: Row Height #### +#### Troubleshooting: Row Height By default a data grid uses a fixed height for each row. If you have not set the row height the first time you populate the data grid with data @@ -511,9 +511,9 @@ Alternatively you could also simply uncheck the **Empty row height** property.(2 ![](images/media_1237547039021_display_2.png) -## Data Grid Fundamentals ## +## Data Grid Fundamentals -### What Is This "Data Grid Templates" Stack That Appeared in My Project? ### +### What Is This "Data Grid Templates" Stack That Appeared in My Project? A data grid relies on record templates (forms) and column templates (tables) to display data. These templates are merely LiveCode controls @@ -521,7 +521,7 @@ that will be used to visualize your data. In order to manage these controls the LiveCode IDE creates a stack named Data Grid Templates the first time you add a data grid to a card in your stack. -#### Data Grid Templates Stack #### +#### Data Grid Templates Stack Open the **Project Browser** (from the **Tools** menu) and expand your stack by clicking on the "+" sign. Here you will see the newly created **Data Grid @@ -533,7 +533,7 @@ This stack (1) contains a single card (2) for each data grid you add to a stack. Each card contains the template(s) and behaviors that the data grid will use to display the data. -#### Data Grid Templates Card Contents #### +#### Data Grid Templates Card Contents This screenshot shows some controls that might appear on a Data Grid Templates card. The **Row Template** (1) is the group that contains either @@ -548,7 +548,7 @@ Template** group and is used for data grid forms. This script controls how data is inserted into the **Row Template** controls and how those controls are positioned. -#### Opening the Data Grid Templates Stack #### +#### Opening the Data Grid Templates Stack The LiveCode IDE makes it easy to locate your templates in the Data Grid @@ -561,14 +561,14 @@ The card containing the template(s) for the selected data grid will open. ![](images/media_1236056276168_display.png) -### What Is a Row Template? ### +### What Is a Row Template? The reason a data grid can be customized is because it uses "templates" to represent data. A template is merely a Livecode group that will be copied and used to draw your data on the screen. When working with data grid forms we refer to this group as a "Row Template". -#### Row Template #### +#### Row Template ![](images/Row_Template_display.png) @@ -577,7 +577,7 @@ a single record in the data that you are displaying in a data grid form. This group can contain any Livecode control and the look and layout are entirely controlled by you. -#### How a Record Template Is Used #### +#### How a Record Template Is Used ![](images/How_A_Record_Template_Is_Used_display.png) @@ -589,7 +589,7 @@ are used but new data is inserted. This means that the data grid form is never drawing more records than the user can actually see which means the data grid is fast. -### What Is a Column Template? ### +### What Is a Column Template? Like data grid forms, data grid tables also use templates. The difference is that when working with a table you create a template to @@ -599,7 +599,7 @@ similar to a **row template**. One difference is that a **column template** is not limited to being a group. You can use a field for a template, a graphic, a button, etc. -#### How a Column Template Is Used #### +#### How a Column Template Is Used ![](images/How_A_Column_Template_Is_Used_display.png) @@ -608,12 +608,12 @@ copied into the data grid as many times as necessary in order to fill the visible area. Data is then inserted into these templates as the user scrolls. -### How Do I Populate a Data Grid With Data? ### +### How Do I Populate a Data Grid With Data? There are a couple of ways you can assign data to a data grid. This lesson will show you how. -#### Use The Property Inspector#### +#### Use The Property Inspector ![](images/datagrid-form-inspector-text.png) @@ -628,7 +628,7 @@ running quickly. When you use the **Property Inspector** to assign data to the data grid the **Property Inspector** sets the **dgText** property of the data grid. -#### Set the dgText Property #### +#### Set the dgText Property ![](images/media_1239244946023_display.png) @@ -669,7 +669,7 @@ Behavior** to display the imported data correctly. If *pText* will be named "Label X" (where X is the item number) in the array that is passed to **FillInData**. -#### Set the dgData Property#### +#### Set the dgData Property ![](images/media_1238000479771_display.png) @@ -714,7 +714,7 @@ these properties when the time comes to draw the data on the screen. theDataA[1]["Image URL"] -### How Do I Customize a Form's Row Template? ### +### How Do I Customize a Form's Row Template? When you drop a data grid from the **Tools palette** onto a card a record template is created for you automatically. This template will display @@ -722,7 +722,7 @@ line delimited text but you will most likely want to customize the template. This lesson will show you how to begin customizing the template to meet your needs. -#### Reveal the Row Template #### +#### Reveal the Row Template ![](images/media_1238098827623_display.png) @@ -736,7 +736,7 @@ The template for the data grid will open. You can now edit the controls within the **Row Template** group in order to customize the look and feel according to your needs. -#### Example of a Customized Template #### +#### Example of a Customized Template ![](images/media_1238098972256_display.png) @@ -744,7 +744,7 @@ Here is an example of a customized template. A *Name* (1) and *Title* field (2) have been added as well as a control for displaying a picture of the person (3). -#### Edit Behavior #### +#### Edit Behavior ![](images/media_1278011291637_display.png) @@ -755,7 +755,7 @@ to position the controls. Click the **Edit Script...** button to open the behavior script. -#### Edit the Behavior Script #### +#### Edit the Behavior Script ![](images/media_1238099074165_display.png) @@ -775,7 +775,7 @@ different than the first parameter passed to **FillInData** for a >removes any ambiguity and ensures that data is displayed in the > correct control. -#### An Example of a Customized Behavior #### +#### An Example of a Customized Behavior ![](images/media_1238100174053_display.png) @@ -801,14 +801,14 @@ This example also shows how to use **LayoutControl** to layout your **row template**. Notice how the rectangle of the **row template** is captured at the beginning (3) and then used to position all of the other elements (4). -### How Do I Customize a Table's Columns? ### +### How Do I Customize a Table's Columns? A **column template** is nothing more than a LiveCode control that is named after a column in your table. This control is located in the **row template** group for your data grid. This lesson will discuss how to create templates for columns in a data grid table. -#### Use Property Inspector to Create a Column Template #### +#### Use Property Inspector to Create a Column Template ![](images/media_1238002014733_display.png) @@ -818,7 +818,7 @@ template** (2). ![](images/media_1238002031307_display.png) -#### Edit the Row Template Group #### +#### Edit the Row Template Group ![](images/media_1238002170294_display.png) @@ -826,14 +826,14 @@ In order to customize the look you need to edit the contents of the template group. Select it (1) and click **Edit Group** (2) in the LiveCode toolbar. -#### Edit Column Group #### +#### Edit Column Group ![](images/media_1238002156173_display.png) Now select the column group (1) and click **Edit Group** again (2). At this point you can customize what controls appear in the column template. -#### A Column Template #### +#### A Column Template ![](images/media_1236271024680_display.png) @@ -848,7 +848,7 @@ is included in the row template by default). Here is what those controls look like in the **Project Browser**. Notice how all of the controls are located in the **Row Template** group. -#### Supporting Controls #### +#### Supporting Controls ![](images/media_1238002344589_display.png) @@ -856,7 +856,7 @@ The controls created (*Time* field, *Genre* button and *My Rating* group) each have behaviors associated with them. These were created automatically and are stored in appropriately named buttons. -#### Behavior Example #### +#### Behavior Example ![](images/media_1238002391039_display.png) @@ -869,7 +869,7 @@ Note how this parameter differs than the parameter sent to **FillInData** for a You then use that value to determine how many stars to display (2). -#### Result #### +#### Result ![](images/media_1236272022940_display.png) @@ -878,18 +878,18 @@ defined. The table found controls named *Genre*, *Time* and *My Rating* in the record template group so those were used to render the data for those three columns. -## Working With Data Grids (Forms & Tables) ## +## Working With Data Grids (Forms & Tables) -### How Do I Determine the Selected Line? ### +### How Do I Determine the Selected Line? -#### The dgHilitedLines Property #### +#### The dgHilitedLines Property ![](images/media_1238000737113_display.png) You can get the selected line or lines of a data grid using the **dgHilitedLines** property. -#### Determining the Line in a Row's Behavior #### +#### Determining the Line in a Row's Behavior If we need to determine the line number of a row's behavior script we can access the **dgLine** property of the row template. The data grid @@ -905,7 +905,7 @@ script were in the **row template** group itself). If you were to put the template group then you would have to use ***of the dgControl of me*** instead. -### How Do I Get Data Associated With a Row or Column? ### +### How Do I Get Data Associated With a Row or Column? This lesson will show you how to get the array of data associated with a row in a Data Grid form as well as how to get the data associated with a @@ -938,7 +938,7 @@ key, or column, for a row. Let's look at some examples of how to use these properties and functions. -#### Getting Data Associated With the Selected Row #### +#### Getting Data Associated With the Selected Row ![](images/media_1247571008922_display.png) @@ -983,7 +983,7 @@ application: put the uSelectedID of group "DataGrid" into theSelectedID -#### Getting Data When the Selection Changes #### +#### Getting Data When the Selection Changes When the user makes a new selection in a Data Grid the **selectionChanged** message is sent to the Data Grid. The following **selectionChanged** message @@ -996,7 +996,7 @@ could appear in the script of your Data Grid group: uiViewRecordOfID theDataA["id"] end selectionChanged -#### Getting Data in a Row Behavior #### +#### Getting Data in a Row Behavior ![](images/media_1237839849843_display.png) @@ -1033,7 +1033,7 @@ check to ensure that the user clicked on a row. This example also uses end if end mouseUp -#### Getting Data in a Column Behavior #### +#### Getting Data in a Column Behavior ![](images/media_1262102060634_display.png) @@ -1071,13 +1071,13 @@ check to ensure that the user clicked on a column: end if end mouseUp -### How Do I Add a Row of Data to an Existing Data Grid? ### +### How Do I Add a Row of Data to an Existing Data Grid? Sometimes you may want to add a row of data to a Data Grid without having to set the **dgData** or **dgText** property. You can add a single row of data by calling the **AddData** or **AddLine** commands of a Data Grid. -#### Using AddData #### +#### Using AddData To use **AddData** you create an array containing the values for the new row. Here is an example of how to add a new row and have it appear as @@ -1096,7 +1096,7 @@ line 1 in a Data Grid. ![](images/media_1256565520707_display.png) -#### Using AddLine #### +#### Using AddLine To use **AddLine** you create a tab delimited string of text containing the values for the new row. You also need to tell the Data Grid the @@ -1113,7 +1113,7 @@ how to add a new row and have it appear as the last line in a Data Grid. ![](images/using_addLine_display.png) -#### Scrolling Data Into View and Getting the Data Control #### +#### Scrolling Data Into View and Getting the Data Control After you add the data to the Data Grid you may want to scroll the new row into view. You can call **ScrollIndexIntoView** or @@ -1125,11 +1125,11 @@ or ScrollLineIntoView theLineNo -### How Do I Update Data in a Row? ### +### How Do I Update Data in a Row? This lesson will show you how to update data in a row. -#### Updating a Row's Data and Refresh Data Grid Automatically #### +#### Updating a Row's Data and Refresh Data Grid Automatically You can update data in a row by setting the **dgDataOfIndex** or **dgDataOfLine** properties. You can set either property to an array @@ -1146,7 +1146,7 @@ containing the values for the row. The data grid will now refresh with the new data you assigned to the highlighted index. -#### Updating a Row's Data Without Refreshing the Data Grid #### +#### Updating a Row's Data Without Refreshing the Data Grid If you want to update the data in a row without automatically refreshing the data grid then you can use **SetDataOfIndex**. You can then use the @@ -1173,14 +1173,14 @@ Example that sets individual keys of the row one at a time: dispatch "RefreshIndex" to group "DataGrid" with the \ dgHilitedIndex of group "DataGrid" -### How Do I Clear Data From a Data Grid? ### +### How Do I Clear Data From a Data Grid? Clearing the data out of a Data Grid is as easy as setting the **dgData** (or **dgText**) of the Data Grid to **empty**. set the dgData of group "DataGrid" to empty -### How Do I Add a mouseDown Event to the Data Grid Without Breaking It? ### +### How Do I Add a mouseDown Event to the Data Grid Without Breaking It? This lesson will show you how you to write your own **mouseDown** event in a Data Grid without breaking the default Data Grid behavior. You need to @@ -1192,7 +1192,7 @@ message that the Data Grid normally handles. Doing so changes the behavior of the Data Grid and you need to take that into account when coding your **mouseDown** handler. -#### What Doesn't Work #### +#### What Doesn't Work If you were to place the following code in your Data Grid script you would not get the result you were expecting. The reason is that the @@ -1211,7 +1211,7 @@ script itself. pass mouseDown end mouseDown -#### What Does Work: dgMouseDown #### +#### What Does Work: dgMouseDown In order to work around this the Data Grid wraps all **mouseDown** functionality in a handler named **dgMouseDown**. You can call this @@ -1247,12 +1247,12 @@ call to **dgMouseDown** which is not the desired behavior. ## Don't pass mouseDown end mouseDown -### How Can I Store an Option Menu Value When the User Makes a Selection? ### +### How Can I Store an Option Menu Value When the User Makes a Selection? This lesson will demonstrate how to update the data associated with a row in a data grid when the user makes a selection from an option menu. -#### Example Data Grid #### +#### Example Data Grid ![](images/media_1239422115316_display.png) @@ -1261,7 +1261,7 @@ and has been customized with an **option menu**. What we are going to do is upda data associated with a row to reflect the selection the user makes in the **option menu**. -#### Edit Column Behavior #### +#### Edit Column Behavior ![](images/media_1239422153707_display.png) @@ -1269,7 +1269,7 @@ We need to customize the column behavior. From the **Columns** pane (1) in the **Property Inspector** select the *Rating* column (2) and then click the **Column Behavior** button (3). -#### FillInData #### +#### FillInData ![](images/media_1239422182841_display.png) @@ -1277,7 +1277,7 @@ In the **FillInData** handler we are setting the **menuhistory** based on the value of *pData* that is passed in. As there is only a single button in the *Rating* column template, it can be referreed to as ***button 1 of me***. -#### menuPick #### +#### menuPick ![](images/media_1239422596775_display.png) @@ -1290,7 +1290,7 @@ the **new value**. Since the above script is in a column behavior we can use the **dgIndex of me** (1) for the **index** and the **dgColumn of me** (2) for the **column name**. -#### The Behavior in Action #### +#### The Behavior in Action Here is what the data grid's internal array looks like before making a menu selection. @@ -1301,7 +1301,7 @@ After making a selection for row 2 (1) the internal value was updated (2). ![](images/media_1239422260513_display.png) -### How Do I Refresh a Data Grid After Making Changes to a Template Through Script? ### +### How Do I Refresh a Data Grid After Making Changes to a Template Through Script? The command **ResetList** redraws a data grid after having copied in fresh copies of any templates. Here is an example of how you might use it. @@ -1322,13 +1322,13 @@ Or you can simply issue it from the message box. ![](images/datagrid_send_refresh_list.png) -### How Do I Use a Template in Multiple Data Grids? ### +### How Do I Use a Template in Multiple Data Grids? If your application needs to use the same style of data grid in multiple places in your project then you can easily share the same row template between multiple data grids. This lesson will show you how. -#### Create First Data Grid #### +#### Create First Data Grid ![](images/media_1240455722959_display.png) @@ -1338,7 +1338,7 @@ Template** that is used to draw the data grid is **dgProps["row template"]**. The message box shows a query for this property in order to get a reference to the data grids row template (2). -#### Create Other Data Grids #### +#### Create Other Data Grids Now you can add other data grids to your project. Here the second data grid is added to the same stack as the first. After adding the data grid you can set the **dgProps["row @@ -1362,7 +1362,7 @@ of a data grid in a second stack) > You may want to delete this card if you aren't going to be using that > template. -#### Result #### +#### Result ![](images/datagrid_setprops_two_stacks_1.png) @@ -1372,9 +1372,9 @@ being used in the second stack. ![](images/datagrid_setprops_two_stacks_2.png) -### How Can I See What the Data Grid's Internal Array Currently Looks Like? ### +### How Can I See What the Data Grid's Internal Array Currently Looks Like? -#### Using PrintKeys #### +#### Using PrintKeys ![](images/media_1239422249334_display.png) @@ -1387,13 +1387,13 @@ This will print the array in the message box. > a quick peek at the array. It only prints the first line of each key so > it is not a 100% accurate view of the data. -### How Do I Get Aggregate Values for Columns? ### +### How Do I Get Aggregate Values for Columns? This lesson will show you how to add a custom property to a data grid that returns the aggregate value of a column. Usually this would be used with data grid tables but works equally as well with data grid forms. -#### Add a getProp to Your Data Grid Script #### +#### Add a getProp to Your Data Grid Script ![](images/Add_A_getProp_To_Your_Data_Grid_Script_display.png) @@ -1402,7 +1402,7 @@ handler to your data grid script. In this example a custom property called **uSumOfColumn** (1) has been defined. Passing it a column name (2) returns the sum of all rows of that column (3). -#### Using the Custom Property #### +#### Using the Custom Property ![](images/Using_the_Custom_Property_display.png) @@ -1410,13 +1410,13 @@ Here is an example of using the custom property. When clicking on the button (1) the text of another field (in this case "sum") is set to the **uSumOfColumn** custom property (2). -#### The Result #### +#### The Result ![](images/The_Result_display.png) Here the result has been put into the *Sum* field. -### How Do I Determine if the Data Grid Has Focus? ### +### How Do I Determine if the Data Grid Has Focus? You can determine if the data grid has focus by performing the following check: @@ -1425,17 +1425,17 @@ check: ## Data grid has focus end if -### How Do I Export Data From a Data Grid? ### +### How Do I Export Data From a Data Grid? This lesson will show you how to get data out of a data grid. -#### The Example Data Grid #### +#### The Example Data Grid ![](images/DataGrid_Sampler_Stack.png) The data will be exported from a data grid that looks like this. -#### The Handler for Populating Data Grid #### +#### The Handler for Populating Data Grid command uiPopulatePeople put "images/" into theImageFolder @@ -1476,7 +1476,7 @@ The data will be exported from a data grid that looks like this. This is the code that was used to populate the data grid. This shows you the keys that each record has (*FirstName*, *LastName*, *Title* and *Image URL*). -#### Export Handler #### +#### Export Handler command uiExportData ## Export data to XML @@ -1512,13 +1512,13 @@ delimited list of the keys of the **dgData** in the proper order. After you have the array and the ordered list of indexes you can loop through each record in the array. In this example the data is just wrapped in XML tags. -#### Example Output #### +#### Example Output This is what the output for this example looks like in the message box. ![](images/media_1247315800246_display.png) -### How Do I Work With Checkboxes in a Data Grid? ### +### How Do I Work With Checkboxes in a Data Grid? This lesson will demonstrate how to associate the hilite state of a checkbox in a data grid with a row value in the data grid. @@ -1527,7 +1527,7 @@ checkbox in a data grid with a row value in the data grid. [Checkbox_Example.livecode](http://lessons.livecode.com/s/lessons/files/303?lesson_id=26382) -#### Adding a Checkbox to a Form #### +#### Adding a Checkbox to a Form ![](images/media_1278011173914_display.png) @@ -1536,7 +1536,7 @@ Before you begin, drag a data grid onto a stack and set the style to Click the **Row Template** button to open the template for the data grid. -#### Edit Row Template Group #### +#### Edit Row Template Group Now that the card with the data grid row template is visible, open the **Project Browser** selecting the **Tools > Project Browser** @@ -1554,7 +1554,7 @@ palette into the group. ![](images/media_1296743472921_display.png) -#### Add a Checkbox #### +#### Add a Checkbox From the **tools palette**, drag a **checkbox** onto the card and place it in the upper-left corner. The button will appear in the list of controls in @@ -1562,14 +1562,14 @@ the **Project Browser**. ![](images/media_1296743517047_display.png) -#### Edit Checkbox Properties #### +#### Edit Checkbox Properties Open the button's Property Inspector, select the **Position** pane and change the **height** to 21. Set the **left** and **top** properties to 0. ![](images/media_1296743535342_display.png) -#### Delete the Label Field #### +#### Delete the Label Field Now that you have added the checkbox button you no longer need the *Label* field in the row template. We will do this using the **Project Browser** @@ -1599,7 +1599,7 @@ After deleting the field you should have only the *Background* graphic and the ![](images/media_1296743555165_display.png) -#### Edit Row Behavior #### +#### Edit Row Behavior Next you need to edit the **Row Behavior** in order to take into account the new checkbox control. @@ -1608,7 +1608,7 @@ the new checkbox control. Click the **Edit Script** button. -#### Edit the FillInData Handler #### +#### Edit the FillInData Handler ![](images/media_1296825944670_display.png) @@ -1630,7 +1630,7 @@ row. set the hilited of button "Check" of me to pDataArray["checked"] end FillInData -#### Update LayoutControl and ResetData #### +#### Update LayoutControl and ResetData The **LayoutControl** and **ResetData** handlers also have references to the *Label* field which no longer exists. Update both of those handlers with references to the *Check* button. @@ -1663,7 +1663,7 @@ which no longer exists. Update both of those handlers with references to the *Ch set the hilite of button "Check" of me to false end ResetData -#### Update Data Grid Row Value When User Changes Checkbox State #### +#### Update Data Grid Row Value When User Changes Checkbox State When the user clicks on the checkbox the hilited state will change. You need to update the row data in the data grid when this happens so that @@ -1694,7 +1694,7 @@ script afterwards. end if end mouseUp -#### Populate the Data Grid #### +#### Populate the Data Grid You have now finished configuring the Data Grid so it is time to test. Add a button to the stack and name it **Populate grid**. @@ -1724,7 +1724,7 @@ Paste this script to the button script. set the dgData of group "DataGrid 1" to theDataA end mouseUp -#### Test #### +#### Test After compiling the script, click on the **Populate Grid** button. The card should now look similar to this. @@ -1734,7 +1734,7 @@ card should now look similar to this. Try it out. If you click on a checkbox in line 1 it should uncheck. Click on it again to check it. -#### Checking/Unchecking All Checkboxes in a Data Grid #### +#### Checking/Unchecking All Checkboxes in a Data Grid When working with lists that have checkboxes it is nice to include the option to check or uncheck all of the items in the list. Let's look at @@ -1782,7 +1782,7 @@ redraw the data grid each time it is called. end mouseUp -#### Test #### +#### Test Click the **Check/Uncheck** button to test. You should see the checkboxes toggle between the checked and unchecked state. @@ -1794,11 +1794,11 @@ see the proper values for the *checked* state of each row. ![](images/media_1296745354985_display.png) -## Working With Data Grid Tables ## +## Working With Data Grid Tables -### How Do I Change Column Alignment? ### +### How Do I Change Column Alignment? -#### Using the Property Inspector #### +#### Using the Property Inspector Select the data grid and open the **Property Inspector**. Navigate to the **Columns** pane (1), select the column you want to modify (2), and @@ -1806,7 +1806,7 @@ change the **alignment** (3). ![](images/Using_the_Property_Inspector_display.png) -#### Using Script #### +#### Using Script ![](images/media_1238000788633_display.png) @@ -1815,9 +1815,9 @@ column. set the dgColumnAlignment["Name"] of group "DataGrid" to "left" -### How Do I Sort by a Column? ### +### How Do I Sort by a Column? -#### Using the Property Inspector #### +#### Using the Property Inspector Select the data grid and open the **Property Inspector**. Navigate to the **Columns** pane (1), select the column you want to modify (2), and @@ -1826,7 +1826,7 @@ options as you see fit. ![](images/media_1236355926146_display.png) -#### Using Script #### +#### Using Script You can sort by column setting the **dgProp["sort by column"]** property of the data grid to the name of the column you want to sort by. @@ -1842,9 +1842,9 @@ Similarly you can change other properties related to the sort by script too. ![](images/media_1238000827781_display_1.png) -### How Do I Resize Columns? ### +### How Do I Resize Columns? -#### Using the Property Inspector #### +#### Using the Property Inspector ![](images/media_1236356044111_display.png) @@ -1852,7 +1852,7 @@ Select the data grid and open the **Property Inspector**. Navigate to the **Columns** pane (1), select the column you want to modify (2), and set the **width** of the column using the **Width** text entry field (3). -#### Using Script #### +#### Using Script You can set the size of a column by setting the **dgColumnWidth** property for the column to an integer. @@ -1861,7 +1861,7 @@ for the column to an integer. ![](images/media_1238000855537_display.png) -### How Do I Override the Default Behavior for Rendering Data to a Cell? ### +### How Do I Override the Default Behavior for Rendering Data to a Cell? By default, a data grid table uses a single field object for each cell in a table and assigns the **text** property of that field to the cell's @@ -1870,11 +1870,11 @@ that determines how data is rendered in the default table cell. This can be useful for rendering HTML and unicode text, trailing off text that is too wide for a column or for coloring particular cells. -#### Begin With a Data Grid Table #### +#### Begin With a Data Grid Table ![](images/media_1239940153040_display.png) -#### Create a Button #### +#### Create a Button The **default column behavior** property can be set to a button. The script of the button will be used to fill in each cell in the table. @@ -1883,7 +1883,7 @@ Drag a button onto the card and name it **My Default Column Behavior.** ![](images/My_Default_Column_Behavior.png) -#### Set the Script of the Button #### +#### Set the Script of the Button ![](images/media_1239940350693_display.png) @@ -1897,7 +1897,7 @@ and executing the following statement in the **Message Box** (2): set the script of selobj() to the script of button "Default Column" \ of stack "revDataGridLibrary" -#### Customize Behavior #### +#### Customize Behavior ![](images/media_1239940253589_display.png) @@ -1912,7 +1912,7 @@ Now this behavior can be customized. Here is what the default behavior looks lik return the long ID of me end dgDataControl -#### Set 'Default Column Behavior' Property #### +#### Set 'Default Column Behavior' Property ![](images/media_1239945029745_display.png) @@ -1926,7 +1926,7 @@ grid. Select the button (1) and execute the following in the **Message Box** Now it is time to customize your script! -#### Example: Truncate Tail #### +#### Example: Truncate Tail ![](images/media_1240836642399_display.png) @@ -1953,7 +1953,7 @@ that cell contents are truncated when drawn or when a column is resized. break end switch -#### Refresh #### +#### Refresh To see the results, click the **Refresh Data Grid** button in the Property Inspector (1). Notice how cell contents are no truncated as @@ -1961,7 +1961,7 @@ needed (2). ![](images/media_1239945061329_display.png) -#### Example: Coloring Cells #### +#### Example: Coloring Cells ![](images/media_1240836750153_display.png) @@ -1969,21 +1969,21 @@ This example will dim any cell that is empty. Since the default cell consists of a single field object this can be accomplished by setting the field's **opaque** to **true**, setting the **backgroundcolor** and changing the **blendlevel**. -#### Result #### +#### Result Deleting some entries in the data and click on the **Refresh Data Grid** button to see the result ![](images/media_1240836803830_display.png) -### How Do I Determine if a User Clicks in the Table Header? ### +### How Do I Determine if a User Clicks in the Table Header? This lesson will show you how to determine if the user clicked in the header of a Data Grid table by showing you how to use the **dgHeaderControl** and **dgHeader** properties of the target control that was clicked on. -#### The Table Header #### +#### The Table Header ![](images/media_1262013649551_display.png) @@ -1996,7 +1996,7 @@ When the user clicks on a column header (2) the **dgHeaderControl** of the target returns the **long id** of the group control that contains all of the column header controls. -####Example#### +####Example ![](images/media_1262013897208_display.png) @@ -2024,16 +2024,16 @@ header (2). ![](images/media_1262013925910_display.png) -### How Do I Display a Contextual Menu When the User Clicks on a Column Header? ### +### How Do I Display a Contextual Menu When the User Clicks on a Column Header? -####Overview#### +####Overview ![](images/media_1262014965604_display.png) This lesson will show you how to display a contextual menu (1) when the user clicks on a column header in a Data Grid table (2). -####The Code#### +####The Code ![](images/media_1262015011787_display.png) @@ -2074,20 +2074,20 @@ the popup button to display (4). end mouseDown -####The Result#### +####The Result ![](images/media_1262015029410_display.png) Now when a ***right-click*** occurs on the State column the *State Popup* popup button is displayed as a contextual menu. -### What if I Need to Work With htmlText or rtfText? ### +### What if I Need to Work With htmlText or rtfText? By default all table columns will have their **text** property assigned. If you need to work with htmltext or rtftext then you need to provide your own behavior for the table columns. -#### Option 1: Set the dgProp["Default Column Behavior"] Property #### +#### Option 1: Set the dgProp["Default Column Behavior"] Property The simplest way to change the default behavior of table columns is to set the **dgProp["default column behavior"]** property of the data grid. You @@ -2117,24 +2117,24 @@ in the **Message box**: edit script of button "Default Column" of stack "revDataGridLibrary" -#### Option 2: Create a Custom Column Template #### +#### Option 2: Create a Custom Column Template Alternatively you can create your own custom column template for a particular column. This allows you complete control over the look and feel of the column. See section [How Do I Customize A Table's Columns?](#how-do-i-customize-a-table's-columns) -### How Do I Display Line Numbers in a Table? ### +### How Do I Display Line Numbers in a Table? This lesson will show you how to dynamically display line numbers in your data grid table. -####The Table#### +####The Table ![](images/media_1236794497421_display.png) Here is the table to display line numbers in. -####Add Line Number Column#### +####Add Line Number Column ![](images/media_1237998926249_display.png) @@ -2142,7 +2142,7 @@ Select the data grid and open its **Property Inspector**. Select the **Columns** pane (1) and add a column using the "+" button (2). Rename the column **Line Number** (3). -####Reorder and Create Column Template#### +####Reorder and Create Column Template ![](images/media_1237999008350_display.png) @@ -2152,7 +2152,7 @@ list. Create a template for this column by clicking on the "+" button at the bottom of the **Property Inspector** (2). -####Edit Line Number Group#### +####Edit Line Number Group ![](images/media_1237999096660_display.png) @@ -2163,7 +2163,7 @@ has been created and within that group is a single field object. We do not need to actually do anything to the template so simply **close** and **save** it when prompted. -####Edit Column Behavior#### +####Edit Column Behavior Now all that is left is to define the behavior for this column. Go back to the **Columns** pane of the data grid's **Property Inspector** and click the @@ -2172,7 +2172,7 @@ the **Columns** pane of the data grid's **Property Inspector** and click the ![](images/media_1237998709031_display.png) -####Edit Behavior Script#### +####Edit Behavior Script ![](images/media_1239247015389_display.png) @@ -2184,19 +2184,19 @@ The **dgLine** is a property of a **row template** and this will display the lin for the current line. In **LayoutControl** you just need to ensure the rect of the field fills the entire cell (2). -####Refresh Data Grid#### +####Refresh Data Grid ![](images/media_1237998627031_display.png) In the **Property Inspector** click the Refresh Data Grid button. -####The Result#### +####The Result ![](images/media_1236795107846_display.png) Now the line numbers appear in the table. -####But How Do I Set the dgText Then?#### +####But How Do I Set the dgText Then? You may be wondering how you would set the **dgText** property of this data grid since we have added a **Line Number** column as the first column in @@ -2210,20 +2210,20 @@ the column names to your data like this: put "State" & tab & "State Code" into theColNames set the dgText [true] of group "Data Grid" to theColNames & cr & theData -### How Do I Customize Column Sorting? ### +### How Do I Customize Column Sorting? This lesson will demonstrate how to customize sorting for columns by handling the **SortDataGridColumn** message that is sent when the user clicks on a column. -####A Data Grid Table#### +####A Data Grid Table ![](images/media_1239310236534_display.png) The goal is to customize when happens when this table is sorted by the **Line Number** column. -####The Data Grid Group Script#### +####The Data Grid Group Script A Data Grid calls a built in handler **SortDataGridColumn** whenever the **dgProps ["sort by column"]** property is set. This includes when the user clicks on a column header @@ -2266,13 +2266,13 @@ that reverses whatever the current sort order is. (2) ![](images/media_1239647097509_display.png) -####The Result#### +####The Result Clicking on the **Line Number** column (1) now reverses the sort. ![](images/media_1239310720274_display.png) -####Custom Sort Example#### +####Custom Sort Example Here is another example of a custom sort. Try it out and see if you can determine what it does. @@ -2310,12 +2310,12 @@ what it does. HiliteAndStoreSortByColumn pColumn end SortDataGridColumn -### How Do I Disable Column Sorting? ### +### How Do I Disable Column Sorting? This lesson will show you how to disable column sorting in a Data Grid table. -####Sort By No Column#### +####Sort By No Column Notice in our example, the **State** column header is hilighted and there is a sorting arrow indicating an ascending sort. @@ -2334,14 +2334,14 @@ Just copy and paste the above into the **Message box** to execute it. Your table headers should now appear the same, with no highlights or sorting arrow. -####Edit Data Grid Script#### +####Edit Data Grid Script Edit the Data Grid group script by ***right clicking*** on the Data Grid and selecting **Edit Script.** ![](images/media_1264520303976_display.png) -####Add SortDataGridColumn Handler#### +####Add SortDataGridColumn Handler ![](images/media_1264520327900_display.png) @@ -2367,12 +2367,12 @@ Now when you click on the table header the data will not be sorted. >remove the **SortDataGridColumn** handler from the script, or at least **pass** >the message. -### How Do I Perform an Action After the User Sorts a Data Grid? ### +### How Do I Perform an Action After the User Sorts a Data Grid? This lesson will show you how to modify a data grid script so that you can perform an action whenever a data grid is sorted. -####Add SortDataGridColumn To Data Grid Group Script#### +####Add SortDataGridColumn To Data Grid Group Script You can customize what happens when a data grid is sort by adding a **SortDataGridColumn** handler to your data grid's script. For more @@ -2397,24 +2397,24 @@ like. ## DON'T PASS the "SortDataGridColumn" message! end SortDataGridColumn -### How Do I Align Decimals in a Column? ### +### How Do I Align Decimals in a Column? This lesson will show you how to create a custom column template that provides decimal alignment. You can [download the stack]([http://www.bluemangolearning.com/download/revolution/tools/datagrid_decimal_align.zip]) used to create this lesson. -####Create a Data Grid Table#### +####Create a Data Grid Table ![](images/media_1240457118727_display.png) -####Add Some Data#### +####Add Some Data ![](images/media_1240457166121_display.png) Here a couple of rows of decimal numbers have been added to experiment with. -####Create Column Template#### +####Create Column Template Select the **Columns** pane (1) in the **Property Inspector** and click the **Add custom column behavior** button (2). This will create a custom @@ -2426,7 +2426,7 @@ Notice how the **Column Behavior...** button has become enabled. ![](images/media_1240457183522_display_0.png) -####Edit Column Template#### +####Edit Column Template When you create a custom template for a column a new group, named after the column, is added to the data grid's **row template**. @@ -2437,7 +2437,7 @@ Here you see the **Project Browser** with the template for the Data Grid expande showing the group for this column (*Col 1*) with a field *\_ColumnData_* to hold the column's data. -####Edit Column Template Group#### +####Edit Column Template Group Double-click on the column group in the **Project Browser** (1). This will select it on the template card (2) and then click the **Edit Group** button (3) to edit the contents of the @@ -2448,7 +2448,7 @@ column group. Be sure to double-click on the **group** icon and not the group's name. Double-clicking on the object's name will simply allow you to edit the name, which is not what is wanted. -####Create 3 Fields#### +####Create 3 Fields A column that aligns decimals in the center of the column, and is editable if the user double-clicks on the cell, is achieved by creating @@ -2471,7 +2471,7 @@ repositioned when drawn in the data grid. Click on the card background of the editing template and then the **Stop Editing** button and **close** and **save** the window. -####Edit Column Behavior#### +####Edit Column Behavior ![](images/media_1240457537950_display.png) @@ -2481,7 +2481,7 @@ its time to tell the column what to do when it is drawn. Return to the click the **Column Behavior ** button (2). This will open the behavior script for the column. -####Update FillInData#### +####Update FillInData ![](images/media_1240457590402_display.png) @@ -2493,7 +2493,7 @@ decimal to the *Rightvalue* field. set the text of field "Leftvalue" of me to max(0, item 1 of pData)&"." set the text of field "Rightvalue" of me to max(0, item 2 of pData) -####Update LayoutControl#### +####Update LayoutControl ![](images/media_1240457650342_display.png) @@ -2516,7 +2516,7 @@ can double-click on to edit the cell contents. set the rect of field "ForEditing" of me to pControlRect -####Update EditValue#### +####Update EditValue **EditValue** is the handler that is called by the data grid to edit a cell value. Usually this is because the user double-clicked on the @@ -2547,7 +2547,7 @@ on the **ForEditing** field (as it has the higher layer) and it is thus end EditValue -####Refresh Data Grid#### +####Refresh Data Grid ![](images/media_1240457946816_display.png) @@ -2559,7 +2559,7 @@ click the **Refresh Data Grid** button. Alternatively you can send send "resetList" to group "datagrid 1" -####Test#### +####Test ![](images/media_1240458424026_display.png) @@ -2567,18 +2567,18 @@ The decimals all appear in the center of the cell. Double-clicking brings up an editing field as shown here. Finally the decimal remains in the center of the cell if the column is resized. -### How Can I Colorize Individual Lines in a Table? ### +### How Can I Colorize Individual Lines in a Table? This lesson will show you how to change the color of individual lines in a Data Grid table. Before you begin this lesson you will need to read the lesson [How Do I Override the Default Behavior for Rendering Data to a Cell?](#how-do-i-override-the-default-behavior-for-rendering-data-to-a-cell) -####Attached Files#### +####Attached Files [Color_Individual_Line_in_Table.rev](http://lessons.livecode.com/s/lessons/files/101?lesson_id=7332) -#### Coloring a Single Line #### +#### Coloring a Single Line ![](images/media_1249058487860_display.png) @@ -2601,7 +2601,7 @@ data to line 3. Now let's look at what the default custom column behavior looks like for this data grid. -####The Default Custom Column Behavior#### +####The Default Custom Column Behavior ![](images/media_1249059040297_display.png) @@ -2641,29 +2641,29 @@ has error** the entire row appears red. end if end SetForeGroundColor -## Working With Data Grid Forms ## +## Working With Data Grid Forms -### How Do I Create a Form With Variable Line Heights? ### +### How Do I Create a Form With Variable Line Heights? This lesson will show you how to create a data grid form with variable height lines by modifying the default data grid **Row Template** and **Row Behavior**. -#### Turn Off "Empty row height" #### +#### Turn Off "Empty row height" ![](images/media_1239376378384_display.png) To begin, turn off **Empty row height** for your data grid form in the **Property Inspector**. -####Edit Row Template#### +####Edit Row Template ![](images/media_1239375695284_display.png) Open the card that has the row template group by clicking the **Row Template** button. -####Turn Off dontWrap Property#### +####Turn Off dontWrap Property ![](images/media_1239375899522_display.png) @@ -2672,14 +2672,14 @@ displays data. With **Select Grouped** turned on (1) select the field (2). Using the **Property Inspector** turn off **dontWrap** (3). You can now close the stack. -####Edit Row Behavior#### +####Edit Row Behavior ![](images/media_1239375899522_display_x.png) Return to the Property Inspector for your data grid. Edit the **Row Behavior** by clicking on **Edit Script** button. -####Script Field to Resize to Fit Height#### +####Script Field to Resize to Fit Height Only a few modifications are needed to make to the default **LayoutControl** handler resize the field to fit the height. @@ -2715,7 +2715,7 @@ of the Background graphic to take into account the new field height (3). end LayoutControl -####Refresh Data Grid Contents#### +####Refresh Data Grid Contents You can now refresh the data grid contents to see the new behavior. @@ -2723,13 +2723,13 @@ You can now refresh the data grid contents to see the new behavior. Notice how each line is resized to fit all of the text. -### How Do I Sort Records by a Specific Key's Values? ### +### How Do I Sort Records by a Specific Key's Values? You can sort the rows of a data grid form using the **SortDataByKey** command. Let's look at an example. -####Example#### +####Example ![](images/media_1242529496945_display.png) @@ -2737,7 +2737,7 @@ This card has a data grid and an option menu. The option menu contains three values that you can sort by: *First Name*, *Last Name* and *Title*. -####Option Menu Code#### +####Option Menu Code The code to perform the sort is pretty straight forward. @@ -2772,23 +2772,23 @@ property then the key will be "Label 1" or "Label 2", etc. end menuPick -####The Result#### +####The Result ![](images/media_1242529778033_display.png) Here is what the sort looks like after selecting *First Name* and after selecting *Last Name*. -### How Do I Create Rows That Can Expand/Contract? ### +### How Do I Create Rows That Can Expand/Contract? This lesson will show you how to make a Data Grid form with rows that expand and contract when clicking on an arrow. -#### Attached Files #### +#### Attached Files [ExpandingRow.rev](http://lessons.livecode.com/s/lessons/files/45?lesson_id=9850) -####Expanding and Contracting Rows#### +####Expanding and Contracting Rows ![](images/media_1265663660291_display.png) @@ -2800,7 +2800,7 @@ are contracted and only show names. Clicking on the arrow next to a name expands the row to show the description of the person. -####Setting the Data Grid Properties#### +####Setting the Data Grid Properties To create a Data Grid form with rows that expand/contact you need to turn off **fixed control height** in the data grid's **Property Inspector**. @@ -2810,7 +2810,7 @@ turn off **fixed control height** in the data grid's **Property Inspector**. >**Note**: To turn off the property using script you set the >**dgProp["fixed row height"]** property to **false**. -####Updating the Row Behavior Script#### +####Updating the Row Behavior Script In order to get expanding rows working a couple of things need to be taken into account in the **Row Behavior Script.** @@ -2847,7 +2847,7 @@ be in its **expanded** state as per the **FillnData** handler. Thus this little snippet effectively toggles the state of the row. -### How Can I Speed Up Drawing When "Fixed Row Height" Is False? ### +### How Can I Speed Up Drawing When "Fixed Row Height" Is False? When you set the **dgProp["fixed row height"]** property of a Data Grid to **false** the Data Grid must draw all records in order to determine the @@ -2859,7 +2859,7 @@ This lesson will show you a technique that can speed up the calculation of the total height of the data in situations where the rows can only have heights of ***known*** values. -#### CalculateFormattedHeight #### +#### CalculateFormattedHeight When the Data Grid loops through the data to calculate the height the message **CalculateFormattedHeight** will be sent to the **Row Template**. @@ -2883,9 +2883,9 @@ the **CalculateFormattedHeight** handler in your Row Behavior script. ... end FillInData -## Using the Built-in Field Editor ## +## Using the Built-in Field Editor -### How Do I Open a Table Cell for Editing? ### +### How Do I Open a Table Cell for Editing? By default a table cell can be edited if the user double-clicks on the cell. This tutorial explains what goes on in the default column behavior @@ -2895,7 +2895,7 @@ so you can customize behavior if you would like. >of stack "**revDataGridLibrary**". >See [How Do I Override the Default Behavior for Rendering Data to a Cell?](#how-do-i-override-the-default-behavior-for-rendering-data-to-a-cell) -#### What You Need to Know #### +#### What You Need to Know In order to edit the columns of a data grid table you need to know about the following: @@ -2908,20 +2908,20 @@ the following: Read up on the entries for **EditFieldText**, **EditValue**, **EditCell**/**EditCellOfIndex** in the API section of the Dictionary. -####EditFieldText#### +####EditFieldText The **EditFieldText** command will create an editor for a field that you specify. The default column behavior calls this command with three parameters so that data is automatically saved after the user finishes editing. -####EditValue#### +####EditValue **EditValue** is the message that is sent to a row when a request to edit a field's contents has been made. The default column behavior calls **EditFieldText** when this message is received. -####EditCell and EditCellOfIndex#### +####EditCell and EditCellOfIndex There are two commands that will open a cell for editing. They are **EditCell** and **EditCellOfIndex**. Each takes the name of the column @@ -2947,7 +2947,7 @@ Either of the above calls will trigger the **EditValue** message. end EditValue -#### CloseFieldEditor #### +#### CloseFieldEditor If the user changes any content in the field editor this message will be sent to the field targeted in the first parameter sent to **EditFieldText**. @@ -2963,12 +2963,12 @@ required if you only passed in one parameter to **EditFieldText**. set the dgDataOfIndex[theIndex] of the dgControl of me to theDataA end CloseFieldEditor -### How Can the User Edit Field Content in a Data Grid Form? ### +### How Can the User Edit Field Content in a Data Grid Form? The data grid commands for creating an editor for a particular field in a row template. This lesson will show you how to use them. -####What You Need to Know#### +####What You Need to Know In order to edit field contents in a data grid form you need to know about the following: @@ -2980,19 +2980,19 @@ about the following: Read up on the entries for **EditFieldText**, **EditValue** and **EditKey**/**EditKeyOfIndex** in the API documentation. -####EditFieldText#### +####EditFieldText The **EditFieldText** command will create an editor for a field that you specify. You can use this command to create a field editor for a field in your row template. -####EditValue#### +####EditValue **EditValue** is the message that is sent to a row when a request to edit a fields contents has been made. You can call **EditFieldText** from within a handler for this message to begin an editing operation. -####EditKey and EditKeyOfIndex#### +####EditKey and EditKeyOfIndex **EditKey** and **EditKeyOfIndex** will trigger the **EditValue** message in a row. Each takes the name of the key you want to edit and the line or index @@ -3038,7 +3038,7 @@ EditFieldText. dgHilitedIndex of me, pKey end EditValue -#### CloseFieldEditor #### +#### CloseFieldEditor If the user changes any content in the field editor this message will be sent to the field targeted in the first parameter sent to **EditFieldText**. @@ -3059,7 +3059,7 @@ This example script would be in the **Row Behavior** script as it uses the set the dgDataOfIndex[theIndex] of the dgControl of me to theDataA end CloseFieldEditor -### How Can I Edit the Text as UTF-8, UTF-16 or HTML? ### +### How Can I Edit the Text as UTF-8, UTF-16 or HTML? The default Data Grid behavior when editing cell contents is to use the **text** property of the cell as the default value to be edited. This @@ -3069,7 +3069,7 @@ to use as the value to edit. The technique described requires that you create a custom column behavior as outlined in the lesson [How Do I Override the Default Behavior For Rendering Data to a Cell ](#how-do-i-override-the-default-behavior-for-rendering-data-to-a-cell). -####The Default Behavior#### +####The Default Behavior Assume you have a column in your table that displays text with some styling. In this example the last name in column 2 for **some** entries is italic. @@ -3087,7 +3087,7 @@ default. ![](images/media_1266461620275_display.png) -####Changing the Default Value For the Editor#### +####Changing the Default Value For the Editor You can change the default value of that the field editor uses by setting a value of the **dgTemplateFieldEditor** property of the Data Grid. @@ -3104,14 +3104,14 @@ of the column being edited: Other properties you can set include **rtftext**, **text**, **unicodetext** and **utf8text**. -#### The Result #### +#### The Result ![](images/media_1266461633668_display.png) Here is the result of using the example code above in the custom column behavior. Notice how the text being edited is bold. -### How Can I Select the Text in the Edit Field When It Opens? ### +### How Can I Select the Text in the Edit Field When It Opens? The default Data Grid behavior when editing cell contents is to put the cursor at the end of the field. This lesson will show how to tell @@ -3147,9 +3147,9 @@ column behavior. Just place the code right before the call to ![](images/media_1266460876219_display.png) -### How Do I Save Changes the User Makes in an Editor Field to an External Data Source? ### +### How Do I Save Changes the User Makes in an Editor Field to an External Data Source? -#### When Calling EditFieldText With 3 Parameters (Simpler) #### +#### When Calling EditFieldText With 3 Parameters (Simpler) When calling **EditFieldText** with all three parameters (which is what a data grid column does by default) the data grid will automatically save @@ -3173,7 +3173,7 @@ Here is an example script that goes in the Data Grid group script. end CloseFieldEditor -#### When Calling EditFieldText With 1 Parameter (More Flexible) #### +#### When Calling EditFieldText With 1 Parameter (More Flexible) If you are working with data grid forms or decide to override the default behavior for data grid columns then you will make the call to @@ -3208,14 +3208,14 @@ Here is an example script that goes in the Data Grid group script. set the dgDataOfIndex[the dgIndex of the target] of me to theDataA end CloseFieldEditor -### How Can I Customize the Field Editor Behavior? ### +### How Can I Customize the Field Editor Behavior? By default the Data Grid field editor allows users to enter data and save it back to the Data Grid. If you need data entry to behave differently you can assign your own behavior script to the field editor before it opens. This lesson will show you how. -####Create Your Behavior Script#### +####Create Your Behavior Script ![](images/media_1251992093862_display.png) @@ -3225,7 +3225,7 @@ field editor. Here it is placed on the same card as the data grid. "revDataGridLibrary". This is the behavior script that Data Grid uses by default and is a good place to start when customizing the behavior. -####Customize Your Script#### +####Customize Your Script Open the button's script... @@ -3233,7 +3233,7 @@ Open the button's script... Make any customizations you need to make. -####Assign Your Custom Behavior to Field Editor#### +####Assign Your Custom Behavior to Field Editor Whenever the Data Grid displays the field editor (e.g. the user double-clicks on a cell in a table) a **preOpenFieldEditor** message is @@ -3243,15 +3243,15 @@ field. ![](images/media_1251992186932_display.png) -## Building Standalones With the Data Grid ## +## Building Standalones With the Data Grid -### What Do I Need to Do to Deploy a Standalone With a Data Grid? ### +### What Do I Need to Do to Deploy a Standalone With a Data Grid? A data grid relies on the stack **revDataGridLibrary** in order to function properly. This lesson will describe how to include this stack in your standalone applications. -####How The Standalone Builder Adds The Necessary Files#### +####How The Standalone Builder Adds The Necessary Files When you add a data grid to a stack, a substack is created whose name begins with "Data Grid Templates". @@ -3265,7 +3265,7 @@ whose name begins with "Data Grid Templates". If it finds one then the ![](images/media_1237996920279_display.png) -####But What About Launcher Stacks (Splash Stacks)?#### +####But What About Launcher Stacks (Splash Stacks)? Some developers prefer to use a launcher (or splash) stack technique. This technique builds a standalone using a stack with very little code @@ -3290,17 +3290,17 @@ checkbox (2) to include it. ![](images/media_1237996920279_display_1.png) -##Useful Things to Know ## +##Useful Things to Know ### What Sorts of Things Should I Not Do in Order to Avoid Needless -### Suffering? ### +### Suffering? There are some things that you could do that will cause you to scratch your head when things go wrong. Since knowing is half the battle we will share the issues we are aware of. #### Don't Call a Handler That Redraws the Data Grid From Within a -#### Control in the Data Grid #### +#### Control in the Data Grid This will generate an error since you are deleting a control that is currently executing code. This is a no-no and the LiveCode engine will @@ -3325,13 +3325,13 @@ or b) placing the code in the data grid script itself. end mouseUp -####Don't try to draw a Data Grid on a card that Is not open#### +####Don't try to draw a Data Grid on a card that Is not open When a Data Grid renders, it dynamically creates fields and accesses certain properties. Some of these properties can not be properly reported by the LiveCode engine unless the field is on an open card. -####Do not lock messages when accessing data grid properties.#### +####Do not lock messages when accessing data grid properties. If messages are **locked** when you try to access a data grid property, for example @@ -3341,21 +3341,21 @@ the correct value will not be returned/set. A Data Grid relies on getProp/setProp handlers to function. When messages are locked these are not triggered. -####Do not password protect the Data Grid Templates Stack#### +####Do not password protect the Data Grid Templates Stack The data grid copies the templates from the **Data Grid Templates xxxx** stack. If you password protect this stack then the data grid will be unable to copy the templates. -####Don't Rename the "Data Grid Templates" Stack#### +####Don't Rename the "Data Grid Templates" Stack If you rename this stack then all of your data grids with templates stored in the stack will stop working. Since the data grid can no longer locate the custom templates they will fail to draw properly. -####Don't Try to Search When Data is Being Loaded From an External Source#### +####Don't Try to Search When Data is Being Loaded From an External Source -####Stop Editing the Template Group Before Drawing Your Data Grid#### +####Stop Editing the Template Group Before Drawing Your Data Grid When you **edit** a group in LiveCode the engine no longer knows that the group exists. If you try to draw a data grid while editing it's template @@ -3363,9 +3363,9 @@ group then the data grid will fail to draw. Make sure you have selected **Stop Editing** from the **Object** menu or clicked on the **Stop Editing** icon on the **Toolbar.** -## Advanced Options ## +## Advanced Options -### Displaying Large Amounts of Data ### +### Displaying Large Amounts of Data Setting the **dgText** property or creating an array and setting the **dgData** property of a data grid is the easiest way to display your data. But @@ -3377,12 +3377,12 @@ Download the attached sample stack and database that shows how to use the techniques described in this lesson to display data from a SQLite database. -####Attached Files#### +####Attached Files [datagrid_databases.zip](http://lessons.livecode.com/s/lessons/files/ 1077?lesson_id=7341) -####The dgNumberOfRecords Property#### +####The dgNumberOfRecords Property Normally a data grid reports the number of records based on the number of numeric indexes in the first dimension of the **dgData** array. If you @@ -3395,7 +3395,7 @@ display data in a line. >displaying records from your data source. It does not store any of that >data internally. -####GetDataForLine Callback#### +####GetDataForLine Callback ![](images/GetDataForLine_Callback_display.png) @@ -3413,11 +3413,11 @@ You can define this handler in the data grid script or anywhere else in the message path. Just fill in pDataA with the appropriate data and the data grid will display it. -### Creating a Data Grid by Hand ### +### Creating a Data Grid by Hand This lesson will show you how to create a data grid through script. -####Copy Data Grid From revDataGridLibrary#### +####Copy Data Grid From revDataGridLibrary The data grid template is stored in the **revDataGridLibrary** stack and can be copied using some code similar to this: @@ -3426,11 +3426,11 @@ be copied using some code similar to this: to card "MyCard" of stack "MyStack" put it into theDataGridRef -####Set The "style" Property#### +####Set The "style" Property set the dgProp["style"] of theDataGridRef to "table" or "form" -####Assign a Row Template#### +####Assign a Row Template set the dgProp["row template"] of theDataGridRef \ to the long id of group "MyRowTemplate" of stack "MyStack" @@ -3440,13 +3440,13 @@ example, you could create a data grid and then delete it while leaving the row template behind (it will exist on a card in "Data Grid Templates xxx" stack). -### How Do I Create a Datagrid Dynamically From Tab Delimited Data ### +### How Do I Create a Datagrid Dynamically From Tab Delimited Data Most of the lessons show how to use and change previously created data grids, and assume you want to create them in the IDE. This lesson will explain how to create a table data grid by script. -#### Prepare Your Data #### +#### Prepare Your Data To make sure that the data grid can accept your tabular data, you should prepare it with these points in mind: @@ -3505,7 +3505,7 @@ Here is how you could do that: set the dgProp["Row Template"] of group "my Datagrid" to the \ long id of group "Row Template" of stack theName -#### Fill in Your Data #### +#### Fill in Your Data As a last step, you will want to insert the prepared data into the data grid. Again, this assumes that the first row of your data contains an @@ -3516,7 +3516,7 @@ unique description for each column: set the dgText[firstLineIsNames] of group "my DataGrid" to theData -#### Prepare the Columns of the Data Grid #### +#### Prepare the Columns of the Data Grid Because you are creating the datagrid from arbitrary data, you will also need to ***dynamically create*** all necessary columns. To do that you @@ -3589,9 +3589,9 @@ handler into a button of an empty stack, and click on it with the set the dgText[firstLineAreNames] of group "my DataGrid" to theData end mouseUp -## Data Grid Tips & Tricks ## +## Data Grid Tips & Tricks -### How Do I Scroll a Row to the Top of the Data Grid Form? ### +### How Do I Scroll a Row to the Top of the Data Grid Form? This lesson will show you how to scroll a particular row to the top of the Data Grid form using the **dgRectOfIndex** (or **dgRectOfLine**) property. This technique is useful when your @@ -3602,7 +3602,7 @@ rows are not a fixed height. Here is selected row in a data grid (1). The goal is to scroll that row to the top of the data grid (2). -####How To Do It#### +####How To Do It Here is the code that will scroll the selected line to the top of the data grid. @@ -3614,13 +3614,13 @@ Here is the code that will scroll the selected line to the top of the data grid. put item 2 of theGridRect - item 2 of theControlRect into theOffset set the dgVScroll of group "DataGrid" to the dgVScroll of group "DataGrid" - theOffset -#### The Result #### +#### The Result ![](images/media_1245509169836_display.png) After executing the code the row will have been moved to the top of the data grid. -### How Do I Find Out Which Line the Mouse Is Over? ### +### How Do I Find Out Which Line the Mouse Is Over? Each data grid row has a **dgDataControl** property that returns the **long id** of the control. Each control also has a **dgLine** and **dgIndex** property. You can combine @@ -3632,12 +3632,12 @@ the two in order to identify the control the mouse is over. end if -### Converting a Database Cursor to a Data Grid Array ### +### Converting a Database Cursor to a Data Grid Array This lesson demonstrates a handler that will convert a database cursor into an array that you can use to set the **dgData** property of a data grid. -####The Handler#### +####The Handler command ConvertSQLCursorToArray pCursor, @pOutArrayA local i,j @@ -3673,7 +3673,7 @@ The handler then steps through the database cursor restructuring the data into a multidimensional array that can be used by the data grid. -####How to use#### +####How to use You can call this command as follows. @@ -3688,7 +3688,7 @@ If theError is empty then dimension 1 of *theDataA* will contain integers from 1 number of records in the cursor (**revNumberOfRecords**). Each 1st dimension, in turn, has a key for each column in the cursor (**revDatabaseColumnNames**). -####Example#### +####Example Here is what the array might look like if your cursor had 2 columns (id and name) and 3 rows. diff --git a/Documentation/guides/LiveCode Script.md b/Documentation/guides/LiveCode Script.md index 4f2d1b6075..58d48fafb1 100644 --- a/Documentation/guides/LiveCode Script.md +++ b/Documentation/guides/LiveCode Script.md @@ -364,10 +364,10 @@ The User Guides are a complete reference to LiveCode. They detail what the dialo RevOnline gives you the opportunity to upload and share your projects as well as download those created by other members of the LiveCode online -community. It can be accessed via the RevOnline button located in the +community. It can be accessed via the Sample Stacks button located in the menu bar. The main interface can be seen below: -![](images/image13.png) +![](images/revonline-main.png) The interface is designed to organise the online content into various categories to aid you in finding the kind of content you wish to @@ -378,7 +378,7 @@ using a lower level language. A code snippet is a portion of LiveCode script that you can paste into and incorporate into your own projects. The results of searching or browsing through the RevOnline content are -displayed in the *search list* area. This is an explaination of the +displayed in the *search list* area. This is an explanation of the controls you can use to adjust the parameters of your search: |  |  | @@ -391,18 +391,18 @@ controls you can use to adjust the parameters of your search: | **View mode** | The search list area can be viewed in two modes, a vertical scrolling list or a grid. In “list” mode 10 results will be displayed per page, in “grid” mode the number of results displayed will be dependent upon the size of the RevOnline stack. Whilst in “grid” mode the *viewing pane* area will not be visible. | | **User filter** | If you apply user filter to a search, the user’s name will appear above the type and tag lists (see below), subsequently only content by that user will be returned in the search results. Clicking on the button or text of the user filter will remove it. | -![](images/image14.png) +![](images/revonline-user-filter.png) The *search list* area displays a preview of the results your search has returned. At the top of this list you will see the *page controls* which allow you to navigate forwards and backwards through the pages of your search should it return more results than can be displayed on one page. -![](images/image15.png) +![](images/revonline-page-list.png) An example of the search list previews can be seen below: -![](images/image16.png) +![](images/revonline-list-preview.png) At the top of the preview is the content’s name. You can also see its average user rating out of five stars, the total number of times it has @@ -428,7 +428,7 @@ in the *viewing pane*. The *viewing pane* displays detailed information on users and uploads. -![](images/image20.png) +![](images/revonline-view-pane.png) If you are a viewing stack details as shown above, in addition to the information provided by the preview you will also see a headline, @@ -463,7 +463,8 @@ text feedback in response to the operations you perform such as In the top right corner of RevOnline you will find the *login controls* which will display your current login status as shown below: -![](images/image22.png) +![](images/revonline-login-status-not-logged-in.png) +![](images/revonline-login-status-logged-in.png) In order to upload, rate and tag content in RevOnline you must have an account, this account is also required for making comments in the wiki @@ -475,7 +476,7 @@ must hit the activation link in the email before your account can be accessed. Once activated, you can login to your account using the “Log In” control pictured above which will bring up the following dialog: -![](images/image23.png) +![](images/revonline-login-dialog.png) The “Remember me” check box will cause RevOnline to maintain your username in the “Email :” field between login attempts. The “Sign in @@ -491,7 +492,7 @@ opportunity to enter information about into the highlighted fields and change your profile picture using the *change profile picture* control as shown below: -![](images/image24.png) +![](images/revonline-account-details.png) Clicking on the *change profile picture* control will bring up the following dialog: @@ -519,7 +520,7 @@ To upload content to RevOnline simply click on the “upload content” in the *login controls,* you will then be presented with the content browser view. -![](images/image26.png) +![](images/revonline-content-browser-code.png) Clicking on the tabs at the top of this view will change the content type. Above you can see the code snippet view, it simply requires you to @@ -533,7 +534,7 @@ to upload (shown below). The default file types for extensions on each platform are; “.dll” for Windows , “.bundle” for Mac OS X and “.so” for Linux. -![](images/image27.png) +![](images/revonline-content-browser-external.png) When uploading a code snippet or external RevOnline will place the code or file into an installer stack. The installer stacks give you the @@ -553,9 +554,9 @@ Whenever you are viewing content that you have uploaded or your own profile whilst logged in the edit controls will appear above the *viewing pane*, shown below: -![](images/image28.png) +![](images/revonline-edit-stack.png) -By clicking on the “edit profile” or “edit content” (for stacks etc.) +By clicking on the “edit profile” or “edit stack” (for stacks etc.) button you are entering edit mode which allows you to make changes to the information shown. When editing your profile you can simply save or discard the changes you have made. When editing an upload you have the @@ -567,11 +568,14 @@ present you with the content browser view discussed earlier. After you have chosen a replacement file you need to save your changes in order for the new file to be submitted. -![](images/image29.png) +![](images/revonline-edit-content-controls.png) The list of tags applied to your own uploads can be altered by using the -“Add/Delete tags” control (shown above) which will bring up the -following dialog: +“Add/Delete tags” control + +![](images/revonline-add-delete-tags.png) + +which will bring up the following dialog: ![](images/image30.png) @@ -588,7 +592,7 @@ can submit your changes by clicking the ok button. Additional options for the RevOnline interface can be set in the RevOnline tab of the preferences stack. As pictured below: -![](images/image31.png) +![](images/revonline-preferences.png) Here you can set the remember password and user name preferences and change your password to one of your choosing. The search results in @@ -989,9 +993,7 @@ With LiveCode’s built in *Database Library*, your application can communicate with external SQL databases. You can get data from single-user and multi-user databases, update data in them, get information about the database structure, and display data from the -database in your stack. With the Database Query Builder, you can -automate the process of querying a database and populating fields with -the data, with no coding required. +database in your stack. For more details on working with databases, see the *Working with Databases* guide. @@ -1046,7 +1048,7 @@ briefly on some tips for good user interface design. The main tools palette allows you to change between Edit and Run mode, create objects, and edit bitmap images with the paint tools. -![](images/image54.png) +![](images/script-build-ui-tools-palette.png) Figure 13 - The Main Tools Palette @@ -1070,7 +1072,7 @@ sections of the tools palette. #### Alignment & Layering -![](images/image55.png) +![](images/script-build-ui-size-position.png) Figure 14 – Size & Position Inspector @@ -1086,7 +1088,7 @@ Figure 14 – Size & Position Inspector Use the Align Objects Inspector to resize objects relative to other objects, to reposition objects and/or to relayer objects. -![](images/image56.png) +![](images/script-build-ui-align-objects.png) Figure 15 – Align Objects Inspector @@ -1201,7 +1203,10 @@ document window. It can be interleaved with other windows, and you can use any of LiveCode's tools to create, select, move, or delete objects in the stack. -![](images/image57.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-editable-stack-mac.png) | ![](images/script-build-ui-editable-stack-win.png) | ![](images/script-build-ui-editable-stack-linux.png) | +| Mac | Windows | Linux | Figure 16 – Editable Document Windows on Multiple Platforms @@ -1228,7 +1233,11 @@ windows, they can be interleaved with other windows in the application. Their appearance may differ slightly from the appearance of editable windows, depending on the platform. -![](images/image58.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-modeless-stack-mac.png) | ![](images/script-build-ui-modeless-stack-win.png) | ![](images/script-build-ui-modeless-stack-linux.png) | +| Mac | Windows | Linux | + Figure 17 – Modeless Dialog Boxes on Multiple Platforms @@ -1255,7 +1264,10 @@ using the tools in the Tools palette. While a modal dialog box is being displayed, the handler that displayed it pauses until the dialog box is closed. -![](images/image59.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-modal-stack-mac.png) | ![](images/script-build-ui-modal-stack-win.png) | ![](images/script-build-ui-modal-stack-linux.png) | +| Mac | Windows | Linux | Figure 18 – Modal Dialog Boxes on Multiple Platforms @@ -1283,7 +1295,11 @@ A palette has a slightly different appearance, with a narrower title bar than an editable window. Like dialog box windows, a palette does not allow use of tools other than the Browse tool. -![](images/image60.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-palette-stack-mac.png) | ![](images/script-build-ui-palette-stack-win.png) | ![](images/script-build-ui-palette-stack-linux.png) | +| Mac | Windows | Linux | + Figure 19 – Palette Windows on Multiple Platforms @@ -1317,7 +1333,11 @@ operating system. However, if you do require more flexibility than is provided in this dialog, you should create your own modal dialog box instead (see above). -![](images/image61.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-ask-dialog-mac.png) | ![](images/script-build-ui-ask-dialog-win.png) | ![](images/script-build-ui-ask-dialog-linux.png) | +| Mac | Windows | Linux | + Figure 20 – Ask Question Dialog Boxes on Multiple Platforms @@ -1361,7 +1381,11 @@ dialog, the font, object positions, button order and icon will do require more flexibility than is provided in this dialog, you should create your own modal dialog box instead (see above). -![](images/image63.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-answer-dialog-mac.png) | ![](images/script-build-ui-answer-dialog-win.png) | ![](images/script-build-ui-answer-dialog-linux.png) | +| Mac | Windows | Linux | + Figure 22 – Answer Dialogs on Multiple Platforms @@ -1458,7 +1482,7 @@ For complete details on the syntax, see answer folder in the The **answer color** dialog allows you to display the operating system’s standard color picker dialog. -![](images/image67.png) +![](images/script-build-ui-answer-color.png) Figure 26 – Answer color dialog for choosing a color @@ -1499,7 +1523,7 @@ window to block as a dialog, float as a palette, etc. > methods of dragging and closing the window if you want the user to be > able to do these tasks. -![](images/image70.png) +![](images/script-build-ui-window-shape.png) Figure 29 – Window with alpha mask applied @@ -1513,7 +1537,7 @@ all windows on the screen, not just the windows in its application. Use system palettes for utilities that you want the user to be able to see and access in every application. -![](images/image71.png) +![](images/script-build-ui-system-window.png) Figure 30 – System Window floating above other applications @@ -1525,46 +1549,6 @@ Using this feature overrides the stack's **style** or **mode**. The system palette style is currently not supported on Linux & Unix. -#### Sheet dialog boxes – Mac OS X only - -A sheet is like a modal dialog box, except that it is associated with a -single window, rather than the entire application. A sheet appears -within its parent window, sliding from underneath the title bar. While -the sheet is displayed, it blocks other actions in its parent window, -but not in other windows in the application. - -To display a stack in a sheet dialog box, you use the **sheet** command: - - sheet "My Stack" -- appears in defaultStack - sheet "My Stack" in stack "My Document" - -> **Note:** Note the **answer**, **answer file**, **answer folder**, -> **ask**, **ask file**, and **answer folder** commands (see above) all -> include an ...as sheet form, so you can display these dialog boxes as -> sheets on Mac OS X. You can safely use the ‘as sheet’ form on -> cross-platform application as on systems other than OS X, the -> **sheet** command displays the stack as an ordinary modal dialog box. - -#### Drawers – Mac OS X only - -A drawer is a subwindow that slides out from underneath one edge of a -window, and slides back in when you close it. You usually use a button -in the main window to open and close a drawer. - -To display a stack as a drawer, you use the **drawer** command: - - drawer "My Stack" at left *-- of defaultStack* - drawer "My Stack" at bottom of stack "My Document" - -On systems other than OS X, the **drawer** command displays the stack as -an editable window. Because this does not map well to other platforms, -we recommend you only use drawers for applications that are only being -developed for Mac OS X. - -Use drawers to hold settings, lists of favorites, and similar controls -that are accessed frequently but that don't need to be constantly -visible. - #### Stack menus – for displaying non-standard menus > **Note:** Usually a menu in a LiveCode application is implemented as a @@ -1618,7 +1602,12 @@ platform. A button is a clickable object that is typically for allowing a user to perform an action by clicking. -![](images/image73.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-standard-button-mac.png) | ![](images/script-build-ui-standard-button-win.png) | ![](images/script-build-ui-standard-button-linux.png) | +| ![](images/script-build-ui-default-button-mac.png) | ![](images/script-build-ui-default-button-win.png) | ![](images/script-build-ui-default-button-linux.png) | +| ![](images/script-build-ui-rectangle-button-mac.png) | ![](images/script-build-ui-rectangle-button-win.png) | ![](images/script-build-ui-rectangle-button-linux.png) | +| Mac | Windows | Linux | Figure 32 – Button Objects on Multiple Platforms @@ -1632,7 +1621,11 @@ options may be turned on and others may be off. > a group. For more details on groups, see the section on > *Groups and Backgrounds*. -![](images/image74.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-check-box-mac.png) | ![](images/script-build-ui-check-box-win.png) | ![](images/script-build-ui-check-box-linux.png) | +| ![](images/script-build-ui-radio-button-mac.png) | ![](images/script-build-ui-radio-button-win.png) | ![](images/script-build-ui-radio-button-linux.png) | +| Mac | Windows | Linux | Figure 33 – Check Boxes and Radio Buttons on Multiple Platforms @@ -1967,7 +1960,14 @@ For more details on working with and scripting menus in general, see the section *Working with Menus* in the *Programming a User Interface* guide. -![](images/image82.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-pulldown-menu-mac.png) | ![](images/script-build-ui-pulldown-menu-win.png) | ![](images/script-build-ui-pulldown-menu-linux.png) | +| ![](images/script-build-ui-option-menu-mac.png) | ![](images/script-build-ui-option-menu-win.png) | ![](images/script-build-ui-option-menu-linux.png) | +| ![](images/script-build-ui-combo-box-mac.png) | ![](images/script-build-ui-combo-box-win.png) | ![](images/script-build-ui-combo-box-linux.png) | +| ![](images/script-build-ui-popup-menu-mac.png) | ![](images/script-build-ui-popup-menu-win.png) | ![](images/script-build-ui-popup-menu-linux.png) | +| Mac | Windows | Linux | + Figure 41 – Menu Controls @@ -1996,7 +1996,11 @@ groups as these can display a built-in scroll bar.) Sliders and scrollbars can be displayed both horizontally and vertically – to display vertically, resize so that the height is greater than the width. -![](images/image84.png) +|  |  |  | +|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](images/script-build-ui-progress-bar-mac.png) | ![](images/script-build-ui-progress-bar-win.png) | ![](images/script-build-ui-progress-bar-linux.png) | +| ![](images/script-build-ui-scrollbar-mac.png) | ![](images/script-build-ui-scrollbar-win.png) | ![](images/script-build-ui-scrollbar-linux.png) | +| ![](images/script-build-ui-slider-mac.png) | ![](images/script-build-ui-slider-win.png) | ![](images/script-build-ui-slider-linux.png) | Figure 43 – Scrollbars @@ -2011,7 +2015,7 @@ details, see the section on *Programming a User Interface*. Choose **Tools -\> Menu Builder** to open the Menu Builder. -![](images/image85.png) +![](images/script-build-ui-menu-builder.png) Figure 44 – Menu Builder @@ -2028,7 +2032,7 @@ Figure 44 – Menu Builder Use the Geometry Manager to specify how objects should be scaled and positioned when the user resizes the window. -![](images/image86.png) +![](images/script-build-ui-geometry-manager.png) Figure 45 – The Geometry Manager @@ -2040,39 +2044,6 @@ Figure 45 – The Geometry Manager | **Limit settings** | Allows you to set the minimum and maximum possible widths and heights for the object. | | **Remove All** | Removes all Geometry settings from the control. Use this option if the settings you have applied do not give the desired effect and you want to start over. | -The Geometry Card Settings options can be accessed from within the Card -Property Inspector. Use these options to determine how Geometry is -applied to the controls within the current card. - -![](images/image87.png) - -Figure 46 – Geometry Card Settings - -|  |  | -|------------------------------------------|-----------| -| **Add to cards virtual width or height** | Use this option to implement a layout that allows a section of optional controls to be folded out. The Geometry manager will ignore the extra height or width pixels specified in this area, resizing objects as if that area of the card has not been "expanded". Normally these values are set by script as the window is resized to fold out additional controls. To set these properties by script, set the **cREVGeneral["virtualWidth"]** or **cREVGeneral["virtualHeight"]** card properties. | -| **Update before opening card** | Causes the objects to be resized when navigating to the card if the window has been resized while on another card. This option is not needed if the controls are contained within a background that has already been correctly resized to the current window dimensions. | - -### Using Property Profiles - -Use Property Profiles to store different sets of properties in a single -object. Property Profiles can be used to provide *localized* versions of -your application, or different *themes* or skins. - -![](images/image88.png) - -Figure 47 – Property Profiles - -|  |  | -|------------------------------------|-----------------| -| **Create, delete or set Profiles** | The icons from left to right allow you to *duplicate*, *delete* or*create* a new profile for the currently selected object. The *Set all* button allows you to set all the objects on the current card or stack to the profile currently selected in Profile selector area.

When creating a new profile, ensure you choose a name that is *valid as a variable* and not a reserved LiveCode word. Use consistent names to allow you to create a theme or language and set all the objects in your card or stack to the same profile.

When you create a new profile, LiveCode automatically switches the object to use that profile. There are two ways to include new property settings in a profile: by using the property inspector to specify the properties you want to include, and by changing the properties directly while the profile is active.

If you make changes to the properties of the object, the profile editor will track the changes and save those into the current Profile. Any properties that have not been set for the current profile will be *inherited* from the Master profile. The profiles system supports all common object properties including styled text and Geometry information. However it does not store properties that duplicate each other (e.g. only the `rect`value will be stored, not the object’s left, right or other location properties). Scripts and custom properties are also not stored by the profile editor. You can however write scripts that first check what profile is in use on the object before taking an action by checking the `revProfile` property of the object.

You can set profiles by script by setting the `revProfile` property. To set the entire card, stack or stack file, use `revSetcardProfile`, revSetStackProfile or `revSetStackFileProfile`commands respectively. To turn on the storage of new properties in the current profile and thus change profiles more rapidly, toggle the g`revProfile`ReadOnly global. | -| **Profile selector** | Select a profile to change all the object’s properties to the values contained in that profile. Click the currently selected profile to update the list of properties stored for it. | -| **Profiles properties** | Displays a list of all properties that have been changed in the currently selected profile, and thus have a value unique to this profile. Select a property to see its contents. Press the *plus* icon to manually *add* a new property to the current profile. Delete the property from the current profile using the *delete* icon. | -| **Property contents** | View and edit the contents of the currently selected property associated with the currently selected profile.

The Add Property dialog box lists all applicable properties, but the Property Profiles pane automatically eliminates redundant properties and property synonyms. For example, if you add the `backgroundColor`and foregroundColor properties, the Property Profiles pane displays the `colors`property instead the next time you re-open the property inspector. This is because the `colors`property contains all eight color settings of an object, so it's not necessary to store the individual color properties once they've been set.

To easily copy a property value from another profile, click the "Copy" button in the bottom section and choose the profile you want to copy from. | - -For more details on working with *Property Profiles*, see the section on -*Property Profiles* in the *Programming a User Interface* guide. - ### 10 Tips for Good User Interface Design If you are creating a simple utility for yourself, a handful of other diff --git a/Documentation/guides/The LiveCode IDE.md b/Documentation/guides/The LiveCode IDE.md index c46a7cde44..13ef3eb20d 100644 --- a/Documentation/guides/The LiveCode IDE.md +++ b/Documentation/guides/The LiveCode IDE.md @@ -565,6 +565,103 @@ Choose a handler to go to that handler in the script. The Window menu contains the names of open script editor windows. +### Autocomplete + +> **Note:** Autocomplete is available in LiveCode CommunityPlus and above + +#### Using Autocomplete + +While typing in the script editor a filtered list of available completions +will appear below the selection. Use the following keys to navigate the +completion list: + +- right arrow - apply the completion or enter group of completions +- left arrow - leave group of completions +- up arrow - move up the list +- down arrow - move down the list + +Moving the mouse will hide the completion list to avoid it remaining in +place over an area you would like to select. Completions include +placeholder fields which you can navigate with the tab key. Some +completions may have multiple placeholders with the same name which +will be edited together. Clicking within a placeholder will select it. + +#### Autocomplete Pro + +> **Note:** Autocomplete Pro is available in LiveCode Indy and above + +Autocomplete Pro provides the following additional features: + +- Completions generated dynamically by introspecting +the object being edited and its message path +- An Autocomplete Snippet Manager dialog is accessible from the script +editor menubar to manage a custom set of completions. + +#### Autocomplete Snippet Manager + +An autocomplete snippet provides the information required to match and +complete some code in the script editor. The Autocomplete Snippet Manager +allows the user to manage a custom set of completion snippets. + +Create a new completion snippet by clicking the **+** icon and delete the +currently selected snippet by clicking the **-** icon. + +The dialog allows entry of the following: + +**Display Name** - choose a completion snippet to edit or change the +display name of the current snippet. + +**Priority** - A value between 1 and 100 indicating the order the +completions should be matched in. Higher priorities will be listed +before lower priorities. + +**Match Scope** - Choose whether the completion should try and match when +the selection is outside a handler, inside a handler or anywhere. A +comment completion might be anywhere, a statement completion (unless +local, global or constant) would be only inside a handler and a handler +completion would be outside a handler. + +**Match Words** - Choose whether to match only all the words of a line, +just the word being written or either. A statement would be all the words +on a line, an expression would be just the current word and a comment +would be either. + +**Alternate Match String** - When matching completion snippets the text +of the completion is matched first but in some cases that is not suitable +or another string would be better to match. Enter a string to try matching +if the completion fails to match. + +**Summary** - This field is optional and provides some detail below the +completion in the script editor. + +**Completion** - This is the string to be used when replacing the +selection after choosing a completion. The completion may be any script +and any length. Add placeholders to the completion in the following form: + + ${:} + +Where: + +- name - is the text seen in the script editor +- type - is used to filter the completions presented for the placeholder +one of: + + - statement - any LiveCode command + - expression - any LiveCode expression + - identifier - a variable or handler name + +Additionally, it is possible to include multiple placeholders with the +same name. When a multiple placeholder is selected they are edited +at the same time. In this example completion as the user enters the +condition a comment is appended to the `end if` with the condition text. +Once the condition is complete the user may tab to the `-- code` line +and enter a statement. The tab order is always top to bottom and left to +right: + + if ${condition:expression} then + ${-- code:statement} + end if # ${condition} + ## The Message Box The Message Box is a command line tool that allows you to run scripts or @@ -783,7 +880,10 @@ Figure 12 – Find and Replace | Switch to find mode | Control-f | Command-f | | Find next | Control-g | Command-g | | Find selected text | Control-Option-f | Command-Option-f | -| Format current handler | Tab | Tab | +| Format handler or move to next placeholder | Tab | Tab | +| Next tab in Editor | Control-tab | Control-tab | +| Previous tab in Editor | Control-shift-tab | Control-shift-tab | +| Show completions palette | F1 | F1 | | **The Message Box** | **Windows / Linux** | **Mac OS X**| |------|--------|-------| diff --git a/Documentation/guides/Working with Media.md b/Documentation/guides/Working with Media.md index 86300d8ff0..723a6274d3 100644 --- a/Documentation/guides/Working with Media.md +++ b/Documentation/guides/Working with Media.md @@ -130,7 +130,7 @@ Figure 85 – The Graphic Tools | ![](images/image120.png) | Select | Drag to select a rectangular area of an image | Shift constraints to a square; command / control duplicates selection | | ![](images/image121.png) | Bucket | Fills shapes with color. Will fill any pixel connected to the pixel you click with the brush color | Control-click to fill with transparency | | ![](images/image122.png) | Spray can | Draw an airbrushed color using the brush shape | Control-click to spray with transparency | -| ![](images/image123.png) | Eraser | Remove color from an area leaving it transparent. Uses the brush shape | | | Shift constrains to a square; control creates transparency | +| ![](images/image123.png) | Eraser | Remove color from an area leaving it transparent. Uses the brush shape | | | ![](images/image128.png) | Polygon | Draw polygon shape (hold down on the rectangle shape to select this shape) | Shift constrains lines angles to multiples of 22.5°; control creates transparency | | ![](images/image129.png) | Line | Draw a straight line | Shift constrains lines angles to multiples of 22.5°; control creates transparency | | ![](images/image130.png) | Freehand | Draw a freehand curve (hold down on the line shape to select this shape). If the filled option is chosen the beginning and end of the curve are joined automatically when you finish drawing | Alt / option prevents drawing line border; control creates transparency | diff --git a/Documentation/guides/guide-order.yml b/Documentation/guides/guide-order.yml index 2efed21a46..a2f766e17f 100644 --- a/Documentation/guides/guide-order.yml +++ b/Documentation/guides/guide-order.yml @@ -7,4 +7,5 @@ group-order: - deployment - advanced - reference + - other --- \ No newline at end of file diff --git a/Documentation/guides/images/extensions-activate.png b/Documentation/guides/images/extensions-activate.png new file mode 100644 index 0000000000..0b80cbd536 Binary files /dev/null and b/Documentation/guides/images/extensions-activate.png differ diff --git a/Documentation/guides/images/extensions-composed.png b/Documentation/guides/images/extensions-composed.png new file mode 100644 index 0000000000..d9832e7e10 Binary files /dev/null and b/Documentation/guides/images/extensions-composed.png differ diff --git a/Documentation/guides/images/extensions-developer_id.png b/Documentation/guides/images/extensions-developer_id.png new file mode 100644 index 0000000000..25a6813090 Binary files /dev/null and b/Documentation/guides/images/extensions-developer_id.png differ diff --git a/Documentation/guides/images/extensions-store.png b/Documentation/guides/images/extensions-store.png new file mode 100644 index 0000000000..5cc8fcbada Binary files /dev/null and b/Documentation/guides/images/extensions-store.png differ diff --git a/Documentation/guides/images/extensions-upload.png b/Documentation/guides/images/extensions-upload.png new file mode 100644 index 0000000000..deef6f2a8b Binary files /dev/null and b/Documentation/guides/images/extensions-upload.png differ diff --git a/Documentation/guides/images/extensions_canvas_elliptic_arc.png b/Documentation/guides/images/extensions_canvas_elliptic_arc.png new file mode 100644 index 0000000000..3f1b771e41 Binary files /dev/null and b/Documentation/guides/images/extensions_canvas_elliptic_arc.png differ diff --git a/Documentation/guides/images/extensions_canvas_parallel_lines.png b/Documentation/guides/images/extensions_canvas_parallel_lines.png new file mode 100644 index 0000000000..28538ab7e2 Binary files /dev/null and b/Documentation/guides/images/extensions_canvas_parallel_lines.png differ diff --git a/Documentation/guides/images/extensions_canvas_svgpath.png b/Documentation/guides/images/extensions_canvas_svgpath.png new file mode 100644 index 0000000000..5c7b6e5ef7 Binary files /dev/null and b/Documentation/guides/images/extensions_canvas_svgpath.png differ diff --git a/Documentation/guides/images/image13.png b/Documentation/guides/images/image13.png deleted file mode 100644 index e61b3eda33..0000000000 Binary files a/Documentation/guides/images/image13.png and /dev/null differ diff --git a/Documentation/guides/images/image14.png b/Documentation/guides/images/image14.png deleted file mode 100644 index 9ebb2757ff..0000000000 Binary files a/Documentation/guides/images/image14.png and /dev/null differ diff --git a/Documentation/guides/images/image15.png b/Documentation/guides/images/image15.png deleted file mode 100644 index c779c516d2..0000000000 Binary files a/Documentation/guides/images/image15.png and /dev/null differ diff --git a/Documentation/guides/images/image16.png b/Documentation/guides/images/image16.png deleted file mode 100644 index 5f3aae31fb..0000000000 Binary files a/Documentation/guides/images/image16.png and /dev/null differ diff --git a/Documentation/guides/images/image20.png b/Documentation/guides/images/image20.png deleted file mode 100644 index dd80816c1e..0000000000 Binary files a/Documentation/guides/images/image20.png and /dev/null differ diff --git a/Documentation/guides/images/image22.png b/Documentation/guides/images/image22.png deleted file mode 100644 index c38e128acd..0000000000 Binary files a/Documentation/guides/images/image22.png and /dev/null differ diff --git a/Documentation/guides/images/image23.png b/Documentation/guides/images/image23.png deleted file mode 100644 index e061f51f7f..0000000000 Binary files a/Documentation/guides/images/image23.png and /dev/null differ diff --git a/Documentation/guides/images/image24.png b/Documentation/guides/images/image24.png deleted file mode 100644 index 201cf2da94..0000000000 Binary files a/Documentation/guides/images/image24.png and /dev/null differ diff --git a/Documentation/guides/images/image26.png b/Documentation/guides/images/image26.png deleted file mode 100644 index 2581545f17..0000000000 Binary files a/Documentation/guides/images/image26.png and /dev/null differ diff --git a/Documentation/guides/images/image27.png b/Documentation/guides/images/image27.png deleted file mode 100644 index 2b7df38702..0000000000 Binary files a/Documentation/guides/images/image27.png and /dev/null differ diff --git a/Documentation/guides/images/image28.png b/Documentation/guides/images/image28.png deleted file mode 100644 index 0c21d31817..0000000000 Binary files a/Documentation/guides/images/image28.png and /dev/null differ diff --git a/Documentation/guides/images/image29.png b/Documentation/guides/images/image29.png deleted file mode 100644 index eb3797ac0a..0000000000 Binary files a/Documentation/guides/images/image29.png and /dev/null differ diff --git a/Documentation/guides/images/image31.png b/Documentation/guides/images/image31.png deleted file mode 100644 index 0344f89e5f..0000000000 Binary files a/Documentation/guides/images/image31.png and /dev/null differ diff --git a/Documentation/guides/images/image55.png b/Documentation/guides/images/image55.png deleted file mode 100644 index 946e48615a..0000000000 Binary files a/Documentation/guides/images/image55.png and /dev/null differ diff --git a/Documentation/guides/images/image56.png b/Documentation/guides/images/image56.png deleted file mode 100644 index 929c519ddd..0000000000 Binary files a/Documentation/guides/images/image56.png and /dev/null differ diff --git a/Documentation/guides/images/image57.png b/Documentation/guides/images/image57.png deleted file mode 100644 index 62848320f2..0000000000 Binary files a/Documentation/guides/images/image57.png and /dev/null differ diff --git a/Documentation/guides/images/image58.png b/Documentation/guides/images/image58.png deleted file mode 100644 index 2e94ea6416..0000000000 Binary files a/Documentation/guides/images/image58.png and /dev/null differ diff --git a/Documentation/guides/images/image59.png b/Documentation/guides/images/image59.png deleted file mode 100644 index 5b1e78750a..0000000000 Binary files a/Documentation/guides/images/image59.png and /dev/null differ diff --git a/Documentation/guides/images/image60.png b/Documentation/guides/images/image60.png deleted file mode 100644 index f3d37e07e8..0000000000 Binary files a/Documentation/guides/images/image60.png and /dev/null differ diff --git a/Documentation/guides/images/image61.png b/Documentation/guides/images/image61.png deleted file mode 100644 index ad93e7f3b8..0000000000 Binary files a/Documentation/guides/images/image61.png and /dev/null differ diff --git a/Documentation/guides/images/image63.png b/Documentation/guides/images/image63.png deleted file mode 100644 index da2ddf942d..0000000000 Binary files a/Documentation/guides/images/image63.png and /dev/null differ diff --git a/Documentation/guides/images/image70.png b/Documentation/guides/images/image70.png deleted file mode 100644 index c7dd488634..0000000000 Binary files a/Documentation/guides/images/image70.png and /dev/null differ diff --git a/Documentation/guides/images/image71.png b/Documentation/guides/images/image71.png deleted file mode 100644 index a04d220493..0000000000 Binary files a/Documentation/guides/images/image71.png and /dev/null differ diff --git a/Documentation/guides/images/image73.png b/Documentation/guides/images/image73.png deleted file mode 100644 index 8f462eea45..0000000000 Binary files a/Documentation/guides/images/image73.png and /dev/null differ diff --git a/Documentation/guides/images/image74.png b/Documentation/guides/images/image74.png deleted file mode 100644 index 57150ac33e..0000000000 Binary files a/Documentation/guides/images/image74.png and /dev/null differ diff --git a/Documentation/guides/images/image82.png b/Documentation/guides/images/image82.png deleted file mode 100644 index eb63d863e9..0000000000 Binary files a/Documentation/guides/images/image82.png and /dev/null differ diff --git a/Documentation/guides/images/image84.png b/Documentation/guides/images/image84.png deleted file mode 100644 index 3ee2fc6fb7..0000000000 Binary files a/Documentation/guides/images/image84.png and /dev/null differ diff --git a/Documentation/guides/images/image85.png b/Documentation/guides/images/image85.png deleted file mode 100644 index ce5ddb473b..0000000000 Binary files a/Documentation/guides/images/image85.png and /dev/null differ diff --git a/Documentation/guides/images/image86.png b/Documentation/guides/images/image86.png deleted file mode 100644 index 07b1608d5c..0000000000 Binary files a/Documentation/guides/images/image86.png and /dev/null differ diff --git a/Documentation/guides/images/revonline-account-details.png b/Documentation/guides/images/revonline-account-details.png new file mode 100644 index 0000000000..a3d4b148e2 Binary files /dev/null and b/Documentation/guides/images/revonline-account-details.png differ diff --git a/Documentation/guides/images/revonline-add-delete-tags.png b/Documentation/guides/images/revonline-add-delete-tags.png new file mode 100644 index 0000000000..d89ccf5804 Binary files /dev/null and b/Documentation/guides/images/revonline-add-delete-tags.png differ diff --git a/Documentation/guides/images/revonline-content-browser-code.png b/Documentation/guides/images/revonline-content-browser-code.png new file mode 100644 index 0000000000..e12a633fc7 Binary files /dev/null and b/Documentation/guides/images/revonline-content-browser-code.png differ diff --git a/Documentation/guides/images/revonline-content-browser-external.png b/Documentation/guides/images/revonline-content-browser-external.png new file mode 100644 index 0000000000..c294fcc5b0 Binary files /dev/null and b/Documentation/guides/images/revonline-content-browser-external.png differ diff --git a/Documentation/guides/images/revonline-edit-content-controls.png b/Documentation/guides/images/revonline-edit-content-controls.png new file mode 100644 index 0000000000..ce4a018220 Binary files /dev/null and b/Documentation/guides/images/revonline-edit-content-controls.png differ diff --git a/Documentation/guides/images/revonline-edit-stack.png b/Documentation/guides/images/revonline-edit-stack.png new file mode 100644 index 0000000000..365ed3de02 Binary files /dev/null and b/Documentation/guides/images/revonline-edit-stack.png differ diff --git a/Documentation/guides/images/revonline-list-preview.png b/Documentation/guides/images/revonline-list-preview.png new file mode 100644 index 0000000000..59ad3ef7f5 Binary files /dev/null and b/Documentation/guides/images/revonline-list-preview.png differ diff --git a/Documentation/guides/images/revonline-login-dialog.png b/Documentation/guides/images/revonline-login-dialog.png new file mode 100644 index 0000000000..0ccb0d87ae Binary files /dev/null and b/Documentation/guides/images/revonline-login-dialog.png differ diff --git a/Documentation/guides/images/revonline-login-status-logged-in.png b/Documentation/guides/images/revonline-login-status-logged-in.png new file mode 100644 index 0000000000..888692c39c Binary files /dev/null and b/Documentation/guides/images/revonline-login-status-logged-in.png differ diff --git a/Documentation/guides/images/revonline-login-status-not-logged-in.png b/Documentation/guides/images/revonline-login-status-not-logged-in.png new file mode 100644 index 0000000000..c416beda24 Binary files /dev/null and b/Documentation/guides/images/revonline-login-status-not-logged-in.png differ diff --git a/Documentation/guides/images/revonline-main.png b/Documentation/guides/images/revonline-main.png new file mode 100644 index 0000000000..52e93bde57 Binary files /dev/null and b/Documentation/guides/images/revonline-main.png differ diff --git a/Documentation/guides/images/revonline-page-list.png b/Documentation/guides/images/revonline-page-list.png new file mode 100644 index 0000000000..b68897fac0 Binary files /dev/null and b/Documentation/guides/images/revonline-page-list.png differ diff --git a/Documentation/guides/images/revonline-preferences.png b/Documentation/guides/images/revonline-preferences.png new file mode 100644 index 0000000000..a3998d62df Binary files /dev/null and b/Documentation/guides/images/revonline-preferences.png differ diff --git a/Documentation/guides/images/revonline-user-filter.png b/Documentation/guides/images/revonline-user-filter.png new file mode 100644 index 0000000000..37d692ecf9 Binary files /dev/null and b/Documentation/guides/images/revonline-user-filter.png differ diff --git a/Documentation/guides/images/revonline-view-pane.png b/Documentation/guides/images/revonline-view-pane.png new file mode 100644 index 0000000000..1d210b5970 Binary files /dev/null and b/Documentation/guides/images/revonline-view-pane.png differ diff --git a/Documentation/guides/images/script-build-ui-align-objects.png b/Documentation/guides/images/script-build-ui-align-objects.png new file mode 100644 index 0000000000..35c4786b5a Binary files /dev/null and b/Documentation/guides/images/script-build-ui-align-objects.png differ diff --git a/Documentation/guides/images/script-build-ui-answer-color.png b/Documentation/guides/images/script-build-ui-answer-color.png new file mode 100644 index 0000000000..3ed2404048 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-answer-color.png differ diff --git a/Documentation/guides/images/script-build-ui-answer-dialog-linux.png b/Documentation/guides/images/script-build-ui-answer-dialog-linux.png new file mode 100644 index 0000000000..f4a395757b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-answer-dialog-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-answer-dialog-mac.png b/Documentation/guides/images/script-build-ui-answer-dialog-mac.png new file mode 100644 index 0000000000..1ed28d233b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-answer-dialog-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-answer-dialog-win.png b/Documentation/guides/images/script-build-ui-answer-dialog-win.png new file mode 100755 index 0000000000..0a57e70727 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-answer-dialog-win.png differ diff --git a/Documentation/guides/images/script-build-ui-ask-dialog-linux.png b/Documentation/guides/images/script-build-ui-ask-dialog-linux.png new file mode 100644 index 0000000000..0dcd6c5ea8 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-ask-dialog-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-ask-dialog-mac.png b/Documentation/guides/images/script-build-ui-ask-dialog-mac.png new file mode 100644 index 0000000000..aaf60b5878 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-ask-dialog-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-ask-dialog-win.png b/Documentation/guides/images/script-build-ui-ask-dialog-win.png new file mode 100755 index 0000000000..f8f8c38ed1 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-ask-dialog-win.png differ diff --git a/Documentation/guides/images/script-build-ui-check-box-linux.png b/Documentation/guides/images/script-build-ui-check-box-linux.png new file mode 100644 index 0000000000..6702a2389d Binary files /dev/null and b/Documentation/guides/images/script-build-ui-check-box-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-check-box-mac.png b/Documentation/guides/images/script-build-ui-check-box-mac.png new file mode 100644 index 0000000000..252d113e10 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-check-box-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-check-box-win.png b/Documentation/guides/images/script-build-ui-check-box-win.png new file mode 100755 index 0000000000..016ea43d34 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-check-box-win.png differ diff --git a/Documentation/guides/images/script-build-ui-combo-box-linux.png b/Documentation/guides/images/script-build-ui-combo-box-linux.png new file mode 100644 index 0000000000..138dc2004c Binary files /dev/null and b/Documentation/guides/images/script-build-ui-combo-box-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-combo-box-mac.png b/Documentation/guides/images/script-build-ui-combo-box-mac.png new file mode 100644 index 0000000000..b1c2a3282e Binary files /dev/null and b/Documentation/guides/images/script-build-ui-combo-box-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-combo-box-win.png b/Documentation/guides/images/script-build-ui-combo-box-win.png new file mode 100755 index 0000000000..487e230fe8 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-combo-box-win.png differ diff --git a/Documentation/guides/images/script-build-ui-default-button-linux.png b/Documentation/guides/images/script-build-ui-default-button-linux.png new file mode 100644 index 0000000000..fe68160f36 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-default-button-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-default-button-mac.png b/Documentation/guides/images/script-build-ui-default-button-mac.png new file mode 100644 index 0000000000..9edb65c8aa Binary files /dev/null and b/Documentation/guides/images/script-build-ui-default-button-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-default-button-win.png b/Documentation/guides/images/script-build-ui-default-button-win.png new file mode 100755 index 0000000000..b5df0c3089 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-default-button-win.png differ diff --git a/Documentation/guides/images/script-build-ui-editable-stack-linux.png b/Documentation/guides/images/script-build-ui-editable-stack-linux.png new file mode 100644 index 0000000000..1eb46049f3 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-editable-stack-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-editable-stack-mac.png b/Documentation/guides/images/script-build-ui-editable-stack-mac.png new file mode 100644 index 0000000000..6a21984014 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-editable-stack-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-editable-stack-win.png b/Documentation/guides/images/script-build-ui-editable-stack-win.png new file mode 100755 index 0000000000..f04158fe5d Binary files /dev/null and b/Documentation/guides/images/script-build-ui-editable-stack-win.png differ diff --git a/Documentation/guides/images/script-build-ui-geometry-manager.png b/Documentation/guides/images/script-build-ui-geometry-manager.png new file mode 100644 index 0000000000..42b96df5b2 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-geometry-manager.png differ diff --git a/Documentation/guides/images/script-build-ui-menu-builder.png b/Documentation/guides/images/script-build-ui-menu-builder.png new file mode 100644 index 0000000000..2af91c168b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-menu-builder.png differ diff --git a/Documentation/guides/images/script-build-ui-modal-stack-linux.png b/Documentation/guides/images/script-build-ui-modal-stack-linux.png new file mode 100644 index 0000000000..6adaa9da5c Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modal-stack-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-modal-stack-mac.png b/Documentation/guides/images/script-build-ui-modal-stack-mac.png new file mode 100644 index 0000000000..e5054a2667 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modal-stack-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-modal-stack-win.png b/Documentation/guides/images/script-build-ui-modal-stack-win.png new file mode 100755 index 0000000000..7df88b695c Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modal-stack-win.png differ diff --git a/Documentation/guides/images/script-build-ui-modeless-stack-linux.png b/Documentation/guides/images/script-build-ui-modeless-stack-linux.png new file mode 100644 index 0000000000..bb6877cd72 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modeless-stack-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-modeless-stack-mac.png b/Documentation/guides/images/script-build-ui-modeless-stack-mac.png new file mode 100644 index 0000000000..e871aa32bd Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modeless-stack-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-modeless-stack-win.png b/Documentation/guides/images/script-build-ui-modeless-stack-win.png new file mode 100755 index 0000000000..24deabc062 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-modeless-stack-win.png differ diff --git a/Documentation/guides/images/script-build-ui-option-menu-linux.png b/Documentation/guides/images/script-build-ui-option-menu-linux.png new file mode 100644 index 0000000000..2641608261 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-option-menu-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-option-menu-mac.png b/Documentation/guides/images/script-build-ui-option-menu-mac.png new file mode 100644 index 0000000000..f6f82a8b08 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-option-menu-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-option-menu-win.png b/Documentation/guides/images/script-build-ui-option-menu-win.png new file mode 100755 index 0000000000..ae1c16f0f7 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-option-menu-win.png differ diff --git a/Documentation/guides/images/script-build-ui-palette-stack-linux.png b/Documentation/guides/images/script-build-ui-palette-stack-linux.png new file mode 100644 index 0000000000..98d2e2fa91 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-palette-stack-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-palette-stack-mac.png b/Documentation/guides/images/script-build-ui-palette-stack-mac.png new file mode 100644 index 0000000000..7d9e614f12 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-palette-stack-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-palette-stack-win.png b/Documentation/guides/images/script-build-ui-palette-stack-win.png new file mode 100755 index 0000000000..f0a2375266 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-palette-stack-win.png differ diff --git a/Documentation/guides/images/script-build-ui-popup-menu-linux.png b/Documentation/guides/images/script-build-ui-popup-menu-linux.png new file mode 100644 index 0000000000..25ea1d51ac Binary files /dev/null and b/Documentation/guides/images/script-build-ui-popup-menu-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-popup-menu-mac.png b/Documentation/guides/images/script-build-ui-popup-menu-mac.png new file mode 100644 index 0000000000..4a25d9bb05 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-popup-menu-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-popup-menu-win.png b/Documentation/guides/images/script-build-ui-popup-menu-win.png new file mode 100755 index 0000000000..eed44bbe0a Binary files /dev/null and b/Documentation/guides/images/script-build-ui-popup-menu-win.png differ diff --git a/Documentation/guides/images/script-build-ui-progress-bar-linux.png b/Documentation/guides/images/script-build-ui-progress-bar-linux.png new file mode 100644 index 0000000000..f5d54ae446 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-progress-bar-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-progress-bar-mac.png b/Documentation/guides/images/script-build-ui-progress-bar-mac.png new file mode 100644 index 0000000000..f90828cf76 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-progress-bar-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-progress-bar-win.png b/Documentation/guides/images/script-build-ui-progress-bar-win.png new file mode 100755 index 0000000000..261e7f20d9 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-progress-bar-win.png differ diff --git a/Documentation/guides/images/script-build-ui-pulldown-menu-linux.png b/Documentation/guides/images/script-build-ui-pulldown-menu-linux.png new file mode 100644 index 0000000000..db3bc12c76 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-pulldown-menu-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-pulldown-menu-mac.png b/Documentation/guides/images/script-build-ui-pulldown-menu-mac.png new file mode 100644 index 0000000000..6a486b89c0 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-pulldown-menu-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-pulldown-menu-win.png b/Documentation/guides/images/script-build-ui-pulldown-menu-win.png new file mode 100755 index 0000000000..34d2818ab1 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-pulldown-menu-win.png differ diff --git a/Documentation/guides/images/script-build-ui-radio-button-linux.png b/Documentation/guides/images/script-build-ui-radio-button-linux.png new file mode 100644 index 0000000000..f15a132a60 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-radio-button-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-radio-button-mac.png b/Documentation/guides/images/script-build-ui-radio-button-mac.png new file mode 100644 index 0000000000..662ee71a7e Binary files /dev/null and b/Documentation/guides/images/script-build-ui-radio-button-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-radio-button-win.png b/Documentation/guides/images/script-build-ui-radio-button-win.png new file mode 100755 index 0000000000..bf04a6800b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-radio-button-win.png differ diff --git a/Documentation/guides/images/script-build-ui-rectangle-button-linux.png b/Documentation/guides/images/script-build-ui-rectangle-button-linux.png new file mode 100644 index 0000000000..5a9de2c405 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-rectangle-button-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-rectangle-button-mac.png b/Documentation/guides/images/script-build-ui-rectangle-button-mac.png new file mode 100644 index 0000000000..5a91282f0b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-rectangle-button-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-rectangle-button-win.png b/Documentation/guides/images/script-build-ui-rectangle-button-win.png new file mode 100755 index 0000000000..6b81afa7d2 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-rectangle-button-win.png differ diff --git a/Documentation/guides/images/script-build-ui-scrollbar-linux.png b/Documentation/guides/images/script-build-ui-scrollbar-linux.png new file mode 100644 index 0000000000..f42c1a3338 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-scrollbar-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-scrollbar-mac.png b/Documentation/guides/images/script-build-ui-scrollbar-mac.png new file mode 100644 index 0000000000..614cc1fef6 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-scrollbar-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-scrollbar-win.png b/Documentation/guides/images/script-build-ui-scrollbar-win.png new file mode 100755 index 0000000000..7b3f22f15b Binary files /dev/null and b/Documentation/guides/images/script-build-ui-scrollbar-win.png differ diff --git a/Documentation/guides/images/script-build-ui-size-position.png b/Documentation/guides/images/script-build-ui-size-position.png new file mode 100644 index 0000000000..21462bc62c Binary files /dev/null and b/Documentation/guides/images/script-build-ui-size-position.png differ diff --git a/Documentation/guides/images/script-build-ui-slider-linux.png b/Documentation/guides/images/script-build-ui-slider-linux.png new file mode 100644 index 0000000000..6ee7e79ac0 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-slider-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-slider-mac.png b/Documentation/guides/images/script-build-ui-slider-mac.png new file mode 100644 index 0000000000..8df8cc5845 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-slider-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-slider-win.png b/Documentation/guides/images/script-build-ui-slider-win.png new file mode 100755 index 0000000000..09524d63c5 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-slider-win.png differ diff --git a/Documentation/guides/images/script-build-ui-standard-button-linux.png b/Documentation/guides/images/script-build-ui-standard-button-linux.png new file mode 100644 index 0000000000..8ca96401be Binary files /dev/null and b/Documentation/guides/images/script-build-ui-standard-button-linux.png differ diff --git a/Documentation/guides/images/script-build-ui-standard-button-mac.png b/Documentation/guides/images/script-build-ui-standard-button-mac.png new file mode 100644 index 0000000000..a9449f6c23 Binary files /dev/null and b/Documentation/guides/images/script-build-ui-standard-button-mac.png differ diff --git a/Documentation/guides/images/script-build-ui-standard-button-win.png b/Documentation/guides/images/script-build-ui-standard-button-win.png new file mode 100755 index 0000000000..5e9a77adad Binary files /dev/null and b/Documentation/guides/images/script-build-ui-standard-button-win.png differ diff --git a/Documentation/guides/images/script-build-ui-system-window.png b/Documentation/guides/images/script-build-ui-system-window.png new file mode 100644 index 0000000000..83c00f8aea Binary files /dev/null and b/Documentation/guides/images/script-build-ui-system-window.png differ diff --git a/Documentation/guides/images/script-build-ui-tools-palette.png b/Documentation/guides/images/script-build-ui-tools-palette.png new file mode 100644 index 0000000000..7ab1abe7da Binary files /dev/null and b/Documentation/guides/images/script-build-ui-tools-palette.png differ diff --git a/Documentation/guides/images/script-build-ui-window-shape.png b/Documentation/guides/images/script-build-ui-window-shape.png new file mode 100644 index 0000000000..45a00abf9d Binary files /dev/null and b/Documentation/guides/images/script-build-ui-window-shape.png differ diff --git a/Documentation/guides/images/standalone-settings-android.png b/Documentation/guides/images/standalone-settings-android.png new file mode 100644 index 0000000000..3e6c9605f7 Binary files /dev/null and b/Documentation/guides/images/standalone-settings-android.png differ diff --git a/Documentation/guides/images/standalone-settings-html5.png b/Documentation/guides/images/standalone-settings-html5.png new file mode 100644 index 0000000000..ad4547ee08 Binary files /dev/null and b/Documentation/guides/images/standalone-settings-html5.png differ diff --git a/Documentation/guides/images/standalone-settings-ios-basic.png b/Documentation/guides/images/standalone-settings-ios-basic.png new file mode 100644 index 0000000000..2adda7b03c Binary files /dev/null and b/Documentation/guides/images/standalone-settings-ios-basic.png differ diff --git a/Documentation/guides/images/standalone-settings-ios-icons.png b/Documentation/guides/images/standalone-settings-ios-icons.png new file mode 100644 index 0000000000..51bfc88145 Binary files /dev/null and b/Documentation/guides/images/standalone-settings-ios-icons.png differ diff --git a/Documentation/guides/images/standalone-settings-ios-requirements.png b/Documentation/guides/images/standalone-settings-ios-requirements.png new file mode 100644 index 0000000000..ee29cbb1d3 Binary files /dev/null and b/Documentation/guides/images/standalone-settings-ios-requirements.png differ diff --git a/Documentation/guides/images/standalone-settings-ios-splash.png b/Documentation/guides/images/standalone-settings-ios-splash.png new file mode 100644 index 0000000000..a37c409772 Binary files /dev/null and b/Documentation/guides/images/standalone-settings-ios-splash.png differ diff --git a/Documentation/guides/images/standalone-settings-windows.png b/Documentation/guides/images/standalone-settings-windows.png index eedc455435..f2e58a0248 100644 Binary files a/Documentation/guides/images/standalone-settings-windows.png and b/Documentation/guides/images/standalone-settings-windows.png differ diff --git a/Documentation/html_viewer/api.html.template b/Documentation/html_viewer/api.html.template index 9d586fbe51..e5781f9a2d 100644 --- a/Documentation/html_viewer/api.html.template +++ b/Documentation/html_viewer/api.html.template @@ -1,135 +1,134 @@ - - - - - - LiveCode Dictionary - - - - + + + + + + LiveCode Dictionary + + + + -
-
+ + +
+
-
-
-
-
- -
-
-
-
+
+
Filters
none
-
+
-
+
-
-
-
-
-
-
-
- -
-
- -
-
- - - - -
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
+
+ +
+
+
-
-
-
- -
-
-
+
+
+
- - - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Documentation/html_viewer/css/lcdoc.css b/Documentation/html_viewer/css/lcdoc.css index 168179f567..f3dd7467a3 100644 --- a/Documentation/html_viewer/css/lcdoc.css +++ b/Documentation/html_viewer/css/lcdoc.css @@ -1,6 +1,15 @@ @charset "UTF-8"; /* CSS Document */ +html { /* always show scroll bar on page */ + overflow-y: scroll; /* keeps nav elements from shifting */ +} + +#lcnavbar { + padding-left: 15px; + padding-right: 15px; +} + .lcdoc_parameterValue{ font-weight:bold} #table_list { @@ -37,6 +46,53 @@ content: "\e107 "; } +#table_list tr.indy > td:nth-child(1):before { + font-family: "Glyphicons Halflings"; + content: "\e107 "; +} + +#table_list tr.communityplus > td:nth-child(1):before { + content: url('../../../Toolset/resources/communityplus/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +#table_list tr.indy > td:nth-child(1):before { + content: url('../../../Toolset/resources/commercial/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +#table_list tr.business > td:nth-child(1):before { + content: url('../../../Toolset/resources/professional/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +div.community:before { + content: url('../../../Toolset/resources/community/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +div.communityplus:before { + content: url('../../../Toolset/resources/communityplus/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +div.indy:before { + content: url('../../../Toolset/resources/commercial/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + +div.business:before { + content: url('../../../Toolset/resources/professional/ideSkin/bubble.png'); + display: inline-block; + width: 20px; +} + #table_list tr:after { content: ' '; display: block; @@ -74,37 +130,32 @@ } #resizer { - content:url("../resources/media/vertical_resizer.png"); + content:url("../resources/media/vertical_resizer_580.png"); cursor: ns-resize; margin: 10px; + margin-left: auto; + margin-right: auto; + width: 75%; } #header_panel_holder { background-color: #FFFFFF; top: 0; - padding-top: 25px; - position: fixed; + padding-top: 56px; min-height: 85px; - height: 353px; } #table_container { width: 100%; height: 227px;; - overflow: scroll; + overflow-y: scroll; } #lcdoc_list { - position: fixed; } #lcdoc_body{ -} - -.affix_right -{ - width:848px; - z-index:100; + margin-top: 20px; } .lcdoc_section_title{ font-weight:bold; text-transform:capitalize} @@ -134,54 +185,6 @@ font-size: inherit; } -@media (min-width: 768px) { - .affix_right{ - width:90%; - margin-left:auto; - margin-right:auto; - } -} - -@media (min-width: 992px) { - .affix_right{ - width:697px; - } -} - -@media (min-width: 1200px) { - .affix_right{ - width:848px; - } -} - -.bs-sidebar.affix { - width: 260px; - top: 25px; - display:none; -} - -@media (min-width: 768px) { - .bs-sidebar.affix { - display:none; - } -} - -@media (min-width: 992px) { - .bs-sidebar.affix { - width: 213px; - position: fixed; - top: 25px; - display:block; - } -} - -@media (min-width: 1200px) { - .bs-sidebar.affix { - width: 263px; - display:block; - } -} - .lcdoc_description a.load_entry { color: inherit; text-decoration: inherit; @@ -210,6 +213,10 @@ #lcdoc_sidebar { height: 100%; + width: 25%; + top: 70px; + position: fixed; + padding-right: 15px; } #filters_options { @@ -217,10 +224,16 @@ overflow-y: scroll; } -#filters_options td { - padding-right: 10px; +#filters_options td:nth-child(1) { + padding-right: 5px; +} +#filters_options td:nth-child(2) { + padding-left: 5px; } +#filters_options td { + width: 50%; +} #filters_options .category { padding-top: 10px; } @@ -230,7 +243,7 @@ } #filters_panel { - height: 75%; + height: 80%; overflow: hidden; } @@ -240,4 +253,9 @@ #dropdownMenu1 { width: 100%; +} + +.dropdown-menu { /* lists may be too long to fit on the page */ + overflow-y: auto; + max-height: 85vh; } \ No newline at end of file diff --git a/Documentation/html_viewer/js/dictionary_functions.js b/Documentation/html_viewer/js/dictionary_functions.js index 022b32ca99..286286b613 100644 --- a/Documentation/html_viewer/js/dictionary_functions.js +++ b/Documentation/html_viewer/js/dictionary_functions.js @@ -1,100 +1,222 @@ - var tState = {selected:"",history:{list:[],selected:-1},searched:{},filters:{},filtered_data:[],data:"",selected_api_id:"", sort_type:""}; + var tState = { + selected_api_id:"", + selected_entry_index:{}, + history:{ + list:[], + selected_index:-1 + }, + cached_search_data:{}, + filters:{}, + filtered_data:[], + data:"", + sort_type:"", + edition: "" + }; - if($.session.get("selected_api_id")) tState.selected = $.session.get("selected_api_id"); - - if($.session.get("selected")) tState.selected = $.session.get("selected"); - else tState.selected = 1; + if ($.session.get("selected_api_id")) { + tState.selected_api_id = $.session.get("selected_api_id"); + } else { + tState.selected_api_id = 0; + } + + if ($.session.get("selected_entry_index")) { + var tIndexArray = $.session.get("selected_entry_index"); + tState.selected_entry_index[tState.selected_api_id] = tIndexArray[tState.selected_api_id]; + } else { + tState.selected_entry_index[tState.selected_api_id] = 0; + } + + library_set(tState.selected_api_id); - function dataGet(){ - //console.log(dictionary_data.docs); - if(!dictionary_data.docs.hasOwnProperty(tState.selected_api_id)){ - - $.each(dictionary_data.docs, function(index, libraryData){ + $.each(dictionary_data.docs, function(index, libraryData) { tState.selected_api_id = index; return false; }); } - if(tState.dirtyData == true || tState.data == ""){ + if (tState.dirtyData == true || tState.data == ""){ tState.data = dictionary_data.docs[tState.selected_api_id].doc.sort(compareEntryObject); tState.dirtyData = false; } return tState.data; } - - // Return all the syntax associated with an entry + + // Return all the syntax and synonyms associated with an entry // as a (matchable) string function collectSyntax(pEntry) { - var tSyntax = ''; + var tSyntax = pEntry["display name"]; $.each(pEntry["display syntax"], function (index, value) { - if (tSyntax != '') - tSyntax += ' '; - - tSyntax += value; + tSyntax += ' ' + value; }); + if(pEntry.hasOwnProperty("synonyms")) + { + $.each(pEntry["synonyms"], function (index, value) + { + tSyntax += ' ' + value; + }); + } + tSyntax = removeHtmlEntityEscapes(tSyntax); return tSyntax; } + // Replace HTML entity escape sequences with native characters for + // searching and highlighting syntax and synonyms. + function removeHtmlEntityEscapes(pTerm) + { + var tTerm = pTerm; + tTerm = tTerm.replace(/&/g,"&"); + tTerm = tTerm.replace(/</g,"<"); + tTerm = tTerm.replace(/>/g,">"); + tTerm = tTerm.replace(/"/g,'"'); + return tTerm; + } + + // Replace characters with their HTML entity escape sequences after + // processing is completed. + function addHtmlEntityEscapes(pTerm) + { + var tTerm = pTerm; + tTerm = tTerm.replace(/&/g,"&"); + tTerm = tTerm.replace(/\/g,">"); + tTerm = tTerm.replace(/\"/g,"""); + return tTerm; + } + + // Escape RegExp special characters for use in searching + var kSpecialCharacters = /[.*+?|()\[\]{}\\$^]/g; // .*+?|()[]{}\$^ + RegExp.escape = function(pText) + { + return pText.replace(kSpecialCharacters, "\\$&"); + } + // Return a list of matched search terms function dataSearch(pTerm) { // Check the cached search data - if (tState.searched.hasOwnProperty("term") && tState.searched.term == pTerm) - return tState.searched.data; + if (tState.cached_search_data.hasOwnProperty("term") && tState.cached_search_data.term == pTerm) + return tState.cached_search_data.data; - tState.searched.term = pTerm; - tState.searched.data = []; - - // Get a list of space-delimited search terms - var tokensOfTerm = pTerm.match(/\S+/g); - + tState.cached_search_data.term = pTerm; + tState.cached_search_data.data = []; + + // Escape RegExp special characters: \ ^ $ [ + // A leading space will enable full RegExp support + var tTerm = ''; + if(pTerm.charAt(0) == ' ') + tTerm = pTerm.trim(); + else + tTerm = RegExp.escape(pTerm); + + // Get a list of space-delimited search terms + var tokensOfTerm = tTerm.match(/\S+/g); - // Generate two regexes - one that matches all syntax that + // Generate three regexes - one that matches all syntax that // contains each search term, and one that matches all syntax that - // contains a word beginning with each search term. This way we - // can prioritise matches that start with the search terms. - var matchExp = ''; - var priorityMatch = ''; - $.each(tokensOfTerm, function(index, matchToken) - { - matchExp += '(?=.*' + matchToken + ')'; - priorityMatch += '(?=.*\\b' + matchToken + ')'; - }); + // contains a word beginning with each search term, one that will + // match full words of each search term. This way we can prioritize + // full word matches and matches that start with the search terms. + var matchExp = ''; + var priorityMatch = ''; + var wordMatch = ''; + $.each(tokensOfTerm, function(index, matchToken) + { + matchExp += '(?=.*' + matchToken + ')'; + priorityMatch += '(?=.*\\b' + matchToken + ')'; + wordMatch += '(?=.*\\b' + matchToken + '\\b)'; + }); + + // Special case sorting for terms considered word break + // characters that would not get sorted properly. + switch(pTerm){ + case '-': + case '/': + case ';': + case '[': + case '(': + case '()': + wordMatch = '(^' + tTerm + ')'; + break; + } var regex = new RegExp(matchExp, "i"); var priorityRegex = new RegExp(priorityMatch, "i"); + var wordRegex = new RegExp(wordMatch, "i"); // Grep for the general search term - tState . searched . data = $.grep(tState.filtered_data, function (e) + tState . cached_search_data . data = $.grep(tState.filtered_data, function (e) { var tToMatch = collectSyntax(e); var tMatched = regex.test(tToMatch); return tMatched; }); - // Sort the priority matches to the top - tState . searched . data . sort(function(a, b) - { - var tToMatch = collectSyntax(a); - if (priorityRegex.test(tToMatch)) + // Sort the priority matches to the top + tState . cached_search_data . data . sort(function(a, b) + { + var tNameA, tNameB, tMatchA, tMatchB + + tNameA = a["display name"].toLowerCase(); + if(a.hasOwnProperty("synonyms")) + { + $.each(a["synonyms"], function (index, value) + { + tNameA += ' ' + value.toLowerCase(); + }); + } + + tNameB = b["display name"].toLowerCase(); + if(b.hasOwnProperty("synonyms")) + { + $.each(b["synonyms"], function (index, value) + { + tNameB += ' ' + value.toLowerCase(); + }); + } + + // full word matches in display name sort to the top + tMatchA = wordRegex.test(tNameA); + tMatchB = wordRegex.test(tNameB); + if (tMatchA && !tMatchB) return -1; - - tToMatch = collectSyntax(b); - if (priorityRegex.test(tToMatch)) + if (tMatchB && !tMatchA) + return 1; + + // display names with words that start with terms next + tMatchA = priorityRegex.test(tNameA); + tMatchB = priorityRegex.test(tNameB); + if (tMatchA && !tMatchB) + return -1; + if (tMatchB && !tMatchA) + return 1; + + // display name contains search terms next + tMatchA = regex.test(tNameA); + tMatchB = regex.test(tNameB); + if (tMatchA && !tMatchB) + return -1; + if (tMatchB && !tMatchA) + return 1; + + // alphabetical sort by display name for everything else + if (tNameA < tNameB) + return -1; + if (tNameA > tNameB) return 1; - return 0; }); + //console.timeEnd("Search"); - return tState . searched . data; + return tState . cached_search_data . data; } - function dataFilter(){ + // Return the data of the current API subject to the applied filters + function dataFilter() { var filtered_data = []; var tFound_data = [] @@ -115,7 +237,7 @@ switch(category){ case "type": - if(entryData[category] == tag_value){ + if(entryData[category] == tag){ tFound_data[category]++; } break; @@ -125,7 +247,7 @@ case "associations": if(entryData.hasOwnProperty(category)){ $.each(entryData[category], function(item_index, entry_item_value){ - if(tag_value == entry_item_value){ + if(tag == entry_item_value){ tFound_data[category]++; } }); @@ -136,20 +258,22 @@ }); var tMatch = true; - $.each(tState.filters, function(category, values){ - if(tFound_data[category] == 0){ + $.each(tState.filters, function(category, values) { + if (tFound_data[category] == 0) { tMatch = false; } }); - if(tMatch == true) filtered_data.push(entryData); + if (tMatch == true) { + filtered_data.push(entryData); + } }); tState.filtered_data = filtered_data; } displayFilters(); - tState.searched = {}; + tState.cached_search_data = {}; displayEntryListGrep($("#ui_filer").val()); } @@ -162,63 +286,86 @@ } - function filterOptions(pCategories){ + function filterOptions(pCategories) + { var tFilterOptionWithCount = {} - var tShowCatogories = pCategories.split(','); - $.each(tShowCatogories, function( index, category_name) { + var tShowCategories = pCategories.split(','); + $.each(tShowCategories, function(index, category_name) + { tFilterOptionWithCount[category_name] = {} }); - $.each(tState.filtered_data, function( entry_index, entry_data) { - $.each(tShowCatogories, function( category_index, category_name) { + $.each(tState.filtered_data, function(entry_index, entry_data) + { + $.each(tShowCategories, function(category_index, category_name) + { // If the category is already being filtered on then don't count - if(!tState.filters.hasOwnProperty(category_name)){ - if(entry_data[category_name]){ + if (!tState.filters.hasOwnProperty(category_name)) + { + if (entry_data[category_name]) + { var tTagData = entry_data[category_name]; - - if(Array.isArray(tTagData)){ - // Data is an array meaning there are multiple values. I.e. multiple tags / platforms to check. - $.each(tTagData, function( tag, tag_value) { - if(tFilterOptionWithCount[category_name].hasOwnProperty(tag_value)){ - tFilterOptionWithCount[category_name][tag_value]++; - } else { - tFilterOptionWithCount[category_name][tag_value] = 1; - } - }); - } else { - if(tFilterOptionWithCount[category_name].hasOwnProperty(tTagData)){ - tFilterOptionWithCount[category_name][tTagData]++; - } else { - tFilterOptionWithCount[category_name][tTagData] = 1; - } + if (!Array.isArray(tTagData)) + { + tTagData = {1: tTagData}; } + + // Iterate through the values of this category and accumulate data + $.each(tTagData, function(tag, tag_value) + { + if (tFilterOptionWithCount[category_name].hasOwnProperty(tag_value)) + { + tFilterOptionWithCount[category_name][tag_value]["count"]++; + } + else + { + tFilterOptionWithCount[category_name][tag_value] = {}; + tFilterOptionWithCount[category_name][tag_value]["count"] = 1; + } + tFilterOptionWithCount[category_name][tag_value]["name"] = tag_value; + }); } } }); }); + + // Use association display name as displayed tag value + $.each(tFilterOptionWithCount["associations"], function(tag_value, tag_data) + { + var tEntryIndex = resolve_association_index(tag_value, ''); + if (!isDefined(tEntryIndex)) + return true; + + var tEntryObject = tState.data[tEntryIndex]; + var tDisplayName = tag_data["value"] + if (tEntryObject.hasOwnProperty("display name")) + { + tDisplayName = tEntryObject["display name"]; + } + tFilterOptionWithCount["associations"][tag_value]["name"] = tDisplayName + }); + return tFilterOptionWithCount; } - function filter_remove(pTag,pData){ - if(tState.filters.hasOwnProperty(pTag)){ - $.each(tState.filters[pTag], function(index, data) { - if(data==pData){ - tState.filters[pTag].splice(index, 1) - if(tState.filters[pTag].length == 0){ - delete tState.filters[pTag]; - } - return false; - } - }); + function filter_remove(pTag,pValue,pName){ + if (tState.filters.hasOwnProperty(pTag) && + tState.filters[pTag].hasOwnProperty(pValue)) + { + delete tState.filters[pTag][pValue]; + if (jQuery.isEmptyObject(tState.filters[pTag])) + { + delete tState.filters[pTag]; + } } dataFilter(); } - function filter_add(pTag,pData){ - if(!tState.filters.hasOwnProperty(pTag)) tState.filters[pTag] = []; + function filter_add(pTag,pValue,pName){ + if(!tState.filters.hasOwnProperty(pTag)) tState.filters[pTag] = {}; - if(tState.filters[pTag].indexOf(pData) == -1){ - tState.filters[pTag].push(pData); + if(!tState.filters[pTag].hasOwnProperty(pValue)){ + tState.filters[pTag][pValue] = pName dataFilter(); } } @@ -228,13 +375,17 @@ return Object.keys(obj).sort(); } - function filter_cell(pCategory, pValue) + function filter_cell(pCategory, pValue, pSpan) { var tHTML = ''; - tHTML += ''; - tHTML += pValue; + tHTML += 'filter_name="'+pValue["name"]+'" '; + tHTML += 'filter_value="'+pValue["value"]+'">'; + tHTML += pValue["name"].toLowerCase(); //tHTML += ''+pFilterData[tFilter]+''; tHTML += ''; return tHTML; @@ -250,22 +401,40 @@ var tDisplayedFilters = []; $.each(tSortedFilters, function(index, value) { - if (!tState.filters.hasOwnProperty(index) || - tState.filters[pCategory].indexOf(value) == 0) - tDisplayedFilters.push(value); + var tTagValue = pFilterData[value]; + if (!tState.filters.hasOwnProperty(pCategory) || + !tState.filters[pCategory].hasOwnProperty(value)) + { + tTagValue["value"] = value; + tDisplayedFilters.push(tTagValue); + } }); - // Display them in alphabetical order going down the table, - // rather than across - var tRowCount = Math.ceil(tDisplayedFilters.length / 2); - var tOddNumber = tDisplayedFilters.length % 2 == 1; - for (i = 1; i <= tRowCount; i++) + if (pCategory == 'associations') { - tHTML += '' - tHTML += filter_cell(pCategory, tDisplayedFilters[i-1]); - if (i != tRowCount || !tOddNumber) - tHTML += filter_cell(pCategory, tDisplayedFilters[i - 1 + tRowCount]); - tHTML += ''; + // Display associations one per line + for (i = 1; i <= tDisplayedFilters.length; i++) + { + tHTML += '' + tHTML += filter_cell(pCategory, tDisplayedFilters[i-1], true); + tHTML += ''; + tHTML += ''; + } + } + else + { + // Display them in alphabetical order going down the table, + // rather than across + var tRowCount = Math.ceil(tDisplayedFilters.length / 2); + var tOddNumber = tDisplayedFilters.length % 2 == 1; + for (i = 1; i <= tRowCount; i++) + { + tHTML += '' + tHTML += filter_cell(pCategory, tDisplayedFilters[i-1], false); + if (i != tRowCount || !tOddNumber) + tHTML += filter_cell(pCategory, tDisplayedFilters[i - 1 + tRowCount], false); + tHTML += ''; + } } tHTML += ''; @@ -275,17 +444,18 @@ function displayFilters(){ // First display the applied filters var tHTML = ""; - $.each(tState.filters, function(filter_tag, filter_data) + $.each(tState.filters, function(filter_category, filter) { tHTML += '
'; - tHTML += ''+filter_tag+': '; - $.each(filter_data, function(index, filter_name) + tHTML += ''+filter_category+': '; + $.each(filter, function(value, name) { tHTML += ''; }); tHTML += '
'; @@ -353,6 +523,9 @@ if (value.hasOwnProperty("deprecated") && value.deprecated != '') tClass = " deprecated"; + if (value.hasOwnProperty("edition") && value.edition != '' && value.edition.toLowerCase() != 'community') + tClass = " "+value.edition.toLowerCase(); + tHTML += ''; tHTML += ''+value["display name"]+''; @@ -378,8 +551,10 @@ var tData; if (pTerm) tData = dataSearch(pTerm); - else + else { + tState . cached_search_data = {}; tData = tState . filtered_data; + } sortFilteredData(tData); @@ -387,6 +562,9 @@ tHTML = data_table_html(tData); $("#table_list").html(tHTML); + + $(window).scrollTop(0); + $("#table_container").scrollTop(0); } function displayLibraryChooser(){ @@ -462,32 +640,116 @@ return tSection; } + // Add a background highlight to search terms found in syntax and synonyms + var kSpanStartMarker = String.fromCharCode(2); + var kSpanEndMarker = String.fromCharCode(3); + var kSpanStartRegex = new RegExp(kSpanStartMarker, "g"); + var kSpanEndRegex = new RegExp(kSpanEndMarker, "g"); + function highlightSearchTerms(pText) + { + var tText = removeHtmlEntityEscapes(pText); + + if($("#ui_filer").val() != "") + { + var tTerm = $("#ui_filer").val(); + var tokensOfTerm = tTerm.match(/\S+/g); + $.each(tokensOfTerm, function(index, matchToken) + { + var match_regex = new RegExp('(' + RegExp.escape(matchToken) + ')', "gi") + tText = tText.replace(match_regex, function($1){ + // Need to use placeholders since we need to remove HTML + // entities once done with adding hilighting. + return kSpanStartMarker + $1 + kSpanEndMarker; + }); + }); + } + tText = addHtmlEntityEscapes(tText); + tText = tText.replace(kSpanStartRegex, ""); + tText = tText.replace(kSpanEndRegex, ""); + return tText; + } + function displayEntry(pEntryID) - { - var tEntryObject = entryData(pEntryID); + { + var tIndex = entryIdToIndex(pEntryID); + displayEntryAtIndex(tIndex); + } + + function syntax_to_string(pSyntax) + { + var tHtml = ''; + $.each(pSyntax, function(index, value) { + if (index > 0) + tHtml += '
'; + tHtml += replace_link_placeholders_with_param(value).replace(/[\n\r]/g, '
'); + }); + return tHtml; + } + + // Associations must be one of the following: + const s_association_types = ["object","library","glossary","module","widget"]; + function resolve_association_index(pName, pAPI) + { + var tIndex; + $.each(s_association_types, function(tTypeIndex, tType) { + tIndex = entryNameToIndex(pName, tType, pAPI) + if (isDefined(tIndex)) + return false; + }); + return tIndex; + } + + function displayEntryAtIndex(pIndex) + { + var tEntryObject = tState.data[pIndex]; + history_add(tEntryObject); - pEntryID = tEntryObject.id; - - console.log(tEntryObject); - - if(tState.selected == pEntryID) return 1; - tState.selected = pEntryID; - $.session.set("selected", pEntryID); + var tEntryId = tEntryObject.id; + if (tState.selected_entry_index[tState.selected_api_id] == pIndex) return 1; + tState.selected_entry_index[tState.selected_api_id] = pIndex; + $.session.set("selected_entry_index", tState.selected_entry_index); + breadcrumb_draw(); $(".entry_list_item").removeClass("active"); - $("#entry_list_item_"+pEntryID).addClass("active"); - selectedEntryEnsureInView(tEntryObject.id); + $("#entry_list_item_"+tEntryId).addClass("active"); + selectedEntryEnsureInView(tEntryId); var tHTML = ""; var references = []; - tHTML += '

'+tEntryObject["display name"]+'

'; + + tHTML += '

'+tEntryObject["display name"]; + + var tUpgrade = true; + if (!tEntryObject.hasOwnProperty("edition")) + tUpgrade = false; + else if (tState.edition == "professional") + tUpgrade = false; + else if (tState.edition == "commercial" && tEntryObject["edition"].toLowerCase() != "business") + tUpgrade = false; + else if (tState.edition == "communityplus" && (tEntryObject["edition"].toLowerCase() != "business" || tEntryObject["edition"].toLowerCase() != "indy")) + tUpgrade = false; + else if (tEntryObject["edition"].toLowerCase() == "community") + tUpgrade = false; + + if (tUpgrade) + { + tHTML += ' Upgrade to ' + tEntryObject["edition"] + ''; + } + + tHTML += '

'; + $.each(tEntryObject, function(index, value) { - if(index == "id" || index == "name") return; - switch(index){ + case "id": + case "name": + case "library": + // These are for 'meta' information, not for display + return; case "examples": tHTML += '
'+index+'
'; if($.isArray(value)){ @@ -526,12 +788,12 @@ tHTML += reference_type + ': '; var reference_html = ""; $.each(reference_array, function(reference_index, reference_name) { - var tReference, tID; - tID = entryNameToID(reference_name, reference_type); - if (tID == 0) - tReference = reference_name; + var tReference, tIndex; + tIndex = entryNameToIndex(reference_name, reference_type, tEntryObject.library); + if (isDefined(tIndex)) + tReference = click_text_from_index(reference_name, tIndex); else - tReference = click_text(reference_name, tID); + tReference = reference_name; if (reference_html == "") reference_html = tReference; @@ -546,16 +808,14 @@ break; case "syntax": - var tSyntaxHTML = ""; tHTML += '
'+index+'
'; if($.isArray(value)){ $.each(value, function(index2, value2) { - tHTML += '
' + remove_link_placeholders(value2) + '
'; + tHTML += '
' + highlightSearchTerms(remove_link_placeholders(value2)) + '
'; }); } else { - tSyntaxHTML += 'Malformed syntax in JSON'; + tHTML += 'Malformed syntax in JSON'; } - tHTML += tSyntaxHTML; tHTML += '
'; break; case "associations": @@ -563,21 +823,19 @@ tHTML += '
'+index+'
'; var association_html = ""; $.each(value, function(index2, value2) { - var tTypes, tType; - tTypes = ["object","library","glossary"]; - - var tID; - $.each(tTypes, function(tTypeIndex, tType) { - tID = entryNameToID(value2, tType) - if (tID != 0) - return; - }); + var tIndex = resolve_association_index(value2, tEntryObject.library); var tAssociation; - if (tID == 0) - tAssociation = value2; + if (isDefined(tIndex)) + { + var tName = value2; + if (tState.data[tIndex].hasOwnProperty("display name")) + tName = tState.data[tIndex]["display name"]; + + tAssociation = click_text_from_index(tName, tIndex); + } else - tAssociation = click_text(value2, tID); + tAssociation = value2; if (association_html == "") association_html = tAssociation; @@ -600,9 +858,13 @@ case "display syntax": case "changes": break; - - + case "edition": + tHTML += '
'+index+'
'; + tHTML += value; + tHTML += '
'; + break; + default: tHTML += '
'+index+'
'; @@ -616,7 +878,10 @@ tOutput += ', '; tOutput += content; }); - tHTML += tOutput; + if(index=="synonyms") + tHTML += highlightSearchTerms(tOutput); + else + tHTML += tOutput; } else tHTML += value; @@ -631,35 +896,48 @@ tHTML += markdown_section(value, tEntryObject); }); - // Now that the entry has been displayed we need to look at the type - // If it is object, we need to generate a list of actions / events and properties - // That can be set on the object. The entry if you like should be a pointer to - // Everything associated with the object. A cross between a overview and userguide - - if(tEntryObject.type == "object" || tEntryObject.type == "widget" || tEntryObject.type == "library"){ - var object_name = tEntryObject["display name"].toLowerCase(); + // Now that the entry has been displayed we need to look at the + // type. If it is one of the association types, we generate a + // list of API entries with this entry as an association + if (s_association_types.indexOf(tEntryObject.type) >= 0) + { + var object_name = tEntryObject["name"].toLowerCase(); var object_data = {}; - $.each(dataGet(),function(entry_index, entry_data){ - if(entry_data.hasOwnProperty("associations")){ - if(entry_data["associations"].indexOf(object_name) >= 0){ - if(!object_data.hasOwnProperty(entry_data.type)){ - object_data[entry_data.type] = []; + $.each(dataGet(),function(entry_index, entry_data) + { + // Ignore self + if (entry_index == pIndex) + return true; + + if (entry_data.hasOwnProperty("associations")) + { + $.each(entry_data["associations"], function(index, value) + { + if (value.toLowerCase() == object_name) + { + if (!object_data.hasOwnProperty(entry_data.type)) + { + object_data[entry_data.type] = []; + } + object_data[entry_data.type].push(entry_data); + return false; } - object_data[entry_data.type].push(entry_data); - } + }); } }); - $.each(object_data,function(item_type, item_data){ + $.each(object_data, function(item_type, item_data) + { tHTML += '
'+item_type+'
'; tHTML += ''; tHTML += ''; - $.each(item_data,function(item_intex, entry_data){ + $.each(item_data, function(item_intex, entry_data) + { tHTML += ''; tHTML += ''; tHTML += ''; - tHTML += ''; + tHTML += ''; tHTML += ''; }); tHTML += '
NameSummarySyntax
' + click_text_from_entry_data('', entry_data) +''+replace_link_placeholders_with_param(entry_data.summary)+''+replace_link_placeholders_with_param(entry_data.syntax[0])+''+syntax_to_string(entry_data.syntax)+'
'; @@ -734,10 +1012,10 @@ if(return_text == matched_whole){ var resolved = resolve_link_placeholder(matched_text); - var resolved_id = resolve_link(pEntryObject, resolved[1], resolved[2]); + var resolved_index = resolve_link(pEntryObject, resolved[1], resolved[2]); - if (resolved_id != 0) - return_text = click_text(resolved[0], resolved_id) + if (isDefined(resolved_index)) + return_text = click_text_from_index(resolved[0], resolved_index) else return_text = resolved[0]; } @@ -759,14 +1037,20 @@ return click_text(pLink, pEntryData.id); } - function click_text(pText, pID) + function click_text_from_index(pText, pIndex) { var text; text = ''; return text; } + + function click_text(pText, pID) + { + var tIndex = entryIdToIndex(pID); + return click_text_from_index(pText, tIndex) + } function undo_link_replacement(pText) { @@ -802,10 +1086,10 @@ // Return an entry ID from the target name and optional type function resolve_link(pEntryObject, pTargetName, pTargetType) { - var entry_id; + var tIndex; if(pTargetType){ // Know name and type so lookup id - entry_id = entryNameToID(pTargetName,pTargetType); + tIndex = entryNameToIndex(pTargetName,pTargetType,pEntryObject.library); } else { // Work out the type from the reference if(pEntryObject.hasOwnProperty("references")) { @@ -813,18 +1097,18 @@ $.each(reference_array, function(reference_index, reference_name) { if (reference_name == pTargetName) { - entry_id = entryNameToID(reference_name,reference_type); + tIndex = entryNameToIndex(reference_name,reference_type,pEntryObject.library); return; } }); // Just find the first one if no type was specified. - if (entry_id) + if (isDefined(tIndex)) return; }); } } - return entry_id; + return tIndex; } function entryData(pEntryID){ @@ -841,41 +1125,87 @@ return tData; } - function entryNameToID(pName,pType){ - var tID = 0; - - $.each(dataGet(), function( index, value) { - if((value.name == pName || value["display name"] == pName) && value.type == pType){ - tID = value.id; - return false; + function entryNameToIndex(pName,pType,pPriorityLibrary){ + pName = pName.toLowerCase(); + pType = pType.toLowerCase(); + pPriorityLibrary = pPriorityLibrary.toLowerCase(); + + var tIndex; + $.each(dataGet(), function(index, value) { + if (value.name.toLowerCase() != pName + && value["display name"].toLowerCase() != pName) + { + // Continue loop + return true; + } + + if (pType != '') + { + if (value.type.toLowerCase() != pType) + { + // Continue loop + return true; + } + } + + // Make sure we always 'fall back' to the lcs syntax + if (value.library == 'livecode_script') + { + tIndex = index; + // If no library was specified, assume lcs syntax + if (pPriorityLibrary == '') + { + // We're done + return false; + } + + // Otherwise, this index is now a candidate in case + // there is no entry found in the given library } + if (pPriorityLibrary == '') + { + // If no library was specified, this index is a + // candidate. + tIndex = index + return true; + } + else if (value.library.toLowerCase() != pPriorityLibrary) + { + // Continue loop + return true; + } + + // We have a perfect match! + tIndex = index; + return false; }); - return tID; + return tIndex; } - function entryIDToArrayKey(pID){ - var tID = 0; - $.each(dataGet(), function( index, value) { - if(value.id == pID){ - tID = index; + function entryIdToIndex(pId){ + var tIndex = 0; + + $.each(dataGet(), function(index, value) { + if(value.id == pId){ + tIndex = index; return false; } }); - return tID; - } + return tIndex; + } function breadcrumb_draw() { var tHistory = tState.history.list; - if (tState.history.selected > 0) + if (tState.history.selected_index > 0) $('#lcdoc_history_back').removeClass('disabled'); else $('#lcdoc_history_back').addClass('disabled'); - if (tState.history.selected < tHistory.length - 1) + if (tState.history.selected_index < tHistory.length - 1) $('#lcdoc_history_forward').removeClass('disabled'); else $('#lcdoc_history_forward').addClass('disabled'); @@ -891,7 +1221,7 @@ var tHistoryList = ''; $.each(tHistory, function(index, value) { - if (index == tState.history.selected) + if (index == tState.history.selected_index) tHistoryList += '
  • '; else { @@ -933,7 +1263,7 @@ tHTML += '
  • '; tHTML += value.value + ''; if (nonEmptyElement(value, "description")) - tHTML += ' -' + value.description; + tHTML += ' - ' + value.description; tHTML += '
  • '; }); tHTML += ""; @@ -975,12 +1305,12 @@ function history_selected_entry() { - return tState.history.list[tState.history.selected]; + return tState.history.list[tState.history.selected_index]; } function history_add(pEntryObject) - { - if (tState.history.selected != -1) + { + if (tState.history.selected_index != -1) { // If this is the currently selected item, don't do anything if (history_selected_entry().id == pEntryObject.id) @@ -1005,43 +1335,89 @@ tNewHistory.push(tObject); tState.history.list = tNewHistory; - tState.history.selected = tNewHistory . length - 1; + tState.history.selected_index = tNewHistory . length - 1; } function history_back() { - go_history(tState.history.selected - 1); + if(tState.history.selected_index > 0){ + go_history(tState.history.selected_index - 1); + } } function history_forward() { - go_history(tState.history.selected + 1); + if(tState.history.selected_index < tState.history.list.length - 1){ + go_history(tState.history.selected_index + 1); + } } function go_history(pHistoryID) { - tState.history.selected = pHistoryID + tState.history.selected_index = pHistoryID displayEntry(history_selected_entry().id); } - function entry_next(){ - var tSelectedID = tState.selected; + function entry_previous() + { + var tSelectedID = tState.history.list[tState.history.selected_index].id; + var tPreviousID = tSelectedID; + + if(tState.cached_search_data.hasOwnProperty("term")) + { + $.each(tState.cached_search_data.data, function( index, value) { + if(value.id == tSelectedID){ + if(index > 0){ + tPreviousID = tState.cached_search_data.data[index-1].id; + } + } + }); + } + else + { + $.each(tState.filtered_data, function( index, value) { + if(value.id == tSelectedID){ + if(index > 0){ + tPreviousID = tState.filtered_data[index-1].id; + } + } + }); + } + + displayEntry(tPreviousID); + } + + function entry_next() + { + var tSelectedID = tState.history.list[tState.history.selected_index].id; var tNextID = tSelectedID; - $.each(tState.filtered_data, function( index, value) { - if(value.id == tSelectedID){ - if(tState.filtered_data[index+1]){ - tNextID = tState.filtered_data[index+1].id; + if(tState.cached_search_data.hasOwnProperty("term")) + { + $.each(tState.cached_search_data.data, function( index, value) { + if(value.id == tSelectedID){ + if(tState.cached_search_data.data[index+1]){ + tNextID = tState.cached_search_data.data[index+1].id; + } } - } - - }); + }); + } + else + { + $.each(tState.filtered_data, function( index, value) { + if(value.id == tSelectedID){ + if(tState.filtered_data[index+1]){ + tNextID = tState.filtered_data[index+1].id; + } + } + }); + } + displayEntry(tNextID); } function library_set(pLibraryID){ - var tChooserLabel = 'Choose API: '; - tChooserLabel += library_id_to_name(pLibraryID); + var tChooserLabel = library_id_to_name(pLibraryID); $("#lcdoc_library_chooser_text").html(tChooserLabel); @@ -1051,15 +1427,21 @@ { tState.selected_api_id = pLibraryID; $.session.set("selected_api_id", pLibraryID); - tState.selected = "" - tState.history = {list:[], selected:-1}; - tState.searched = {}; + var tIndex = 0; + if (tState.selected_entry_index.hasOwnProperty(pLibraryID)) + { + tIndex = tState.selected_entry_index[pLibraryID]; + } + + tState.history = {list:[], selected_index:-1}; + tState.cached_search_data = {}; tState.filters= {}; tState.filtered_data = []; tState.data = ""; - + tState.selected_entry_index[pLibraryID] = -1; + dataFilter(); - displayEntry(1); + displayEntryAtIndex(tIndex); } } } @@ -1082,21 +1464,6 @@ return tID; } - function entry_previous(){ - var tSelectedID = tState.selected; - var tPreviousID = tSelectedID; - - $.each(tState.filtered_data, function( index, value) { - if(value.id == tSelectedID){ - if(index > 0){ - tPreviousID = tState.filtered_data[index-1].id; - } - } - - }); - displayEntry(tPreviousID); - } - function selectedEntryEnsureInView(tEntryID) { var listTop = $("#list").offset().top; @@ -1111,15 +1478,30 @@ } } + function isDefined(pVar) + { + return (typeof pVar !== typeof undefined); + } + function goEntryName(pLibraryName, pEntryName, pEntryType) { var tLibraryID = library_name_to_id(pLibraryName); library_set(tLibraryID); - - var tID = entryNameToID(pEntryName, pEntryType); - if (tID == 0) - tID = 1; - displayEntry(tID); + + var tID; + if (pEntryName == '') + tID = 0; + else + tID = entryNameToIndex(pEntryName, pEntryType, pLibraryName); + + if (isDefined(tID)) + { + displayEntryAtIndex(tID); + } + else + { + displayEntryListGrep(pEntryName); + } } function isRunningInLiveCodeBrowser() @@ -1127,17 +1509,62 @@ return (typeof liveCode !== 'undefined'); } + function setEdition(pEdition) + { + tState.edition = pEdition; + } + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. Used to make search more responsive. + var debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + function setActions() { breadcrumb_draw(); - - $('#ui_filer').keyup(function() { - displayEntryListGrep(this.value); - }) + + $("body").on("click", ".upgrade", function() { + if (isRunningInLiveCodeBrowser()) + { + var tEdition = $(this).attr("edition"); + var tDisplayName = $(this).attr("display_name"); + liveCode.showUpgradeOptions(tEdition, tDisplayName); + } + else + { + window.location.href = 'https://livecode.com/products/livecode-platform/pricing/'; + } + }); + + // Delay search until 250ms after last character typed + $('#ui_filer').keyup( debounce( function() { + displayEntryListGrep(this.value); + if(tState.cached_search_data.hasOwnProperty("data") && + tState.cached_search_data.data.hasOwnProperty(0)) + displayEntry(tState.cached_search_data.data[0].id); + }, 250)); $("body").on( "click", ".load_entry", function() { - var tEntryID = $(this).attr("entryid"); - displayEntry(tEntryID); + var tEntryIndex = $(this).attr("entryindex"); + if (typeof tEntryIndex !== typeof undefined && tEntryIndex !== false) { + displayEntryAtIndex(tEntryIndex); + } + + var tEntryId = $(this).attr("entryid"); + if (typeof tEntryId !== typeof undefined && tEntryId !== false) { + displayEntry(tEntryId); + } }); $("body").on("click", ".list_sort", function() { @@ -1153,14 +1580,16 @@ $("body").on( "click", ".apply_filter", function() { var filter_tag = $(this).attr("filter_category"); - var filter_data = $(this).attr("filter_value"); - filter_add(filter_tag,filter_data); + var filter_value = $(this).attr("filter_value"); + var filter_name = $(this).attr("filter_name"); + filter_add(filter_tag,filter_value,filter_name); }); $("body").on( "click", ".remove_filter", function() { - var filter_tag = $(this).attr("filter_tag"); - var filter_data = $(this).attr("filter_data"); - filter_remove(filter_tag,filter_data); + var filter_tag = $(this).attr("filter_category"); + var filter_value = $(this).attr("filter_value"); + var filter_name = $(this).attr("filter_name"); + filter_remove(filter_tag,filter_value,filter_name); }); $("body").on( "click", ".external_link", function(e) { @@ -1202,14 +1631,6 @@ var tResizerMargin; tResizerMargin = parseInt($resizer.css('margin')); - function update_lcdoc_margin() - { - var tHeaderHeight; - tHeaderHeight = parseInt($('#header_panel_holder').css('height')); - - $('#lcdoc_body').css('margin-top', tHeaderHeight + 20); - } - function doTableResize() { var $textarea = $('#header_panel_holder'); @@ -1237,7 +1658,7 @@ tNewHeight = Math.max(tHeaderMinHeight, tNewHeight); var tContainerHeight; - tContainerHeight = tNewHeight - tHeaderMinHeight - tTableHeaderHeight - tResizerMargin; + tContainerHeight = tNewHeight - tHeaderMinHeight - tTableHeaderHeight - tResizerMargin + 5; $('#table_container').css('height', tContainerHeight); if (tContainerHeight < 5) @@ -1251,7 +1672,6 @@ $('#table_header').css('display', ''); } - update_lcdoc_margin(); }); $window.on('mouseup', function () { @@ -1267,7 +1687,7 @@ doTableResize(); }); - // Prevent mouse scroll on table bubbling to window level + // Prevent mouse scroll on table bubbling to window level function preventScrollBubble(pEventTarget, pScrollTarget) { pEventTarget.bind('mousewheel', function(e, d) { @@ -1286,40 +1706,38 @@ preventScrollBubble($("#lcdoc_list"), $("#table_container")); preventScrollBubble($("#filters_panel"), $("#filters_options")); - update_lcdoc_margin(); - $(document).keydown(function(e) { - switch(e.which) { - case 37: // left + switch(e.which) { + case 37: // left if(!$("#ui_filer").is(":focus")){ history_back(); e.preventDefault(); } break; - case 38: // up - if($("#table_list").hasClass("table_focused")){ - entry_previous(); - e.preventDefault(); - } - break; + case 38: // up + if($("#table_list").hasClass("table_focused")){ + entry_previous(); + e.preventDefault(); + } + break; - case 39: // right + case 39: // right if(!$("#ui_filer").is(":focus")){ history_forward(); e.preventDefault(); } break; - case 40: // down - if($("#table_list").hasClass("table_focused")){ - entry_next(); - e.preventDefault(); - } - break; + case 40: // down + if($("#table_list").hasClass("table_focused")){ + entry_next(); + e.preventDefault(); + } + break; - default: return; // exit this handler for other keys - } - + default: return; // exit this handler for other keys + } + }); } diff --git a/Documentation/html_viewer/js/guide_functions.js b/Documentation/html_viewer/js/guide_functions.js index 597fdf50c0..cab5c72ee6 100644 --- a/Documentation/html_viewer/js/guide_functions.js +++ b/Documentation/html_viewer/js/guide_functions.js @@ -67,10 +67,17 @@ { return ''; } - else + else if (tGuideLocation == 'ide') { return ''; } + else + { + var tExtImageFolder = ''; + return tExtImageFolder; + } }, renderer.link = function(href, title, text) diff --git a/Documentation/html_viewer/js/marked.js b/Documentation/html_viewer/js/marked.js index 96e9370577..4854b66460 100644 --- a/Documentation/html_viewer/js/marked.js +++ b/Documentation/html_viewer/js/marked.js @@ -2,4 +2,4 @@ * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) * https://github.com/chjj/marked */ -(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^
    /i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occurred:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/Documentation/html_viewer/resources/media/vertical_resizer_580.png b/Documentation/html_viewer/resources/media/vertical_resizer_580.png new file mode 100644 index 0000000000..3d922f197c Binary files /dev/null and b/Documentation/html_viewer/resources/media/vertical_resizer_580.png differ diff --git a/Documentation/specs/tutorial-syntax.md b/Documentation/specs/tutorial-syntax.md index 69793e6a8b..c2d560114e 100644 --- a/Documentation/specs/tutorial-syntax.md +++ b/Documentation/specs/tutorial-syntax.md @@ -63,6 +63,7 @@ The possible actions are as follows: | "go" "to" "step" | "add" "guide" "with" "rect" "to" | “interlude” + | "load" ("lesson" | "stack") The highlight action causes the tutorial stack to point at the relevant object on the screen. If there is no highlight action, the tutorial stack @@ -133,8 +134,19 @@ satisfied before continuing. | "fits" "guide" [ "with" "tolerance" ] | "there" "is" ( "a" | "an" ) | "there" "is" ( "a" | "an" ) "for" - | “is” (“clicked” | “selected” | “scripted” | “focused” | "grouped") - | “the” “tool” “is” (“edit” | “run” | “graphic”) - | “the” “of” “is” - | “pops” “up” “answer” “dialog” - | "this" "card" "is" \ No newline at end of file + | "is" ("clicked" | "selected" | "scripted" | "focused" | "grouped") + | "the" "tool" "is" ("edit" | "run" | "graphic") + | "the" "of" "is" + | "the" "of" "is" "changed" "with" "default" + | "pops" "up" "answer" "dialog" + | "this" "card" "is" + +The load action causes tutorial state to be loaded. If the "lesson" Source +is used, the tutorial runner will find the lesson with name Source in the +same lessons folder as the current tutorial, and run it to completion. The +resulting stack will then be available to use in the current tutorial. + +If the "stack" Source is used, a stack will be loaded from the internal +resources folder of the tutorial (_resources/). Any `cTutorialTag` custom +property of objects on the stack will be converted to tags for objects +which can subsequently be used in the current tutorial. diff --git a/Plugins/livecodeTestInterface.livecode b/Plugins/livecodeTestInterface.livecode index 96e56414b9..b6ee04aa21 100644 Binary files a/Plugins/livecodeTestInterface.livecode and b/Plugins/livecodeTestInterface.livecode differ diff --git a/Toolset/home.livecodescript b/Toolset/home.livecodescript index f3d22ffd96..df3488e334 100644 --- a/Toolset/home.livecodescript +++ b/Toolset/home.livecodescript @@ -2,6 +2,8 @@ constant kImportantTextColor = "#569e54" on startup + revSetTestEnvironment($TRAVIS is true) + -- MW-2011-03-13: Make sure the externals are empty on startup set the externals of me to empty @@ -26,6 +28,8 @@ on startup end try revInternal__Log "Leave", "Startup" + + return tError end startup on relaunch @@ -36,7 +40,7 @@ on relaunch -- Pass the relaunch request through a hook local tParameters - repeat with x = 1 to the paramCount() + repeat with x = 1 to the paramCount put param(x) into tParameters[x] end repeat dispatch command "revHookLaunchInstance" to me with tParameters @@ -50,7 +54,7 @@ on relaunch end if -- The hook did nothing, so do our default processing - repeat with x = 1 to the paramcount() + repeat with x = 1 to the paramcount local tStackFile put param(x) into tStackFile if there is a file tStackFile then -- open it @@ -195,12 +199,6 @@ on revInternal__openStack put the result into tSuccess end if - if tSuccess then - revInternal__setSplashStatus "Loading Debugger..." - revInternal__InitialiseDebugger - put the result into tSuccess - end if - if tSuccess then revInternal__setSplashStatus "Loading Plug-ins..." revInternal__InitialisePlugIns @@ -238,7 +236,7 @@ on revInternal__openStack end if if $REV_TOOLS_PATH is empty and (revInternal__CheckFileAssociations() is true) and (the platform is "win32") then - if revIDEPrefGet("DontShowFileAssociationsDialog") is not true then + if revIDEGetPreference("cDontShowFileAssociationsDialog") is not true then modal stack "revFileAssociations" end if end if @@ -499,36 +497,58 @@ command revInternal__SetupCustomizationPath end revInternal__SetupCustomizationPath function revInternal__StackFiles - local tDefaultFolder - put the defaultFolder into tDefaultFolder - local tPaletteFolder, tFolders put revEnvironmentToolsetPath() & slash & "palettes" into tPaletteFolder put tPaletteFolder into tFolders - set the defaultfolder to tPaletteFolder - repeat for each line tFolder in the folders + repeat for each line tFolder in folders(tPaletteFolder) if char 1 of tFolder is "." then next repeat put return & tPaletteFolder & slash & tFolder after tFolders end repeat put return & revEnvironmentToolsetPath() & slash & "libraries" after tFolders - if revEnvironmentIsInstalled() then - put return & revEnvironmentToolsetPath() after tFolders - else + if not revEnvironmentIsInstalled() then put return & revEnvironmentRepositoryPath() & slash & "ide-support" after tFolders + + -- legacy from commercial repo + put return & revEnvironmentCommercialRepositoryPath() & "/ide/Toolset/libraries" after tFolders + put revEnvironmentCommercialRepositoryPath() & "/ide/Toolset/palettes" into tPaletteFolder + repeat for each line tFolder in folders(tPaletteFolder) + if tFolder begins with "." then next repeat + put return & tPaletteFolder & slash & tFolder after tFolders + end repeat + + -- components + local tComponentFolder + put revEnvironmentCommercialRepositoryPath() & "/components" into tComponentFolder + repeat for each line tFolder in folders(tComponentFolder) + if tFolder begins with "." then next repeat + put return & tComponentFolder & slash & tFolder after tFolders + end repeat + + -- commercial extensions (ensure they are loaded from the repo) + local tExtensionFolder + put revEnvironmentCommercialRepositoryPath() & "/extensions/script-libraries" into tExtensionFolder + repeat for each line tFolder in folders(tExtensionFolder) + if tFolder begins with "." then next repeat + put return & tExtensionFolder & slash & tFolder after tFolders + end repeat + + -- extensions (ensure they are loaded from the repo) + put revEnvironmentRepositoryPath() & "/extensions/script-libraries" into tExtensionFolder + repeat for each line tFolder in folders(tExtensionFolder) + if tFolder begins with "." then next repeat + put return & tExtensionFolder & slash & tFolder after tFolders + end repeat end if - local tStackFiles, tStackName local tStackFilesA, tIDEVersion set the itemdel to "." put item 1 of the version into tIDEVersion repeat for each line tPath in tFolders - set the defaultfolder to tPath - - repeat for each line tFile in the files + repeat for each line tFile in files(tPath) if the last item of tFile is not among the items of "rev.livecode.livecodescript" then next repeat put item 1 to -2 of tFile into tStackName @@ -536,7 +556,7 @@ function revInternal__StackFiles local tVersion put empty into tVersion // AL-2015-02-18: [[ Named Stack Versions ]] Check if this stack should be loaded in this version. - if the number of items in tFile > 2 then + if not (tFile begins with "revidelibrary") and the number of items in tFile > 2 then get item -2 of tFile if it is a number then put it into tVersion @@ -547,19 +567,7 @@ function revInternal__StackFiles end if end if - if tStackName is "revpagesetupdialog" then put "Page Setup Dialog" into tStackName - else if tStackName is "revprintdialog" then put "Print Dialog" into tStackName - else if tStackName is "revcolorchooser" then put "Color Chooser" into tStackName - else if tStackName is "revfileselector" then put "File Selector" into tStackName - else if tStackName is "revanswerdialog" then put "Answer Dialog" into tStackName - else if tStackName is "revaskdialog" then put "Ask Dialog" into tStackName - else if tStackName is "revmessagebox" then put "Message Box" into tStackName - else if tStackName is "revscripteditor" then put "revNewScriptEditor" into tStackName - # AL-2015-03-12: [[ Bug ]] Make sure Linux stacks included in standalones have the correct name - else if tStackName is "revprinterchooser" then put "Printer Chooser" into tStackName - else if tStackName is "revpagesetup" then put "Page Setup" into tStackName - # AL-2015-09-25: [[ Bug 16000 ]] Don't load stack "revPreferences" into memory - causes issues with actual prefs. - else if tStackName is "revpreferences" then next repeat + if tStackName is "revpreferences" then next repeat // AL-2015-02-18: [[ Named Stack Versions ]] Choose a versioned stack file name over an unversioned one, and a later version over an earlier one. local tExistingVersion @@ -571,11 +579,17 @@ function revInternal__StackFiles end repeat end repeat - set the defaultFolder to tDefaultFolder - + lock messages repeat for each key tKey in tStackFilesA - put tKey & comma & tStackFilesA[tKey]["file"] & return after tStackFiles + try + put the short name of stack tStackFilesA[tKey]["file"] into tStackName + delete stack tStackName + put tStackName & comma & tStackFilesA[tKey]["file"] & return after tStackFiles + catch e + revInternal__Log "Error", "Could not load stack:" && tStackFilesA[tKey]["file"] + end try end repeat + unlock messages delete the last char of tStackFiles return tStackFiles end revInternal__StackFiles @@ -646,7 +660,7 @@ private command revInternal__SetupPreferences -- ensure the script of stack preferences is empty -- as setprops could be dangerous - set the script of stack "revpreferences" to empty + set the script of stack tPreferencesStackFile7 to empty put the stackFiles of stack "Home" into tStackFiles put return & "revPreferences", tPreferencesStackFile7 after tStackFiles @@ -744,7 +758,8 @@ command revInternal__ResetPreferences put "false" into tPropsArray["cShowRevolutionStacks"] put "22" into tPropsArray["cMenuHeight"] put "1067,251,1882,827" into tPropsArray["cRevDocsRect"] - put "Black" into tPropsArray["cBackDropColor"] + put "Gray88" into tPropsArray["cBackDropColor"] + put "Gray88" into tPropsArray["cBackdrop"] put "false" into tPropsArray["cREVMsgShowUIFrontScripts"] put "false" into tPropsArray["revstack"] put "100" into tPropsArray["cMacOSProgressScrollbarWidth"] @@ -802,7 +817,6 @@ command revInternal__ResetPreferences put "selectedObject" into tPropsArray["cREVMsgIntelligenceObject"] put "false" into tPropsArray["cSEHideErrors"] put "56" into tPropsArray["cFieldHeight"] - put "none" into tPropsArray["cBackDrop"] put "300" into tPropsArray["cREVUnmaximizedScriptHeight"] put "13,125" into tPropsArray["cToolsTopLeft"] put "--" into tPropsArray["cCommentCharacter"] @@ -893,7 +907,7 @@ local sSavePreferencesMessage command revInternal__SavePreferences cancel sSavePreferencesMessage - send "__revInternal_SavePreferences" to me in 500 milliseconds + send "__revInternal_SavePreferences" to me in 30 seconds put the result into sSavePreferencesMessage end revInternal__SavePreferences @@ -910,10 +924,12 @@ end __revInternal_SavePreferences private command revInternal__EnsureFolder pFolder revInternal__Log "Enter", "Ensuring Folder '" & pFolder & "'" - local tPath, tComponent + local tPath + local tComponent set the itemDelimiter to "/" - repeat for each item tComponent in pFolder + put item 1 of pFolder & "/" into tPath + repeat for each item tComponent in item 2 to -1 of pFolder put tComponent & "/" after tPath if there is no folder (char 1 to -2 of tPath) then create folder char 1 to -2 of tPath @@ -991,7 +1007,57 @@ command revInternal__InstallFileAssociations end if end revInternal__InstallFileAssociations -local sLogIndent, sLogPath +local sLogIndent, sLogPath, sLog +private command revInternal__LogToFile pType, pMessage + if sLogPath is empty then + exit revInternal__LogToFile + end if + + open file sLogPath for text append + + if pType is not "Message" then + put pType && pMessage into pMessage + end if + + repeat for each line tLine in pMessage + if sLogIndent > 0 then + write char 1 to sLogIndent of " " to file sLogPath + end if + write tLine & return to file sLogPath + end repeat + + close file sLogPath +end revInternal__LogToFile + +private command revInternal__LogToVariable pType, pMessage + if pType is "Error" then + repeat for each line tLine in pMessage + put tLine & return after sLog["Error"] + end repeat + end if + + if pType is not "Message" then + put pType && pMessage into pMessage + end if + + repeat for each line tLine in pMessage + if sLogIndent > 0 then + put char 1 to sLogIndent of " " after sLog["Message"] + end if + put tLine & return after sLog["Message"] + end repeat + +end revInternal__LogToVariable + +-- For test mode +function revEnvironmentGetStartupLog pType + if sTestEnvironment is not true then + return empty + end if + + return sLog[pType] +end revEnvironmentGetStartupLog + command revInternal__Log pType, pMessage if pType is "Start" then local tLogPath @@ -1025,32 +1091,17 @@ command revInternal__Log pType, pMessage exit revInternal__Log end if - if sLogPath is empty then - exit revInternal__Log - end if - - open file sLogPath for text append - if pType is "Leave" then subtract 2 from sLogIndent - end if - - if pType is not "Message" then - put pType && pMessage into pMessage - end if - - repeat for each line tLine in pMessage - if sLogIndent > 0 then - write char 1 to sLogIndent of " " to file sLogPath - end if - write tLine & return to file sLogPath - end repeat - - if pType is "Enter" then + else if pType is "Enter" then add 2 to sLogIndent end if - close file sLogPath + if sTestEnvironment is true then + revInternal__LogToVariable pType, pMessage + else + revInternal__LogToFile pType, pMessage + end if end revInternal__Log -------------------------------------------------------------------------------- @@ -1068,7 +1119,7 @@ command revInternal__InitialiseSystem if it is empty then get "Small" end if - if sLicensePlatform is "Windows" and the word 2 of the systemVersion >= "5.1" and it is not "None" then + if sLicensePlatform is "Windows" and it is not "None" then local tCrashSettings, tVersion put the version into tVersion replace "." with "_" in tVersion @@ -1127,64 +1178,72 @@ end revInternal__FilterHandlerList command revInternal__InitialiseLibraries revInternal__Log "Enter", "Libraries Initialisation" - - insert script of stack "revInitialisationLibrary" into back - - # BB-2014-09-30: New IDE library - try - insert script of stack "revideextensionlibrary" into back - insert script of stack "revidedeveloperextensionlibrary" into back - insert script of stack "revsaveasstandalone" into back - insert script of stack "revsaveasiosstandalone" into back - insert script of stack "revsaveasandroidstandalone" into back - insert script of stack "revsaveasemscriptenstandalone" into back - catch tError - answer "Error loading extensions library" & return & tError - end try - # AL-2015-11-15 : New documentation library - revInternal__LoadLibrary "revIDEDocumentationLibrary" - try - revInternal__LoadLibrary "revIDELibrary.8" - revInternal__LoadLibrary "revidemessagehandlerlibrary" + insert script of stack "revInitialisationLibrary" into back catch tError - answer "Error loading main IDE" & return & tError - end try - - revInternal__LoadLibrary "revBackScriptLibrary" - - revInternal__LoadLibrary "revSBLibrary" - # MW-2011-04-11: New deploy library for Android/iOS simulate/test support - revInternal__LoadLibrary "revDeployLibrary" + revInternal__Log "Error", "Error loading initialisation library" & return & tError + end try - # OK-2008-03-11 : New debugger and metadata library - revInternal__LoadLibrary "revDebuggerLibrary" - revInternal__LoadLibrary "revMetadataLibrary" + revInternal_SetJAVA_HOME + + local tLoadList + put "revCommonLibrary" into tLoadList + put return & "revDatabaseLibrary" after tLoadList + put return & "revIDEDocumentationLibrary" after tLoadList + put return & "revMetadataLibrary" after tLoadList + put return & "revSBLibrary" after tLoadList + put return & "revIDELibrary" after tLoadList + put return & "revidemessagehandlerlibrary" after tLoadList + put return & "revBackScriptLibrary" after tLoadList + put return & "revDeployLibrary" after tLoadList + put return & "revDebuggerLibrary" after tLoadList + put return & "revLibUrl" after tLoadList + put return & "revPrintLibrary" after tLoadList + put return & "revAnimationLibrary" after tLoadList + put return & "revGeometryLibrary" after tLoadList + put return & "revXMLRPCLibrary" after tLoadList + put return & "revProfilesLibrary" after tLoadList + put return & "revTableLibrary" after tLoadList + put return & "revhtml5urllibrary" after tLoadList + + if revEnvironmentEditionProperty("autocomplete_pro") then + put return & "autocomplete-pro" after tLoadList + end if - # OK-2008-11-25 : revOnline library - insert the script of stack "revOnlineLibrary" into back + if revEnvironmentEditionProperty("autocomplete") then + put return & "autocomplete" after tLoadList + end if - revInternal__LoadLibrary "revIdeLibrary" - revInternal__LoadLibrary "revLibUrl" - revInternal__LoadLibrary "revCommonLibrary" - revInternal__LoadLibrary "revPrintLibrary" - revInternal__LoadLibrary "revAnimationLibrary" - revInternal__LoadLibrary "revGeometryLibrary" - revInternal__LoadLibrary "revXMLRPCLibrary" - revInternal__LoadLibrary "revProfilesLibrary" - revInternal__LoadLibrary "revDatabaseLibrary" - revInternal__LoadLibrary "revTableLibrary" + local tBackList + put "revidedeveloperextensionlibrary" into tBackList + put return & "revsaveasstandalone" after tBackList + put return & "revsaveasiosstandalone" after tBackList + put return & "revsaveasandroidstandalone" after tBackList + put return & "revsaveasemscriptenstandalone" after tBackList + put return & "revOnlineLibrary" after tBackList + put return & "revCore" after tBackList - // EJB - New IDE Libraries + # AL-2015-09-02: [[ Bug 15841 ]] Temporarily add project browser library to prevent preference errors + put return & "revIDEProjectBrowserLibrary" after tBackList + + local tLib + repeat for each line tLib in tLoadList + revInternal__Log "Message", "Loading library" && tLib + revInternal__LoadLibrary tLib + if the result is not empty then + revInternal__Log "Error", the result + end if + end repeat - try - insert script of stack "revCore" into back + try + repeat for each line tLib in tBackList + insert script of stack tLib into back + end repeat + catch tError + revInternal__Log "Error", "Error loading library" && tLib & return & tError end try - # AL-2015-09-02: [[ Bug 15841 ]] Temporarily add project browser library to prevent preference errors - insert script of stack "revIDEProjectBrowserLibrary" into back - # MW-2010-10-13: [[ Bug 8600 ]] Make sure the handler lists of the rev frontscript, backscript and shortcuts script # are all up to date (used by revNoMessages script). set the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" to revInternal__FilterHandlerList(the revAvailableHandlers of stack "revBackScriptLibrary") @@ -1343,13 +1402,6 @@ command revInternal__InitialiseDefaults break case "Windows" set the hidePalettes to false - - if word 1 of the systemVersion is "Windows" then - set the shellCommand to "command.com" - else - set the shellCommand to "cmd.exe" - end if - hide stack "revCursors" break case "Linux" @@ -1599,17 +1651,18 @@ command revInternal__InitialiseProjectBrowser end revInternal__InitialiseProjectBrowser command revInternal__InitialiseMessageBox - revInternal__Log "Enter", "Message Box Initialisation" - - if the platform is among the items of "MacOS,Win32" then - set the style of stack "Message Box" to "palette" - else - set the style of stack "Message Box" to "modeless" - end if - - revInternal__Log "Leave", "Message Box Initialisation" - - return true + revInternal__Log "Enter", "Message Box Initialisation" + + if the platform is among the items of "MacOS,Win32" then + set the style of stack "Message Box" to "palette" + else + set the style of stack "Message Box" to "modeless" + end if + dispatch "ideInitialiseMessageBox" to stack "Message Box" + + revInternal__Log "Leave", "Message Box Initialisation" + + return true end revInternal__InitialiseMessageBox command revInternal__InitialisePlugIns @@ -1635,19 +1688,27 @@ command revInternal__InitialiseFinalSteps --the following *MUST* be the last item to avoid excess sending to overview as environment loads revInternal__Log "Message", "Installing Remaining Libraries" + revInternal__LoadLibrary "revFrontScriptLibrary" + if the result is not empty then + revInternal__Log "Error", the result + end if + set the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" to revInternal__FilterHandlerList(the revAvailableHandlers of stack "revFrontScriptLibrary") revInternal__LoadLibrary "revShortCutsLibrary" + if the result is not empty then + revInternal__Log "Error", the result + end if + set the cREVGeneral["handlerlist"] of stack "revShortCutsLibrary" to revInternal__FilterHandlerList(the revAvailableHandlers of stack "revShortCutsLibrary") - //insert script of btn "revShortcuts" of cd 1 of stack "revLibrary" into front revInternal__Log "Message", "Setting up verbose debugging" send "revVerboseDebug" && the cVerboseDebug of stack "revPreferences" to stack "revFrontScriptLibrary" - if the cBackDrop of stack "revPreferences" is not "none" and the cBackDrop of stack "revPreferences" is not empty then + if the cBackDrop of stack "revPreferences" is not "none" then revInternal__Log "Message", "Setting up backdrop" - set the backdrop to the cBackDrop of stack "revPreferences" + set the backdrop to the cBackDropColor of stack "revPreferences" end if revInternal__Log "Message", "Closing Splash" @@ -1665,24 +1726,12 @@ command revInternal__InitialiseFinalSteps end if revInternal__Log "Message", "Initialising revFrontScript" - --send "preOpenStack" to stack "revFrontScriptLibrary" in 5 milliseconds - --send "preOpenStack" to stack "revFrontScriptLibrary" in 5 milliseconds revInternal__Log "Leave", "Final Initialisation" return true end revInternal__InitialiseFinalSteps -# OK-2008-03-11 -# Description -# Initializes the debugger. This resets the breakpoints property to the appropriate -# value for IDE startup. This command must be called after the preferences stack has -# been initialized. -command revInternal__InitialiseDebugger - send "revDebuggerInitialize" to stack "revDebuggerLibrary" - return true -end revInternal__InitialiseDebugger - command revInternal__BuildDictionary revInternal__Log "Enter", "Building Dictionary" revIDEGenerateDistributedDocs @@ -1722,7 +1771,7 @@ command revInternal__ConstrainStack pStack else -- We assume this is about 30 pixels put 30 into tTitleBarHeight - if the platform is "macos" and char 1 of the systemVersion is "1" then + if the platform is "macos" then put 0 into tBorderWidth else put 5 into tBorderWidth @@ -1817,6 +1866,176 @@ function revEnvironmentToolsetPath return hookToolsPath("toolset", sToolsPath & "/Toolset") end revEnvironmentToolsetPath +function revEnvironmentEditionProperty pProp, pEdition + if pEdition is empty then + put the editionType into pEdition + end if + + if pProp is "skin" then + return revEnvironmentToolsetPath() & "/resources/" & pEdition & "/ideSkin" + end if + + switch pEdition + case "community" + switch pProp + case "name" + return "Community" + case "color" + return 173,208,54 + case "pb_line_selected_color" + return 226,238,185 + case "revonline_hilite_color" + return 156,199,45 + case "revabout_hilite_color" + return 106,139,15 + case "revsplash_text_color" + return 0,0,0 + case "start_center_tile_color_step" + return -9 + case "password_protection" + return false + case "open_source_required" + return true + case "splash_strap" + return empty + case "upgrade_mini_url" + return "https://livecode.com/products/community-plus-ide-2/" + case "upgrade_url" + return "https://livecode.com/products/community-plus-ide/" + case "upgrade_edition" + return "communityplus" + case "edition_external_url" + return "https://livecode.com/products/community-edition/" + case "autocomplete" + case "autocomplete_pro" + return false + case "script_profiler" + return false + end switch + break + case "communityplus" + switch pProp + case "name" + return "Community Plus" + case "color" + return 49,163,102 + case "pb_line_selected_color" + return 226,238,185 + case "revonline_hilite_color" + return 49,163,102 + case "revabout_hilite_color" + return 49,163,102 + case "revsplash_text_color" + return 0,0,0 + case "start_center_tile_color_step" + return -9 + case "password_protection" + return false + case "open_source_required" + return true + case "splash_strap" + return empty + case "upgrade_mini_url" + return empty + case "upgrade_url" + return empty + case "upgrade_edition" + return "commercial" + case "edition_external_url" + return "https://livecode.com/products/community-plus-edition/" + case "autocomplete" + return true + case "autocomplete_pro" + return false + case "script_profiler" + return false + end switch + break + case "indy" + case "commercial" + switch pProp + case "name" + return "Indy" + case "color" + return 28,154,206 + case "pb_line_selected_color" + return 222,243,255 + case "revonline_hilite_color" + return 124,193,222 + case "revabout_hilite_color" + return 44,113,170 + case "revsplash_text_color" + return 0,0,0 + case "start_center_tile_color_step" + return 0 + case "password_protection" + return true + case "open_source_required" + return false + case "splash_strap" + if revLicenseInfo["com.livecode.norevenuelimit"] is not empty then + return empty + else + return "

    This Indy license is only valid for organizations with annual revenues of $500,000 USD or less

    " + end if + case "upgrade_mini_url" + return empty + case "upgrade_url" + return empty + case "upgrade_edition" + return "professional" + case "edition_external_url" + return "https://livecode.com/products/indy-edition/" + case "autocomplete" + case "autocomplete_pro" + return true + case "script_profiler" + return false + end switch + break + case "business" + case "professional" + switch pProp + case "name" + return "Business" + case "color" + return 82,82,82 + case "pb_line_selected_color" + return 222,243,255 + case "revonline_hilite_color" + return 124,193,222 + case "revabout_hilite_color" + return 44,113,170 + case "revsplash_text_color" + return 255,255,255 + case "start_center_tile_color_step" + return 0 + case "password_protection" + return true + case "open_source_required" + return false + case "splash_strap" + return empty + case "upgrade_mini_url" + return empty + case "upgrade_url" + return empty + case "upgrade_edition" + return empty + case "edition_external_url" + return "https://livecode.com/products/business-edition/" + case "autocomplete" + case "autocomplete_pro" + return true + case "script_profiler" + return true + end switch + break + end switch + + throw "Unknown edition property" +end revEnvironmentEditionProperty + function revEnvironmentPluginsPath return hookToolsPath("plugins", sToolsPath & "/Plugins") end revEnvironmentPluginsPath @@ -1839,12 +2058,16 @@ function revEnvironmentExternalsPath end revEnvironmentExternalsPath function revEnvironmentExtensionsPath + return line 1 of revEnvironmentExtensionsPaths() +end revEnvironmentExtensionsPath + +function revEnvironmentExtensionsPaths if revEnvironmentIsInstalled() then return hookToolsPath("extensions", sToolsPath & "/Extensions") else - return revEnvironmentBinariesPath() & slash & "packaged_extensions" + return sBinariesPath & slash & "packaged_extensions" end if -end revEnvironmentExtensionsPath +end revEnvironmentExtensionsPaths function revEnvironmentRuntimePath return hookToolsPath("runtime", sToolsPath & "/Runtime") @@ -1953,50 +2176,65 @@ end revEnvironmentBinariesPath // SN-2015-05-15: [[ DeployAllPlatforms ]] Allow the deployment to happen for any // platform, from any repository platform -function revEnvironmentNonNativeBinariesPath pPlatform - local tNonNativeBinariesPath, tReleaseFolder, tDebugFolder - put sBinariesPath into tNonNativeBinariesPath - - set the itemDelimiter to slash - - // If the platform is Linux, there will be archs - if the platform is "linux" then - delete item -3 to -1 of tNonNativeBinariesPath - else - delete item -2 to -1 of tNonNativeBinariesPath - end if - - // Init to lower-case, will change if Mac platform - put "release" into tReleaseFolder - put "debug" into tDebugFolder +function revEnvironmentNonNativeBinariesPath pPlatform, pSDK + local tNonNativeBinariesPath + put sRepositoryPath into tNonNativeBinariesPath switch pPlatform case "Windows" - put slash & "windows" after tNonNativeBinariesPath + put slash & "win-x86-bin" after tNonNativeBinariesPath + break + case "Windows x86-64" + case "Windows x64" + case "Windows x86_64" + put slash & "win-x86_64-bin" after tNonNativeBinariesPath break case "Linux" - put slash & "linux/i386" after tNonNativeBinariesPath + put slash & "linux-x86-bin" after tNonNativeBinariesPath break + case "Linux x86-64" case "Linux x64" - put slash & "linux/x86_64" after tNonNativeBinariesPath + case "Linux x86_64" + put slash & "linux-x86_64-bin" after tNonNativeBinariesPath + break + case "Linux armv6_hf" + put slash & "linux-armv6_hf-bin" after tNonNativeBinariesPath break case "MacOS" - case "MacOSX PowerPC-32" case "MacOSX x86-32" - put slash & "mac" after tNonNativeBinariesPath - put "Release" into tReleaseFolder - put "Debug" into tDebugFolder + case "MacOSX x86_32" + case "MacOSX x86-64" + case "MacOSX x64" + case "MacOSX x86_64" + put slash & "mac-bin" after tNonNativeBinariesPath + break + case "Android" + case "Android armv6" + put slash & "android-armv6-bin" after tNonNativeBinariesPath + break + case "Android armv7" + put slash & "android-armv7-bin" after tNonNativeBinariesPath + break + case "Android arm64" + put slash & "android-arm64-bin" after tNonNativeBinariesPath + break + case "Android x86" + put slash & "android-x86-bin" after tNonNativeBinariesPath + break + case "Android x86_64" + put slash & "android-x86_64-bin" after tNonNativeBinariesPath + break + case "Emscripten" + case "HTML5" + put slash & "emscripten-bin" after tNonNativeBinariesPath + break + case "iOS" + put slash & "ios-bin" & slash & pSDK after tNonNativeBinariesPath break default return empty end switch - if the last item of sBinariesPath is "release" then - put slash & tReleaseFolder after tNonNativeBinariesPath - else - put slash & tDebugFolder after tNonNativeBinariesPath - end if - return tNonNativeBinariesPath end revEnvironmentNonNativeBinariesPath @@ -2005,6 +2243,10 @@ function revEnvironmentRepositoryPath return sRepositoryPath end revEnvironmentRepositoryPath +function revEnvironmentCommercialRepositoryPath + set the itemDelimiter to slash + return item 1 to -2 of sRepositoryPath +end revEnvironmentCommercialRepositoryPath -- Deprecated Path Functions @@ -2095,26 +2337,22 @@ end revEnvironmentGuessRepositoryPath -- function revEnvironmentPlatform - local tPlatform - - switch the platform - case "Linux" - put "Linux" into tPlatform - break - case "MacOS" - if char 1 of the systemVersion is 1 then - put "MacOS X" into tPlatform - else - put "MacOS Classic" into tPlatform - end if - break - case "Win32" - put "Windows" into tPlatform - break - default - put "Unsupported" into tPlatform - break - end switch - - return tPlatform + local tPlatform + + switch the platform + case "Linux" + put "Linux" into tPlatform + break + case "MacOS" + put "MacOS X" into tPlatform + break + case "Win32" + put "Windows" into tPlatform + break + default + put "Unsupported" into tPlatform + break + end switch + + return tPlatform end revEnvironmentPlatform diff --git a/Toolset/libraries/revanimationlibrary.livecodescript b/Toolset/libraries/revanimationlibrary.livecodescript index 6a9fdaa10c..af26126bb7 100644 --- a/Toolset/libraries/revanimationlibrary.livecodescript +++ b/Toolset/libraries/revanimationlibrary.livecodescript @@ -1,16 +1,16 @@ script "revanimationlibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize --------Animation Library-------- local lOverRide diff --git a/Toolset/libraries/revbackscriptlibrary.livecodescript b/Toolset/libraries/revbackscriptlibrary.livecodescript index d51073bd8b..2b13c29355 100644 --- a/Toolset/libraries/revbackscriptlibrary.livecodescript +++ b/Toolset/libraries/revbackscriptlibrary.livecodescript @@ -1,21 +1,20 @@ script "revbackscriptlibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back revIDESubscribe "ideMouseMove" end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back revIDEUnsubscribeAll end if -end revUnloadLibrary +end extensionFinalize global gREVSuppressMessages -global gREVStackStatus local lUpdateDimensionsTimerID, lUpdateAOControlsTimerID, lLastTopStack @@ -442,7 +441,8 @@ end revMovePalettesForSheet function revSaveCheck pStack, pNoWarning if the secureMode then return true put the short name of stack pStack into pStack - if gREVStackStatus[pStack] is "edited" and the short name of stack (the mainstack of stack pStack) is not the short name of revScriptEditorMain() then + if revIDEStackIsEdited(pStack) and the short name of stack \ + (the mainstack of stack pStack) is not the short name of revScriptEditorMain() then toplevel stack pStack local tStackPath @@ -497,7 +497,7 @@ function revSaveCheck pStack, pNoWarning end if break case "Don't Save" - put empty into gREVStackStatus[pStack] + revIDESetUnedited pStack break case "Cancel" return false @@ -687,10 +687,6 @@ on newScrollbar end newScrollbar on newImage - if the width of the target < 9 and the height of the target < 9 then - set the width of the target to the cREVImageWidth of stack "revPreferences" - set the height of the target to the cREVImageHeight of stack "revPreferences" - end if set the cREVGeneral["revUniqueID"] of the target to the milliseconds // PM-2015-09-17: [[ Bug 13826 ]] Allow a new image to appear offscreen revUpdateAOControls @@ -714,15 +710,6 @@ end newEPS on newGraphic - if the width of the target < 9 and the height of the target < 9 then - local tOrigLoc - put the loc of the target into tOrigLoc - if the style of the target is in "polygon,curve" then set the points of the target to 0,0,100,100,100,50,50,100 - if the style of the target is "line" then set the points of the target to 0,0,120,120 - set the width of the target to the cREVGraphicWidth of stack "revPreferences" - set the height of the target to the cREVGraphicHeight of stack "revPreferences" - set the loc of the target to tOrigLoc - end if set the cREVGeneral["revUniqueID"] of the target to the milliseconds // PM-2015-09-17: [[ Bug 13826 ]] Allow a new graphic to appear offscreen revUpdateAOControls @@ -740,13 +727,6 @@ on newPlayer if not gREVSuppressMessages or (gREVSuppressMessages and revOKTarget()) then pass newPlayer end newPlayer -on newGroup - selectedObjectChanged - set the cREVGeneral["revUniqueID"] of the target to the milliseconds - revUpdateAOControls - if not gREVSuppressMessages or (gREVSuppressMessages and revOKTarget()) then pass newGroup -end newGroup - on newCard if there is a stack "revApplicationOverview" then if the mode of stack "revApplicationOverview" is not 0 @@ -1407,6 +1387,8 @@ command revEditScriptInNewWindow pObject, pSpecial set the behavior of stack tNewEditorName to the long id of stack revIDEScriptEditorBehavior("stack") end if + set the cIDETransient of it to true + put the long id of it into tEditor send "setBehaviors" to tEditor @@ -1460,14 +1442,22 @@ end revListScriptEditors # Returns # The long id of the topmost script editor, or empty if there is no script editor open. -function revTopMostScriptEditor +function revTopMostScriptEditor pMode local tEditors put revListScriptEditors() into tEditors - if the number of lines of tEditors = 0 then - return empty - else + + if pMode is empty then return line 1 of tEditors end if + + repeat for each line tEditor in tEditors + dispatch "revSEGetMode" to tEditor + if the result is pMode then + return tEditor + end if + end repeat + + return empty end revTopMostScriptEditor function revScriptEditorTemplate @@ -1485,13 +1475,6 @@ function revScriptEditorMain end revScriptEditorMain command revGoScriptEditor pEditor, pPosition - # When the user clicks on any stack, revFrontScript intercepts the resulting mouseDown - # and among other things, attempts to detect whether or not the stack has been edited - # as a result of the click. Unfortunately any stack clicked on in run mode is flagged as edited, - # this causes a problem with script editors asking the user to "save" etc when they are closed. - # For now we work around this here by manually ensuring the editor is not flagged as edited. - put empty into gREVStackStatus[the short name of pEditor] - lock screen lock messages toplevel pEditor @@ -1538,6 +1521,10 @@ function revMenuManagerGroup pGroups end revMenuManagerGroup on errorDialog pWhatError, pWhatError2 + if revTestEnvironment() then + pass errorDialog + end if + ###################### close printing global gREVSuppressErrors, gREVDevelopment @@ -1923,100 +1910,6 @@ end revReturnSelectionDescription # Script Editor functions ------------------------------------------ -# Parameters -# pObject : either a long id or a valid reference to an object. -# Returns -# The "rugged" id of the object. This can be used the same as a long id, -# but is slightly more resistant to stuff like objects being grouped, renamed etc. -# The script editor uses rugged ids to store object ids when there is a chance that the object -# could be renamed or grouped etc. -function revRuggedId pObject - # First get the long id of our object. If pObject is a valid object reference we just get the - # object's long id. If its not a valid reference, this does not always mean the object doesn't - # exist (because of edit group mode), in this case we assume that pObject is the long id of the object - # we want, and parse it directly to obtain the rugged id, without needing to refer to the actual - # object at all. - local tObject - if there is a pObject then - put the long id of pObject into tObject - else - put pObject into tObject - # MDW-2015-08-21: [[ bugfix_revRuggedId ]] pObject is empty when creating a new object - if tObject is empty then - put the long id of the target into tObject - end if - end if - - # Find out what the name of the stack owning the object is. We are only interested in the - # stack that immediately owns the object, which could be a substack. To find this we can - # simply search from the front and find the first ocurrence of "of stack". - local tSubStack, tMainstack - local tStackFound - local tWordNumber - put 1 into tWordNumber - repeat for each word tWord in tObject - # The first match is always the substack, the second (and last) match is always the mainstack - if tWord is "stack" then - if tStackFound then - put tMainStack into tSubStack - put word (tWordNumber + 1) of tObject into tMainStack - exit repeat - else - put word (tWordNumber + 1) of tObject into tMainStack - end if - put true into tStackFound - end if - add 1 to tWordNumber - end repeat - - try - local tStack - if tSubStack is not empty then - put "stack " & tSubStack & " of " & (the name of stack (char 2 to -2 of tMainStack)) into tStack - else - put (the name of stack (char 2 to -2 of tMainStack)) into tStack - end if - catch tError - - end try - - # MW-2008-09-08: [[ Bug 7142 ]] If the hcAddressing of the stack is true, then the long id - # is in a different form than this expects. Thus we temporarily fetch it while hcAddressing - # is false. - if the hcAddressing of tStack then - set the hcAddressing of tStack to false - put the long id of pObject into tObject - set the hcAddressing of tStack to true - end if - - local tType - put word 1 of tObject into tType - - local tId - if tType is "stack" then - # With stacks, the name is the most robust way to refer to them. We assume that the stack exists... - put tStack into tId - else if tType is "audioclip" then - put "audioclip id" && word 3 of tObject & " of " & tStack into tId - else if tType is "videoclip" then - put "videoclip id" && word 3 of tObject & " of " & tStack into tId - else - # With any other object, the safest thing is to return the object id and the name of its owning stack. - # For cards we use "card id..." for other objects "control id..". This is significant because when in - # edit group mode, the group being edited can be referred to as "control id.." but *not* "group id..." - - local tPrefix - if tType is "card" then - put "card" into tPrefix - else - put "control" into tPrefix - end if - put tPrefix & " id " & word 3 of tObject & " of " & tStack into tId - end if - - return tId -end revRuggedId - function revScriptEditor pObject if exists(pObject) then return _revScriptEditorNew(the long id of pObject) @@ -2105,7 +1998,7 @@ end revBrowserTopStack ------------------------------------ local sPalettesMsgID -constant kDontHide = "revMenuBar,revErrorDisplay,revVariableWatcher,revMessageWatcher,revDocsLanguageQuickref" +constant kDontHide = "revMenuBar,revErrorDisplay,revVariableWatcher,revMessageWatcher,revDocsLanguageQuickref,com.livecode.palette.autocomplete.completions" # OK-2008-05-12 : Added to fix problem with script editor dialogs not being recognized as part of the script editor # and palettes consequently being reshown when they are invoked. @@ -2354,17 +2247,9 @@ function revExternalVersion pExternal local tExternalList put empty into tExternalList - if (the platform is "MacOS") and (char 1 of the systemVersion is not "1") then - --MacOS 9+ - local tOS9HomePath - put the fileName of stack "home" into tOS9HomePath - - local tCheckExternals - put getResources(tOS9HomePath,"CODE") into tCheckExternals - else - -- Win,OSX and Unix - put the externals of stack "home" into tCheckExternals - end if + -- Win,OSX and Unix + local tCheckExternals + put the externals of stack "home" into tCheckExternals local tExternals repeat for each line i in tCheckExternals @@ -2592,26 +2477,17 @@ function revDBDriverPath pDriver, pPlatform, pArchitecture -- returns path to database driver from runtime or user runtime folder -- will be a folder on Mac OS X, a list of files on Windows - local tEnvironmentFolder, tUserFolder - switch pPlatform - case "MacOSX" - if pArchitecture is empty then - put "Universal" into pArchitecture - end if - put revEnvironmentRuntimePath() & "/Mac OS X/" & pArchitecture & "/Externals" into tEnvironmentFolder - put revEnvironmentUserRuntimePath() & "/Mac OS X/" & pArchitecture & "/Externals" into tUserFolder - break - - case "Windows" - put revEnvironmentRuntimePath() & "/Windows/x86-32/Externals" into tEnvironmentFolder - put revEnvironmentUserRuntimePath() & "/Windows/x86-32/Externals" into tUserFolder - break - - case "Linux" - put revEnvironmentRuntimePath() & "/Linux/" & pArchitecture & "/Externals" into tEnvironmentFolder - put revEnvironmentUserRuntimePath() & "/Linux/" & pArchitecture & "/Externals" into tUserFolder - break - end switch + local tPlatform, tEnvironmentFolder, tUserFolder + put pPlatform into tPlatform + if tPlatform is "MacOSX" then + put "Mac OS X" into tPlatform + if pArchitecture is empty then + put "Universal" into pArchitecture + end if + end if + + put revEnvironmentRuntimePath() & "/" & tPlatform & "/" & pArchitecture & "/Externals" into tEnvironmentFolder + put revEnvironmentUserRuntimePath() & "/" & tPlatform & "/" & pArchitecture & "/Externals" into tUserFolder local tEnvironmentFile, tUserFile, tLegacyFile put tEnvironmentFolder & slash & kDriverIndexSubFolder & slash & kDriverIndexName into tEnvironmentFile @@ -2702,9 +2578,9 @@ function revExternalPath pDriver, pPlatform, pArchitecture put revEnvironmentUserRuntimePath() & "/Mac OS X/" & pArchitecture & "/Externals/Legacy/Externals.txt" into tLegacyFile break case "Windows" - put revEnvironmentRuntimePath() & "/Windows/x86-32/Externals/Externals.txt" into tEnvironmentFile - put revEnvironmentUserRuntimePath() & "/Windows/x86-32/Externals/Externals.txt" into tUserFile - put revEnvironmentUserRuntimePath() & "/Windows/x86-32/Externals/Legacy/Externals.txt" into tLegacyFile + put revEnvironmentRuntimePath() & "/Windows/" & pArchitecture & "/Externals/Externals.txt" into tEnvironmentFile + put revEnvironmentUserRuntimePath() & "/Windows/" & pArchitecture & "/Externals/Externals.txt" into tUserFile + put revEnvironmentUserRuntimePath() & "/Windows/" & pArchitecture & "/Externals/Legacy/Externals.txt" into tLegacyFile break # OK-2007-08-14 : Linux support reinstated case "Linux" @@ -3076,57 +2952,6 @@ on revShutDown end revShutDown -function revCombineFilePaths pPaths, pPaths2 - -- combines file paths based on last item, where duplicates keeps list 1 - set the itemDel to slash - - local tPaths - repeat for each line l in pPaths2 - if the number of words in l is 0 then next repeat - put l into tPaths[item -1 of l] - end repeat - repeat for each line l in pPaths - if the number of words in l is 0 then next repeat - put l into tPaths[item -1 of l] - end repeat - - local tReturn - repeat for each element e in tPaths - put e & cr after tReturn - end repeat - delete last char of tReturn - return tReturn -end revCombineFilePaths - -function revAbsoluteFolderListing pDirectory - local tReturn - if there is no directory pDirectory then return empty - put the directory into tReturn - set the directory to pDirectory - - local tFiles - put the files into tFiles - - local tOutput - repeat for each line l in tFiles - put the directory & slash & l & cr after tOutput - end repeat - delete last char of tOutput - set the directory to tReturn - return tOutput -end revAbsoluteFolderListing - -local lExecutingDesktopChanged - -on deskTopChanged - if lExecutingDesktopChanged then exit deskTopChanged - put true into lExecutingDesktopChanged - repeat for each line l in the openStacks - send "deskTopChanged" to cd 1 of stack l - end repeat - put false into lExecutingDesktopChanged -end deskTopChanged - function revCalculateRelativePath pRoot, pFile local tResult, tCount set the itemDel to "/" @@ -3279,7 +3104,8 @@ command revIDEHandleMouseDown pWhich, pTarget end if send "selectedObjectChanged" to me end if - if the mode of stack "revSaving" is 0 then put "edited" into gREVStackStatus[revTargetStack(tTarget)] + revIDESetEdited the short name of revIDEStackOfObject(tTarget) + return "exit to top" end if end revIDEHandleMouseDown @@ -3452,6 +3278,8 @@ resize cursor when the mouse is over a selection handle. constant kHandleSize = 5 on ideMouseMove pX, pY, pTarget + if the tool is not "pointer tool" then exit ideMouseMove + if pTarget is among the lines of the selectedObjects then local tRect put the rect of pTarget into tRect @@ -3507,3 +3335,10 @@ on ideMouseMove pX, pY, pTarget unlock cursor end if end ideMouseMove + +on msgChanged pHandler, pLine + global gRevDevelopment + if gRevDevelopment then + pass msgChanged + end if +end msgChanged diff --git a/Toolset/libraries/revcommonlibrary.livecodescript b/Toolset/libraries/revcommonlibrary.livecodescript index 4db9e64414..65655e1a4b 100644 --- a/Toolset/libraries/revcommonlibrary.livecodescript +++ b/Toolset/libraries/revcommonlibrary.livecodescript @@ -1,16 +1,16 @@ script "revcommonlibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize function revTargetStack pWhich local tParse @@ -54,7 +54,11 @@ end revGoPDF # TH-2008-06-27 :: Bug 6521/6432, have seperated revMail into two alternative handlers. revMailUnicode # should be ussed by people sending unicode characters, the original revMail can be used otherwise command revMail pTo, pCC, pSubject, pBody - revMailUnicode pTo, pCC, uniEncode(pSubject), uniEncode(pBody) + if the environment is "mobile" then + mobileComposeMail pSubject, pTo, pCC, , pBody + else + revMailUnicode pTo, pCC, uniEncode(pSubject), uniEncode(pBody) + end if end revMail command revMailUnicode pTo, pCC, pSubject, pBody @@ -128,41 +132,25 @@ end revRunningWindowsNT on revSetWindowsShellCommand if the platform is not "Win32" then exit revSetWindowsShellCommand set the hideConsoleWindows to true - if $COMSPEC is not empty then set the shellCommand to $COMSPEC - else - --just in case some windows versions don't use $COMSPEC - if revRunningWindowsNT() then set the shellCommand to "cmd.exe" - else set the shellCommand to "command.com" - end if + set the shellCommand to $COMSPEC end revSetWindowsShellCommand -getProp cREVGeneral[pWhichProp] pWhichProfile - lock messages - local tRevUniqueID - put the cREVGeneral["revUniqueID"] of the target into tRevUniqueID - unlock messages - - # OK-2008-04-14 : The long id will return an invalid reference when in edit group mode, - # instead the "rugged id" should be used. - --put the long id of the target into tTarget - - # OK-2008-06-02 : Because this script is used in standalones, using revRuggedId will break this - # because its located in revBackscript (which is not included in standalones). As we don't require a - # rugged id in standalones anyway, just revert to the old behavior in standalone environment. - local tTarget - if the environment is "development" then - put revRuggedId(the long id of the target) into tTarget - else - put the long id of the target into tTarget - end if - - local tMilliseconds - if pWhichProp is "revUniqueID" and tRevUniqueID is empty then - put the milliseconds into tMilliSeconds - set the cREVGeneral["revUniqueID"] of tTarget to tMilliSeconds - return tMilliSeconds - else if pWhichProp is "revUniqueID" then +getProp revProfile + return the cREVGeneral["profile"] of the target +end revProfile + +getProp cREVGeneral[pWhichProp] + if pWhichProp is "revUniqueID" then + lock messages + local tRevUniqueID + put the cREVGeneral["revUniqueID"] of the target into tRevUniqueID + unlock messages + + if tRevUniqueID is empty then + put the milliseconds into tRevUniqueID + set the cREVGeneral["revUniqueID"] of the target to tRevUniqueID + end if return tRevUniqueID end if @@ -172,30 +160,25 @@ getProp cREVGeneral[pWhichProp] pWhichProfile lock messages local tProfile - put the cREVGeneral["profile"] of tTarget into tProfile - if tProfile is empty or tProfile is the cREVGeneral["masterName"] of tTarget then put "Master" into tProfile + put the cREVGeneral["profile"] of the target into tProfile + if tProfile is empty or tProfile is the cREVGeneral["masterName"] of the target then put "Master" into tProfile unlock messages return tProfile end cREVGeneral - + setProp revProfile pWhich set the cREVGeneral["profile"] of the target to pWhich end revProfile -getProp revProfile - return the cREVGeneral["profile"] of the target -end revProfile - - - setProp cREVGeneral[pWhichProp] pWhichProfile local tTarget put the long id of the target into tTarget - local tTargetLongID - put tTarget into tTargetLongID - if pWhichProp is not "profile" and pWhichProp is not "inLineImages" and pWhichProp is not "virtualWidth" and pWhichProp is not "virtualHeight" and pWhichProp is not "breakPoints" then pass cREVGeneral + if pWhichProp is not "profile" and pWhichProp is not "inLineImages" and \ + pWhichProp is not "virtualWidth" and pWhichProp is not "virtualHeight" \ + then pass cREVGeneral + if pWhichProp is "virtualWidth" then lock messages local tOriginalWidth @@ -212,6 +195,7 @@ setProp cREVGeneral[pWhichProp] pWhichProfile unlock messages exit cREVGeneral end if + if pWhichProp is "virtualHeight" then lock messages local tOriginalHeight @@ -224,52 +208,7 @@ setProp cREVGeneral[pWhichProp] pWhichProfile unlock messages exit cREVGeneral end if - if pWhichProp is "breakPoints" then - - pass cREVGeneral - - local tBreakPointsList - put the breakPoints into tBreakPointsList - - local tMainStack - put the mainStack of stack revTargetStack(tTarget) into tMainStack - - local tObjects - put the cREVGeneral["debugObjects"] of stack tMainStack into tObjects - - local tStack - put word -2 to -1 of tTarget into tStack - put the name of tStack into word -2 to -1 of tTarget - if pWhichProfile is not empty then - if tTarget is not among the lines of tObjects then - --add breakpoint object - put tTarget into line (the number of lines in tObjects)+1 of tObjects - end if - else - if tTarget is among the lines of tOBjects then - --remove breakpoint object - delete line lineOffset(tTarget,tObjects) of tOBjects - end if - end if - set the cREVGeneral["debugObjects"] of stack tMainStack to tObjects - - local tOldPoints - repeat for each line l in tBreakPointsList - if tTargetLongID is not in l then put l & cr after tOldPoints - end repeat - delete last char of tOldPoints - put tOldPoints into tBreakPointsList - - local tAddPoints - repeat for each line l in pWhichProfile - put tTarget,l & cr after tAddPoints - end repeat - delete last char of tAddPoints - put tAddPoints into line (the number of lines in tBreakPointsList+1) of tBreakPointsList - set the breakPoints to tBreakPointsList - pass cREVGeneral - end if - --inline images next + if pWhichProp is "inLineImages" then if pWhichProfile is true then lock messages @@ -390,7 +329,9 @@ setProp cREVGeneral[pWhichProp] pWhichProfile end if set the cREVGEneral["inLineImages"&the number of this cd] of tTarget to pWhichProfile exit cREVGeneral - end if + end if --inLineImages + + -- pWhichProp is "profile" global gREVProfileReadOnly, gREVAutoCreateProfiles lock screen lock messages @@ -965,6 +906,13 @@ on revDeleteFolder pSrcFolder return the result end revDeleteFolder +on revDeleteFile pWhich + close file pWhich + if the platform is "MacOS" then put empty into URL ("resfile:"&pWhich) + put empty into URL ("binfile:"&pWhich) + delete file pWHich +end revDeleteFile + on revMoveFolder pSrcFolder, pDestFolder if the platform is "Win32" then revSetWindowsShellCommand @@ -1348,6 +1296,14 @@ function revFontGetSystemFont return "Helvetica" break + case "iphone" + return "San Francisco" + break + + case "android" + return "Roboto" + break + end switch end revFontGetSystemFont @@ -1371,6 +1327,14 @@ function revFontGetSystemFontSize return 12 break + case "iphone" + return 17 + break + + case "android" + return 14 + break + end switch end revFontGetSystemFontSize @@ -1414,6 +1378,15 @@ private function _revEnvironmentPlatform case "Win32" put "Windows" into tPlatform break + case "iphone" + put "iphone" into tPlatform + break + case "android" + put "android" into tPlatform + break + case "HTML5" + put "html5" into tPlatform + break default put "Unsupported" into tPlatform break @@ -1472,3 +1445,134 @@ function macVersionLessThan pLeft, pRight end repeat return false end macVersionLessThan + +# Parameters +# pObject : either a long id or a valid reference to an object. +# Returns +# The "rugged" id of the object. This can be used the same as a long id, +# but is slightly more resistant to stuff like objects being grouped, renamed etc. +# The script editor uses rugged ids to store object ids when there is a chance that the object +# could be renamed or grouped etc. +function revRuggedId pObject + # First get the long id of our object. If pObject is a valid object reference we just get the + # object's long id. If its not a valid reference, this does not always mean the object doesn't + # exist (because of edit group mode), in this case we assume that pObject is the long id of the object + # we want, and parse it directly to obtain the rugged id, without needing to refer to the actual + # object at all. + local tObject + if there is a pObject then + put the long id of pObject into tObject + else + put pObject into tObject + # MDW-2015-08-21: [[ bugfix_revRuggedId ]] pObject is empty when creating a new object + if tObject is empty then + put the long id of the target into tObject + end if + end if + + # Find out what the name of the stack owning the object is. We are only interested in the + # stack that immediately owns the object, which could be a substack. To find this we can + # simply search from the front and find the first ocurrence of "of stack". + local tSubStack, tMainstack + local tStackFound + local tWordNumber + put 1 into tWordNumber + repeat for each word tWord in tObject + # The first match is always the substack, the second (and last) match is always the mainstack + if tWord is "stack" then + if tStackFound then + put tMainStack into tSubStack + put word (tWordNumber + 1) of tObject into tMainStack + exit repeat + else + put word (tWordNumber + 1) of tObject into tMainStack + end if + put true into tStackFound + end if + add 1 to tWordNumber + end repeat + + try + local tStack + if tSubStack is not empty then + put "stack " & tSubStack & " of " & (the name of stack (char 2 to -2 of tMainStack)) into tStack + else + put (the name of stack (char 2 to -2 of tMainStack)) into tStack + end if + catch tError + + end try + + # MW-2008-09-08: [[ Bug 7142 ]] If the hcAddressing of the stack is true, then the long id + # is in a different form than this expects. Thus we temporarily fetch it while hcAddressing + # is false. + if there is a tStack and the hcAddressing of tStack then + set the hcAddressing of tStack to false + put the long id of pObject into tObject + set the hcAddressing of tStack to true + end if + + local tType + put word 1 of tObject into tType + + local tId + if tType is "stack" then + # With stacks, the name is the most robust way to refer to them. We assume that the stack exists... + put tStack into tId + else if tType is "audioclip" then + put "audioclip id" && word 3 of tObject & " of " & tStack into tId + else if tType is "videoclip" then + put "videoclip id" && word 3 of tObject & " of " & tStack into tId + else + # With any other object, the safest thing is to return the object id and the name of its owning stack. + # For cards we use "card id..." for other objects "control id..". This is significant because when in + # edit group mode, the group being edited can be referred to as "control id.." but *not* "group id..." + + local tPrefix + if tType is "card" then + put "card" into tPrefix + else + put "control" into tPrefix + end if + put tPrefix & " id " & word 3 of tObject & " of " & tStack into tId + end if + + return tId +end revRuggedId + +function revAbsoluteFolderListing pDirectory + if there is no directory pDirectory then return empty + + local tFiles + put files(pDirectory) into tFiles + + local tOutput + repeat for each line tFile in tFiles + put pDirectory & slash & tFile & return after tOutput + end repeat + delete last char of tOutput + + return tOutput +end revAbsoluteFolderListing + +function revCombineFilePaths pPaths, pPaths2 + -- combines file paths based on last item, where duplicates keeps list 1 + set the itemDel to slash + + local tPaths + repeat for each line l in pPaths2 + if the number of words in l is 0 then next repeat + put l into tPaths[item -1 of l] + end repeat + repeat for each line l in pPaths + if the number of words in l is 0 then next repeat + put l into tPaths[item -1 of l] + end repeat + + local tReturn + repeat for each element e in tPaths + put e & cr after tReturn + end repeat + delete last char of tReturn + return tReturn +end revCombineFilePaths \ No newline at end of file diff --git a/Toolset/libraries/revdatabaselibrary.livecodescript b/Toolset/libraries/revdatabaselibrary.livecodescript index 9b2b290cea..88a41f0f91 100644 --- a/Toolset/libraries/revdatabaselibrary.livecodescript +++ b/Toolset/libraries/revdatabaselibrary.livecodescript @@ -1,23 +1,27 @@ -script "revdatabaselibrary" +script "revdatabaselibrary" -on revLoadLibrary +on extensionInitialize if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front - -- MW-2009-07-09: We only do this if we are in a standalone environment - -- ( note that 'runtime' check can be removed if you reading this :o) ) - if the environment is not "browser" and the environment is not "player" and the environment is not "runtime" then - revDBInit - end if -end revLoadLibrary - -on revUnloadLibrary + + -- If we are running in development mode, we must set the driver path + if the environment is "development" then + if revEnvironmentIsInstalled() then + revSetDatabaseDriverPath revEnvironmentExternalsPath() & slash & "Database Drivers" + else + revSetDatabaseDriverPath revEnvironmentBinariesPath() + end if + end if +end extensionInitialize + +on extensionFinalize if the target is not me then - pass "revUnloadLibrary" + pass "extensionFinalize" end if remove the script of me from front -end revUnloadLibrary +end extensionFinalize #################################################################################################### # Original comment by J.S @@ -309,10 +313,6 @@ on revConnectQuery pObject if the platform is "Win32" then replace "/" with "\" in tInfo["dbdatabase"] end if - if the platform is "MacOS" and char 1 of the systemVersion is not "1" then - put revMacFromUnixPath(tInfo["dbdatabase"]) into tInfo["dbdatabase"] - end if - local tResult put revdb_connect(tInfo["dbtype"],tInfo["dbhost"],tInfo["dbdatabase"],tInfo["dbuser"],tInfo["dbpassword"],3*1024,tInfo["dbuser"],tInfo["dbpassword"]) into tResult else @@ -2387,27 +2387,3 @@ private command log pMessage --put pMessage & return after msg end log -# OK-2007-09-24 : Legacy driver support. Rewrote this handler as it seemed to have deprecated code, the old handler is -# commented out above. -command revDBInit - try - if the environment is "development" then - local tDataPath - if the cREVUseLegacyDrivers of stack "revPreferences" then - put revEnvironmentUserExternalsPath() & "/Legacy/Database Drivers" into tDataPath - else - put revEnvironmentExternalsPath() & "/Database Drivers" into tDataPath - end if - - local tRootPath - put revEnvironmentUserExternalsPath() Into tRootPath - if there is a folder tRootPath then - put return & tRootPath & "/Database Drivers" after tDataPath - end if - else - put specialfolderpath("engine") & slash & "Externals/database_drivers" into tDataPath - end if - - revSetDatabaseDriverPath tDataPath - end try -end revDBInit diff --git a/Toolset/libraries/revdebuggerlibrary.livecodescript b/Toolset/libraries/revdebuggerlibrary.livecodescript index e9ee596bd9..e8f05ed008 100644 --- a/Toolset/libraries/revdebuggerlibrary.livecodescript +++ b/Toolset/libraries/revdebuggerlibrary.livecodescript @@ -1,24 +1,26 @@ script "revdebuggerlibrary" -on revLoadLibrary +on extensionInitialize if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front - ideSubscribe "idePreferenceChanged:cREVScriptDebugMode" -end revLoadLibrary + if "development" is in the environment then + ideSubscribe "idePreferenceChanged:cREVScriptDebugMode" + end if + + __Initialize +end extensionInitialize -on revUnloadLibrary - if the target is not me then - pass "revUnloadLibrary" - end if +on extensionFinalize + if the target is not me then + pass "extensionFinalize" + end if remove the script of me from front -end revUnloadLibrary +end extensionFinalize -# This constant specifies that the debugger should use the cREVGeneral -# custom property set to store its metadata. -constant kMetadataType = "general" +local sLastBreakInfo ################################################################################ # @@ -26,27 +28,33 @@ constant kMetadataType = "general" # ################################################################################ +constant kUndebuggableHandlers = "moveStack resizeStack resizeControl" + # Description # Initializes the debugger, should be called on IDE startup or when script debug mode is turned on. -command revDebuggerInitialize +private command __Initialize # When the debugger is first initialized, the breakpoints property should be empty as other # IDE stacks should not be setting it. Unfortunately if there are no breakpoints set, traceError messages # are not sent by the engine, so we have to set a dummy breakpoint here to prevent this problem. - if debuggerEnabled() then + if __Enabled() then set the breakpoints to the long id of me,5000 else set the breakpoints to empty end if -end revDebuggerInitialize +end __Initialize + +# This constant specifies that the debugger should use the cREVGeneral +# custom property set to store its metadata. +constant kMetadataType = "general" on idePreferenceChanged pPreference, pValue if the target is me then switch pPreference case "cREVScriptDebugMode" - if debuggerEnabled() then - __DebuggerEnable + if __Enabled() then + __Enable else - __DebuggerDisable + __Disable end if break end switch @@ -59,47 +67,59 @@ end idePreferenceChanged # Whether or not the debugger is enabled. This is currently defined as whether or not the cREVScriptDebugMode # of stack "revPreferences" is true. function revDebuggerEnabled - return debuggerEnabled() + return __Enabled() end revDebuggerEnabled # Description # Enables the debugger, should be called when the user switches script debug mode on. command revDebuggerEnable - revIDESetPreference "cREVScriptDebugMode", true + if the environment contains "development" then + revIDESetPreference "cREVScriptDebugMode", true + end if + + __Enable end revDebuggerEnable -private command __DebuggerEnable +private command __Enable + # OK-2008-08-07 : 6875 - The debugger must be re-initialized when script debug node is switched on. + __Initialize + # When the debugger is enabled we need to go through all the open stacks and # activate their breakpoints if appropriate. - local tOpenStacks - put the openStacks into tOpenStacks - repeat for each line tStack in tOpenStacks - if not debuggerStackAllowed(the long id of stack tStack) then - next repeat - end if - revDebuggerActivateBreakpoints the long id of stack tStack - revDebuggerActivateWatches the long id of stack tStack + local tMainstacks, tMainstack + put the mainstacks into tMainstacks + repeat for each line tMainstack in tMainstacks + repeat for each line tStack in tMainstack & return & the substacks of stack tMainstack + if tStack is empty then next repeat + + if not __StackAllowed(the long id of stack tStack) then + next repeat + end if + __ActivateBreakpoints the long id of stack tStack + __ActivateWatches the long id of stack tStack + end repeat end repeat - revDebuggerActivateWatches empty - - # OK-2008-08-07 : 6875 - The debugger must be re-initialized when script debug node is switched on. - revDebuggerInitialize -end __DebuggerEnable + __ActivateWatches empty +end __Enable local sContext # Description # Disables the debugger, should be called when the user switches script debug mode off. command revDebuggerDisable - revIDESetPreference "cREVScriptDebugMode", false + if the environment contains "development" then + revIDESetPreference "cREVScriptDebugMode", false + else + __Disable + end if end revDebuggerDisable -private command __DebuggerDisable +private command __Disable set the breakpoints to empty set the watchedVariables to empty put empty into sContext -end __DebuggerDisable +end __Disable # Returns # The current debug context if there is one, empty otherwise. The context returned by this function @@ -122,8 +142,8 @@ function revDebuggerGetContext return tContext end revDebuggerGetContext - - + + # Parameters # pContext : a debug context in the format returned by revDebuggerContexts. Note this includes a number as the first item. # Description @@ -154,7 +174,7 @@ function revDebuggerContexts # OK-2009-06-23 : Bug 7954 - Parse the execution contexts properly to avoid problems with commas local tArray - put parseExecutionContext(tContext) into tArray + put __ParseExecutionContext(tContext) into tArray if tArray["behavior"] is not empty then put tArray["behavior"] into tControl @@ -170,10 +190,13 @@ function revDebuggerContexts put revTargetStack(the long id of tControl) into tStack + local tParsedContext + put tArray["object"], tArray["handler"], tArray["line number"], tArray["behavior"] into tParsedContext + # If gREVDevelopment is false then only non IDE stacks can appear in the contexts if not gREVDEvelopment then - if debuggerStackAllowed(the long id of stack tStack) then - put return & tLineNumber & comma & tContext before tContexts + if __StackAllowed(the long id of stack tStack) then + put return & tLineNumber & comma & tParsedContext before tContexts else next repeat end if @@ -182,7 +205,7 @@ function revDebuggerContexts # debugger itself and anything that was called by the debugger, i.e. appears after a debugger # call in the call stack. - if tStack is "revDebuggerLibrary" then + if tStack is "revDebuggerLibrary" or tStack is "com.livecode.library.remotedebugger" then # No debugger stack contexts are placed onto the call stack, however we also need to remove # *any* contexts that appear after a trace, traceError or traceBreak (or traceDone although less important). --if item -2 of tContext is among the words of "trace traceError traceBreak traceDone" then @@ -192,20 +215,16 @@ function revDebuggerContexts next repeat end if else - put return & tLineNumber & comma & tContext before tContexts + put return & tLineNumber & comma & tParsedContext before tContexts end if end if end repeat delete the first char of tContexts return tContexts end revDebuggerContexts - -function revDebuggerParseExecutionContext pContext - return parseExecutionContext(pContext) -end revDebuggerParseExecutionContext # OK-2009-06-23 : Bug 7954 - Parses an execution context taking into account that object long ids may contain commas. -private function parseExecutionContext pContext +private function __ParseExecutionContext pContext # If pContext was from the revDebuggerContexts it will have an extra "context number" at the start, # chop this off first. local tArray @@ -222,17 +241,19 @@ private function parseExecutionContext pContext if tItem is an integer then put tItem into tArray["line number"] put item (tItemNumber - 1) of pContext into tArray["handler"] - put item 1 to (tItemNumber - 2) of pContext into tArray["object"] + put revRuggedID(item 1 to (tItemNumber - 2) of pContext) into tArray["object"] put item (tItemNumber + 1 ) to -1 of pContext into tArray["behavior"] + if tArray["behavior"] is not empty then + put revRuggedID(tArray["behavior"]) into tArray["behavior"] + end if return tArray end if end repeat -end parseExecutionContext +end __ParseExecutionContext function revDebuggerParseExecutionContext pContext - return parseExecutionContext(pContext) + return __ParseExecutionContext(pContext) end revDebuggerParseExecutionContext - # Returns # A list of global variable names @@ -242,10 +263,7 @@ end revDebuggerParseExecutionContext function revDebuggerGlobalNames local tGlobalsRaw, tGlobals - # OK-2009-01-29 : Bug 7178 - The 64 bit Vista environment variables ending with (x86) cause problems - # because LiveCode throws an error when parsing do "global $VARIABLE(x86)" or similar. For now, we just - # remove these until we can test on a 64 bit Vista machine to get them working. - put revDebuggerValidGlobalNames() into tGlobalsRaw + put the globals into tGlobalsRaw replace comma with return in tGlobalsRaw global gREVShowStacks @@ -259,15 +277,6 @@ function revDebuggerGlobalNames return tGlobals end revDebuggerGlobalNames -# Returns -# A list of the globals with valid names. -# -# FIXME this function is no longer required; all globals now contain -# valid names. -function revDebuggerValidGlobalNames - return the globals -end revDebuggerValidGlobalNames - # Parameters # pContext : a debug context in the format returned by revDebuggerContexts (,,, # Returns @@ -473,8 +482,6 @@ local sDebugElements, sDebugValue # Description # Sets the specified value in the specified debug context command revDebuggerSetValue pVariableName, pElementList, @pNewValue, pContext - - -- if pVariableName is among the items of the globalNames then -- put "global " & the globalNames & return into tStatement -- end if @@ -482,17 +489,17 @@ command revDebuggerSetValue pVariableName, pElementList, @pNewValue, pContext put pElementList into sDebugElements put pNewValue into sDebugValue --- local tStatement --- put "put pNewValue into " & pVariableName after tStatement --- repeat with x = 1 to item 2 of line 1 of extents(pElementList) --- put "[pElementList[" & x & "]]" after tStatement + -- local tStatement + -- put "put pNewValue into " & pVariableName after tStatement + -- repeat with x = 1 to item 2 of line 1 of extents(pElementList) + -- put "[pElementList[" & x & "]]" after tStatement -- end repeat # In order not to interfere with the code being debugged, we change the value by passing a reference # to the variable to be changed back to the debugger. This prevents the creation of any variables in the # current debug context. local tStatement - put "revDebuggerSetValueDo " & pVariableName into tStatement + put "__SetValueDo " & pVariableName into tStatement local tContextNumber if pContext is empty then @@ -516,7 +523,7 @@ command revDebuggerSetValue pVariableName, pElementList, @pNewValue, pContext return tResult end revDebuggerSetValue -command revDebuggerSetValueDo @pVariable +command __SetValueDo @pVariable local tStatement put "put sDebugValue into pVariable" into tStatement repeat with x = 1 to item 2 of line 1 of extents(sDebugElements) @@ -524,11 +531,12 @@ command revDebuggerSetValueDo @pVariable end repeat do tStatement -end revDebuggerSetValueDo +end __SetValueDo # Description # Runs the currently debugging script until the next breakpoint command revDebuggerRun + delete variable sLastBreakInfo set the traceStack to empty set the traceUntil to 65535 set the traceReturn to true @@ -538,6 +546,7 @@ end revDebuggerRun # Description # Performs the debugger "stop" function, terminates the script currently being debugged command revDebuggerStop + delete variable sLastBreakInfo # When executing certain structures, the debugger will continue to loop until the # breakpoints property becomes empty. In order to make sure the debugger always # exits when asked to, we set the breakpoints to empty here and restore them again @@ -633,7 +642,7 @@ constant kObjectBreakpointLimit = 100 # Empty under normal circumstances. If there are already the maximum number # of breakpoints set then returns an error string. command revDebuggerAddBreakpoint pObject, pLine - debuggerAddBreakpoint pObject, pLine, empty + __AddBreakpoint pObject, pLine, empty end revDebuggerAddBreakpoint # Parameters @@ -654,7 +663,7 @@ end revDebuggerAddBreakpoint # Empty under normal circumstances. If there are already the maximum number # of breakpoints set then returns an error string. command revDebuggerAddConditionalBreakpoint pObject, pLine, pCondition - debuggerAddBreakpoint pObject, pLine, pCondition + __AddBreakpoint pObject, pLine, pCondition end revDebuggerAddConditionalBreakpoint # Parameters @@ -672,10 +681,10 @@ command revDebuggerRemoveBreakpoint pObject, pLine revDebuggerDeactivateBreakpoint pObject, pLine local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tBreakpoint - put debuggerGetId(pObject) & comma & pLine into tBreakpoint + put __GetId(pObject) & comma & pLine into tBreakpoint local tObjectBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tObjectBreakpoints @@ -687,7 +696,7 @@ command revDebuggerRemoveBreakpoint pObject, pLine put revMetadataGet(tStack, kMetadataType, "breakpointconditions") into tConditions local tLineNumber - put debuggerBreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber if tLineNumber = 0 then return "Breakpoint not found" @@ -700,7 +709,7 @@ command revDebuggerRemoveBreakpoint pObject, pLine revMetadataSet tStack, kMetadataType, "breakpointstates", tStates revMetadataSet tStack, kMetadataType, "breakpointconditions", tConditions - debuggerCleanBreakpoints tStack + __CleanBreakpoints tStack end revDebuggerRemoveBreakpoint # Parameters @@ -729,23 +738,23 @@ command revDebuggerMoveBreakpoint pOldObject, pOldLine, pNewObject, pNewLine revDebuggerSuspendBreakpoints pOldObject local tStack - put debuggerTargetStack(pOldObject) into tStack + put __TargetStack(pOldObject) into tStack local tBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tBreakpoints local tBreakpoint - put debuggerGetId(pOldObject) & comma & pOldLine into tBreakpoint + put __GetId(pOldObject) & comma & pOldLine into tBreakpoint local tLineNumber - put debuggerBreakpointOffset(tBreakpoint, tBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpoint, tBreakpoints) into tLineNumber if tLineNumber = 0 then exit revDebuggerMoveBreakpoint end if local tChanged put false into tChanged - put debuggerGetId(pNewObject) & comma & pNewLine into line tLineNumber of tBreakpoints + put __GetId(pNewObject) & comma & pNewLine into line tLineNumber of tBreakpoints revMetadataSet tStack, kMetadataType, "breakpoints", tBreakpoints revDebuggerRestoreBreakpoints pOldObject @@ -756,7 +765,7 @@ end revDebuggerMoveBreakpoint command revDebuggerClearAllBreakpoints global gREVDevelopment local tMainstacks - if not gREVDevelopment then + if "development" is in the environment and not gREVDevelopment then put revFilterStacksList(the mainstacks) into tMainstacks else put the mainstacks into tMainstacks @@ -771,9 +780,9 @@ command revDebuggerClearAllBreakpoints end repeat delete the last char of tStacks - repeat for each line tStack in tStacks - debuggerClearStackBreakpoints tStack - end repeat + repeat for each line tStack in tStacks + __ClearStackBreakpoints tStack + end repeat end revDebuggerClearAllBreakpoints # Parameters @@ -781,9 +790,9 @@ end revDebuggerClearAllBreakpoints # Description # Removes all breakpoints from the stack that owns pObject, this means all breakpoints set on the # and any of its cards / objects are removed and deactivated. -private command debuggerClearStackBreakpoints pObject +private command __ClearStackBreakpoints pObject local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tStackBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tStackBreakpoints @@ -793,11 +802,11 @@ private command debuggerClearStackBreakpoints pObject # clearing all breakpoints that that values in the metadata will be valid, hence the try. try local tObjectId - put debuggerResolveId(item 1 of tBreakpoint, tStack) into tObjectId + put __ResolveId(item 1 of tBreakpoint, tStack) into tObjectId revDebuggerRemoveBreakpoint tObjectId, item 2 of tBreakpoint end try end repeat -end debuggerClearStackBreakpoints +end __ClearStackBreakpoints @@ -828,7 +837,7 @@ end revDebuggerSuspendBreakpoints # Restores the correct state of all breakpoints for the specified object. # i.e. activates them if their state is "active" command revDebuggerRestoreBreakpoints pObject - revDebuggerActivateBreakpoints debuggerTargetStack(pObject), pObject + __ActivateBreakpoints __TargetStack(pObject), pObject end revDebuggerRestoreBreakpoints constant kMaxActiveWatches = 100 @@ -841,13 +850,13 @@ constant kMaxActiveWatches = 100 # Activates the specified watch. I.e by putting it into the watchedVariables command revDebuggerActivateWatch pObject, pHandler, pVariable local tStoredWatches - put debuggerGetWatchInformation(pObject, "watches") into tStoredWatches + put __GetWatchInformation(pObject, "watches") into tStoredWatches local tWatch - put debuggerBuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch + put __BuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch local tLineNumber - put debuggerWatchOffset(tWatch, tStoredWatches) into tLineNumber + put __WatchOffset(tWatch, tStoredWatches) into tLineNumber if tLineNumber = 0 then return "watch_not_found" end if @@ -866,7 +875,7 @@ command revDebuggerActivateWatch pObject, pHandler, pVariable if pObject is empty then put empty & comma & empty & comma & pVariable & comma & tCondition into tWatchString else - put debuggerResolveId(item 1 of tWatch, debuggerTargetStack(pObject)) & comma & pHandler & comma & pVariable & comma & tCondition into tWatchString + put __ResolveId(item 1 of tWatch, __TargetStack(pObject)) & comma & pHandler & comma & pVariable & comma & tCondition into tWatchString end if if tCurrentWatches is empty then @@ -878,110 +887,9 @@ command revDebuggerActivateWatch pObject, pHandler, pVariable end if # Store the breakpoint's status in the object so it is remembered between restarts etc - debuggerUpdateWatchStatus pObject, tLineNumber, "active" + __UpdateWatchStatus pObject, tLineNumber, "active" end revDebuggerActivateWatch -command revDebuggerActivateWatches pStack - local tWatches - put debuggerGetWatchInformation(pStack, "watches") into tWatches - - local tWatchStates - put debuggerGetWatchInformation(pStack, "watchstates") into tWatchStates - - local tLineNumber - put 1 into tLineNumber - repeat for each line tWatchState in tWatchStates - local tCurrentWatches - put the watchedVariables into tCurrentWatches - if the number of lines of tCurrentWatches >= kMaxActiveWatches then - return "Active watch limit reached" - end if - - if tWatchState is not "active" then - add 1 to tLineNumber - next repeat - end if - - local tWatch - put line tLineNumber of tWatches into tWatch - - local tWatchString - if item 1 of tWatch is empty then - put tWatch into tWatchString - else - put debuggerResolveId(item 1 of tWatch, pStack) & comma & item 2 to -1 of tWatch into tWatchString - end if - - if tCurrentWatches is empty then - set the watchedVariables to tWatchString - else - if tWatchString is not among the lines of tCurrentWatches then - set the watchedVariables to tCurrentWatches & return & tWatchString - end if - end if - - add 1 to tLineNumber - end repeat -end revDebuggerActivateWatches - -# Parameters -# pStack : reference to the stack to activate breakpoints for -# pObject : reference to an object on the stack -# Description -# Activates breakpoints stored on pStack. If pObject is empty then all breakpoints -# are activated, otherwise only those breakpoints that are in the script of pObject -# are activated. -command revDebuggerActivateBreakpoints pStack, pObject - local tStack - if pObject is not empty then - put debuggerTargetStack(pObject) into tStack - if the long id of tStack is not the long id of pStack then - return "invalid object" - end if - end if - - local tLineNumber - put 1 into tLineNumber - - local tStackBreakpoints - put revMetadataGet(pStack, kMetadataType, "breakpoints") into tStackBreakpoints - - local tStates - put revMetadataGet(pStack, kMetadataType, "breakpointstates") into tStates - - local tBreakpointsToActivate - repeat for each line tBreakpoint in tStackBreakpoints - if pObject is empty or item 1 of tBreakpoint is debuggerGetId(pObject) then - local tState - put line tLineNumber of tStates into tState - - if tState is "active" then - put debuggerResolveId(item 1 of tBreakpoint, pStack) & comma & item 2 of tBreakpoint & return after tBreakpointsToActivate - end if - end if - end repeat - delete the last char of tBreakpointsToActivate - - # If the breakpoints property is allowed to contain duplicates, then the lines with duplicate breakpoints on - # will break more than once, i.e. multiple traceBreak messages. We should ensure that this doesn't happen, - # as there is no good reason for it and it will just cause annoyance. - local tBreakpointsNotActivated - repeat for each line tBreakpoint in tBreakpointsToActivate - if tBreakpoint is among the lines of the breakpoints then - next repeat - end if - put tBreakpoint & return after tBreakpointsNotActivated - end repeat - delete the last char of tBreakpointsNotActivated - put tBreakpointsNotActivated into tBreakpointsToActivate - - if the breakpoints is empty then - set the breakpoints to tBreakpointsToActivate - else - set the breakpoints to the breakpoints & return & tBreakpointsToActivate - end if -end revDebuggerActivateBreakpoints - # Parameters # pObject : reference to the object owning the breakpoint # pLine : the line number that the breakpoint is on @@ -992,16 +900,16 @@ end revDebuggerActivateBreakpoints # Empty if successful, an error string otherwise. command revDebuggerActivateBreakpoint pObject, pLine local tBreakpoint - put debuggerGetId(pObject) & comma & pLine into tBreakpoint + put __GetId(pObject) & comma & pLine into tBreakpoint local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tObjectBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tObjectBreakpoints local tLineNumber - put debuggerBreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber if tLineNumber = 0 then # This is a bug in the code that called this command @@ -1016,7 +924,7 @@ command revDebuggerActivateBreakpoint pObject, pLine end if local tBreakpointString - put debuggerResolveId(item 1 of tBreakpoint, tStack) & comma & pLine into tBreakpointString + put __ResolveId(item 1 of tBreakpoint, tStack) & comma & pLine into tBreakpointString if tCurrentBreakpoints is empty then set the breakpoints to tBreakpointString @@ -1027,7 +935,7 @@ command revDebuggerActivateBreakpoint pObject, pLine end if # Store the breakpoint's status in the object so it is remembered between restarts etc - debuggerUpdateBreakpointStatus tStack, tLineNumber, "active" + __UpdateBreakpointStatus tStack, tLineNumber, "active" end revDebuggerActivateBreakpoint # Parameters @@ -1038,18 +946,18 @@ end revDebuggerActivateBreakpoint # Sets the specified condition on the breakpoint. Set the condition to empty to remove it. command revDebuggerSetBreakpointCondition pObject, pLine, pCondition local tBreakpoint - put debuggerGetId(pObject) & comma & pLine into tBreakpoint + put __GetId(pObject) & comma & pLine into tBreakpoint local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tObjectBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tObjectBreakpoints local tLineNumber - put debuggerBreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpoint, tObjectBreakpoints) into tLineNumber - debuggerUpdateBreakpointCondition tStack, tLineNumber, pCondition + __UpdateBreakpointCondition tStack, tLineNumber, pCondition end revDebuggerSetBreakpointCondition # Parameters @@ -1060,16 +968,16 @@ end revDebuggerSetBreakpointCondition command revDebuggerDeactivateBreakpoint pObject, pLine # Ensure that the breakpoint actually exists local tBreakpoint - put debuggerGetId(pObject) & comma & pLine into tBreakpoint + put __GetId(pObject) & comma & pLine into tBreakpoint local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tObjectBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tObjectBreakpoints local tStackLineNumber - put debuggerBreakpointOffset(tBreakpoint, tObjectBreakpoints) into tStackLineNumber + put __BreakpointOffset(tBreakpoint, tObjectBreakpoints) into tStackLineNumber if tStackLineNumber = 0 then # This is a bug in the code that called this command. Don't throw errors in the debugger library @@ -1082,16 +990,16 @@ command revDebuggerDeactivateBreakpoint pObject, pLine put the breakpoints into tCurrentBreakpoints local tBreakpointString - put debuggerResolveId(item 1 of tBreakpoint, tStack) & comma & pLine into tBreakpointString + put __ResolveId(item 1 of tBreakpoint, tStack) & comma & pLine into tBreakpointString local tLineNumber - put debuggerBreakpointOffset(tBreakpointString, tCurrentBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpointString, tCurrentBreakpoints) into tLineNumber delete line tLineNumber of tCurrentBreakpoints set the breakpoints to tCurrentBreakpoints # Update the breakpoint's status # Store the breakpoint's status in the object so it is remember between restarts etc - debuggerUpdateBreakpointStatus tStack, tStackLineNumber, "inactive" + __UpdateBreakpointStatus tStack, tStackLineNumber, "inactive" end revDebuggerDeactivateBreakpoint # Parameters @@ -1102,18 +1010,18 @@ end revDebuggerDeactivateBreakpoint # format as the engine "breakpoints" property. function revDebuggerListBreakpoints pObject local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack - debuggerCleanBreakpoints tStack + __CleanBreakpoints tStack local tStackBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tStackBreakpoints local tBreakpointsList repeat for each line tBreakpoint in tStackBreakpoints - if debuggerGetId(pObject) = item 1 of tBreakpoint then + if __GetId(pObject) = item 1 of tBreakpoint then local tBreakpointString - put debuggerResolveId(item 1 of tBreakpoint, tStack) & comma & item 2 of tBreakpoint into tBreakpointString + put __ResolveId(item 1 of tBreakpoint, tStack) & comma & item 2 of tBreakpoint into tBreakpointString put tBreakpointString & return after tBreakpointsList end if end repeat @@ -1128,7 +1036,7 @@ function revDebuggerListActiveBreakpoints global gREVDevelopment # With gREVDevelopment we return all breakpoints exactly as they are - if gREVDevelopment then + if "development" is not in the environment or gREVDevelopment then return the breakpoints end if @@ -1144,7 +1052,7 @@ function revDebuggerListActiveBreakpoints local tStack put revTargetStack(revRuggedId(tObject)) into tStack - if revIDEStack(the effective filename of stack tStack) then + if revIDEStackIsIDEStack(the long id of stack tStack) then next repeat end if @@ -1200,7 +1108,7 @@ end revDebuggerParseWatch # Registers a watch with the specified parameters. Does not activate the watch. command revDebuggerAddWatch pObject, pHandler, pVariable, pCondition local tWatches - put debuggerGetWatchInformation(pObject, "watches") into tWatches + put __GetWatchInformation(pObject, "watches") into tWatches if the number of lines of tWatches >= kMaxActiveWatches then # Return an error here as the other option (removal of other watches # to make room) could potentially confuse the user. @@ -1208,21 +1116,21 @@ command revDebuggerAddWatch pObject, pHandler, pVariable, pCondition end if local tWatch - put debuggerBuildWatchLineFromDetails(pObject, pHandler, pVariable, pCondition, true) into tWatch + put __BuildWatchLineFromDetails(pObject, pHandler, pVariable, pCondition, true) into tWatch if tWatches is empty then put tWatch into tWatches else put tWatches & return & tWatch into tWatches end if - debuggerSetWatchInformation pObject, "watches", tWatches + __SetWatchInformation pObject, "watches", tWatches # New watches are initially inactive. local tStates - put debuggerGetWatchInformation(pObject, "watchstates") into tStates + put __GetWatchInformation(pObject, "watchstates") into tStates put "inactive" into line (the number of lines of tWatches) of tStates - debuggerSetWatchInformation pObject, "watchstates", tStates + __SetWatchInformation pObject, "watchstates", tStates - debuggerCleanWatches pObject + __CleanWatches pObject end revDebuggerAddWatch # Parameters @@ -1236,33 +1144,33 @@ command revDebuggerRemoveWatch pObject, pHandler, pVariable revDebuggerDeactivateWatch pObject, pHandler, pVariable local tWatch - put debuggerBuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch + put __BuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch local tStoredWatches - put debuggerGetWatchInformation(pObject, "watches") into tStoredWatches + put __GetWatchInformation(pObject, "watches") into tStoredWatches local tStates - put debuggerGetWatchInformation(pObject, "watchstates") into tStates + put __GetWatchInformation(pObject, "watchstates") into tStates local tLineNumber - put debuggerWatchOffset(tWatch, tStoredWatches) into tLineNumber + put __WatchOffset(tWatch, tStoredWatches) into tLineNumber if tLineNumber = 0 then return "Watch not found" end if delete line tLineNumber of tStoredWatches delete line tLineNumber of tStates - debuggerSetWatchInformation pObject, "watches", tStoredWatches - debuggerSetWatchInformation pObject, "watchstates", tStates - debuggerCleanWatches pObject + __SetWatchInformation pObject, "watches", tStoredWatches + __SetWatchInformation pObject, "watchstates", tStates + __CleanWatches pObject end revDebuggerRemoveWatch -private function debuggerBuildWatchLineFromDetails pObject, pHandler, pVariable, pCondition, pIncludeTrailingCommaIfConditionEmpty +private function __BuildWatchLineFromDetails pObject, pHandler, pVariable, pCondition, pIncludeTrailingCommaIfConditionEmpty local tLine if pObject is empty then put empty & comma & empty & comma & pVariable into tLine else - put debuggerGetId(pObject) & comma & pHandler & comma & pVariable into tLine + put __GetId(pObject) & comma & pHandler & comma & pVariable into tLine end if if pIncludeTrailingCommaIfConditionEmpty or pCondition is not empty then @@ -1274,52 +1182,56 @@ private function debuggerBuildWatchLineFromDetails pObject, pHandler, pVariable, end if return tLine -end debuggerBuildWatchLineFromDetails +end __BuildWatchLineFromDetails -private function debuggerGetWatchDataStoreForObject pObject +private function __GetWatchDataStoreForObject pObject if pObject is empty then - return the long id of stack "revPreferences" + if the environment contains "development" then + return the long id of stack "revPreferences" + else + return the long id of me + end if else - return debuggerTargetStack(pObject) + return __TargetStack(pObject) end if -end debuggerGetWatchDataStoreForObject +end __GetWatchDataStoreForObject -private function debuggerGetWatchDataStoreTypeForObject pObject +private function __GetWatchDataStoreTypeForObject pObject if pObject is empty then return "debugger" else return kMetadataType end if -end debuggerGetWatchDataStoreTypeForObject +end __GetWatchDataStoreTypeForObject -private command debuggerSetWatchInformation pObject, pInformationType, pValue +private command __SetWatchInformation pObject, pInformationType, pValue # Watch information (watchedVariables) can be found in two possible locations, # if pObject is given, then the stack owning pObject will contain the metadata in its # cREVGeneral custom property set. This is for watchedVariables at handler or script local scope. # For global variables, pObject is empty, and the information is stored in the preferences stack. local tMetadataType - put debuggerGetWatchDataStoreTypeForObject(pObject) into tMetadataType + put __GetWatchDataStoreTypeForObject(pObject) into tMetadataType local tMetadataStore - put debuggerGetWatchDataStoreForObject(pObject) into tMetadataStore + put __GetWatchDataStoreForObject(pObject) into tMetadataStore revMetadataSet tMetadataStore, tMetadataType, pInformationType, pValue -end debuggerSetWatchInformation +end __SetWatchInformation -private function debuggerGetWatchInformation pObject, pInformationType +private function __GetWatchInformation pObject, pInformationType # Watch information (watchedVariables) can be found in two possible locations, # if pObject is given, then the stack owning pObject will contain the metadata in its # cREVGeneral custom property set. This is for watchedVariables at handler or script local scope. # For global variables, pObject is empty, and the information is stored in the preferences stack. local tMetadataType - put debuggerGetWatchDataStoreTypeForObject(pObject) into tMetadataType + put __GetWatchDataStoreTypeForObject(pObject) into tMetadataType local tMetadataStore - put debuggerGetWatchDataStoreForObject(pObject) into tMetadataStore + put __GetWatchDataStoreForObject(pObject) into tMetadataStore return revMetadataGet(tMetadataStore, tMetadataType, pInformationType) -end debuggerGetWatchInformation +end __GetWatchInformation # Parameters @@ -1340,13 +1252,13 @@ command revDebuggerDeactivateWatch pObject, pHandler, pVariable -- end if local tStackWatches - put debuggerGetWatchInformation(pObject, "watches") into tStackWatches + put __GetWatchInformation(pObject, "watches") into tStackWatches local tWatch - put debuggerBuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch + put __BuildWatchLineFromDetails(pObject, pHandler, pVariable) into tWatch local tStackLineNumber - put debuggerWatchOffset(tWatch, tStackWatches) into tStackLineNumber + put __WatchOffset(tWatch, tStackWatches) into tStackLineNumber if tStackLineNumber = 0 then # This is a bug in the code that called this command. Don't throw errors in the debugger library @@ -1365,7 +1277,7 @@ command revDebuggerDeactivateWatch pObject, pHandler, pVariable if pObject is empty then put empty into tResolvedObject else - put debuggerResolveId(item 1 of tWatch, debuggerTargetStack(pObject)) into tResolvedObject + put __ResolveId(item 1 of tWatch, __TargetStack(pObject)) into tResolvedObject end if local tWatchString @@ -1376,13 +1288,13 @@ command revDebuggerDeactivateWatch pObject, pHandler, pVariable end if local tLineNumber - put debuggerWatchOffset(tWatchString, tCurrentWatches) into tLineNumber + put __WatchOffset(tWatchString, tCurrentWatches) into tLineNumber delete line tLineNumber of tCurrentWatches set the watchedVariables to tCurrentWatches # Store the watch's status in the object so it is remembered between restarts etc - debuggerUpdateWatchStatus pObject, tStackLineNumber, "inactive" + __UpdateWatchStatus pObject, tStackLineNumber, "inactive" end revDebuggerDeactivateWatch # Parameters @@ -1391,15 +1303,15 @@ end revDebuggerDeactivateWatch # A list of watches set on the specified object, in the format of the watchedVariables property. function revDebuggerListWatches pObject local tWatches - put debuggerGetWatchInformation(pObject, "watches") into tWatches + put __GetWatchInformation(pObject, "watches") into tWatches local tMatchingWatches repeat for each line tWatch in tWatches if pObject is empty then put empty & comma & item 2 to -1 of tWatch & return after tMatchingWatches else - if debuggerGetId(pObject) is item 1 of tWatch then - put debuggerResolveId(item 1 of tWatch, debuggerTargetStack(pObject)) & comma & item 2 to -1 of tWatch & return after tMatchingWatches + if __GetId(pObject) is item 1 of tWatch then + put __ResolveId(item 1 of tWatch, __TargetStack(pObject)) & comma & item 2 to -1 of tWatch & return after tMatchingWatches end if end if end repeat @@ -1409,9 +1321,8 @@ function revDebuggerListWatches pObject end revDebuggerListWatches function revDebuggerListWatchStates pObject - local tWatches - put debuggerGetWatchInformation(pObject, "watches") into tWatches + put __GetWatchInformation(pObject, "watches") into tWatches local tMatchingLineNumbers @@ -1421,7 +1332,7 @@ function revDebuggerListWatchStates pObject if pObject is empty then put tLineNumber & return after tMatchingLineNumbers else - if debuggerGetId(pObject) is item 1 of tWatch then + if __GetId(pObject) is item 1 of tWatch then put tLineNumber & return after tMatchingLineNumbers end if end if @@ -1430,7 +1341,7 @@ function revDebuggerListWatchStates pObject delete the last char of tMatchingLineNumbers local tStates - put debuggerGetWatchInformation(pObject, "watchstates") into tStates + put __GetWatchInformation(pObject, "watchstates") into tStates local tMatchingStates repeat for each line tMatchingLineNumber in tMatchingLineNumbers @@ -1451,7 +1362,7 @@ end revDebuggerListWatchStates # in the same order as the breakpoints list. function revDebuggerListBreakpointStates pObject local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tBreakpoints @@ -1461,7 +1372,7 @@ function revDebuggerListBreakpointStates pObject local tMatchingLines repeat for each line tBreakpoint in tBreakpoints - if debuggerGetId(pObject) = item 1 of tBreakpoint then + if __GetId(pObject) = item 1 of tBreakpoint then put tLineNumber & return after tMatchingLines end if add 1 to tLineNumber @@ -1486,7 +1397,7 @@ end revDebuggerListBreakpointStates # Returns a list of the conditions of the breakpoints for pObject. function revDebuggerListBreakpointConditions pObject local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tBreakpoints @@ -1496,7 +1407,7 @@ function revDebuggerListBreakpointConditions pObject local tMatchingLines repeat for each line tBreakpoint in tBreakpoints - if debuggerGetId(pObject) = item 1 of tBreakpoint then + if __GetId(pObject) = item 1 of tBreakpoint then put tLineNumber & return after tMatchingLines end if add 1 to tLineNumber @@ -1548,7 +1459,7 @@ function revDebuggerNextAvailableBreakpoint @pScript, pLineNumber put line tLineNumber to -1 of pScript into tText local tContinuation - put debuggerLineHasContinuation(line 1 of tText) into tContinuation + put __LineHasContinuation(line 1 of tText) into tContinuation local tInHandler @@ -1562,7 +1473,7 @@ function revDebuggerNextAvailableBreakpoint @pScript, pLineNumber # Detect if the line is a continuation of line tLineNumber if tContinuation then - put debuggerLineHasContinuation(tCurrentLine) into tContinuation + put __LineHasContinuation(tCurrentLine) into tContinuation next repeat end if @@ -1595,7 +1506,14 @@ function revDebuggerNextAvailableBreakpoint @pScript, pLineNumber return tMatchingLineNumber + 1 end if end revDebuggerNextAvailableBreakpoint - + + +command revDebuggerReturnToEditMode + repeat for each line tScriptEditor in revScriptEditors() + send "revSESetMode edit" to tScriptEditor + end repeat +end revDebuggerReturnToEditMode + ################################################################################ # @@ -1613,16 +1531,16 @@ local sLastDisplayedContexts # Returns # The line number that the specified breakpoint appears on in # pBreakpoints, or 0 if it does not appear. -private function debuggerBreakpointOffset pBreakpoint, pBreakpoints +private function __BreakpointOffset pBreakpoint, pBreakpoints set the wholeMatches to true return lineOffset(pBreakpoint, pBreakpoints) set the wholeMatches to false -end debuggerBreakpointOffset +end __BreakpointOffset # Parameters # pWatch : the watch to search for (object, handler, variable) # pWatches : the list of watches to search in -private function debuggerWatchoffset pWatch, pWatches +private function __Watchoffset pWatch, pWatches local tMatchString if the last char of pWatch is not comma then put pWatch & comma into tMatchString @@ -1630,13 +1548,13 @@ private function debuggerWatchoffset pWatch, pWatches put pWatch into tMatchString end if return lineOffset(tMatchString, pWatches) -end debuggerWatchoffset +end __Watchoffset # Parameters # pLine : a line of LiveCode script # Returns # Whether or not pLine has a continuation -private function debuggerLineHasContinuation pLine +private function __LineHasContinuation pLine # First find if the line contains a continuation char among its words, if not then we're done. local tContinuationCharOffset put wordOffset("\", pLine) into tContinuationCharOffset @@ -1669,7 +1587,7 @@ private function debuggerLineHasContinuation pLine end if end if end repeat -end debuggerLineHasContinuation +end __LineHasContinuation # Parameters @@ -1679,19 +1597,19 @@ end debuggerLineHasContinuation # Description # Evaluates the specified breakpoint's condition and returns whether to break or not. # If the breakpoint has no condition attached to to, returns true, otherwise it depends on the condition. -private function debuggerEvaluateCondition pObject, pLine, pContext +private function __EvaluateCondition pObject, pLine, pContext local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tBreakpoints local tBreakpoint - put debuggerGetId(pObject) & comma & pLine into tBreakpoint + put __GetId(pObject) & comma & pLine into tBreakpoint local tLineNumber - put debuggerBreakpointOffset(tBreakpoint, tBreakpoints) into tLineNumber + put __BreakpointOffset(tBreakpoint, tBreakpoints) into tLineNumber if tLineNumber = 0 then # The debugger library does not know about this breakpoint but this is not neccessarily an error, # it could be a script breakpoint or one that the user manually set. Also it could be an internal breakpoint @@ -1723,19 +1641,19 @@ private function debuggerEvaluateCondition pObject, pLine, pContext else return false end if -end debuggerEvaluateCondition +end __EvaluateCondition -private function debuggerTargetStack pObject +private function __TargetStack pObject local tStackName put revTargetStack(pObject) into tStackName return the long id of stack tStackName -end debuggerTargetStack +end __TargetStack # Implements the revDebuggerAddBreakpoint and revDebuggerAddConditionalBreakpoint # commands, please see the comments above them for semantics and parameters. -private command debuggerAddBreakpoint pObject, pLine, pCondition +private command __AddBreakpoint pObject, pLine, pCondition local tStack - put debuggerTargetStack(pObject) into tStack + put __TargetStack(pObject) into tStack local tStackBreakpoints put revMetadataGet(tStack, kMetadataType, "breakpoints") into tStackBreakpoints @@ -1746,7 +1664,7 @@ private command debuggerAddBreakpoint pObject, pLine, pCondition end if local tNewBreakpoint - put debuggerGetId(pObject) & comma & pLine into tNewBreakpoint + put __GetId(pObject) & comma & pLine into tNewBreakpoint if tStackBreakpoints is empty then put tNewBreakpoint into tStackBreakpoints @@ -1762,7 +1680,7 @@ private command debuggerAddBreakpoint pObject, pLine, pCondition revMetadataSet tStack, kMetadataType, "breakpointstates", tStates if pCondition is empty then - exit debuggerAddBreakpoint + exit __AddBreakpoint end if # Apply the condition if given. @@ -1771,8 +1689,8 @@ private command debuggerAddBreakpoint pObject, pLine, pCondition put pCondition into line (the number of lines of tStackBreakpoints) of tStackConditions revMetadataSet tStack, kMetadataType, "breakpointconditions", tStackConditions - debuggerCleanBreakpoints tStack -end debuggerAddBreakpoint + __CleanBreakpoints tStack +end __AddBreakpoint # Parameters # pObject : reference to the object to clean watches for @@ -1780,12 +1698,12 @@ end debuggerAddBreakpoint # Cleans up the specified stack's watch related metadata by removing # watches that cannot be resolved (e.g. because the object was deleted) # and removing any duplicates. -private command debuggerCleanWatches pObject +private command __CleanWatches pObject local tStack - put debuggerGetWatchDataStoreForObject(pObject) into tStack + put __GetWatchDataStoreForObject(pObject) into tStack local tMetadataType - put debuggerGetWatchDataStoreTypeForObject(pObject) into tMetadataType + put __GetWatchDataStoreTypeForObject(pObject) into tMetadataType local tWatches put revMetadataGet(tStack, tMetadataType, "watches") into tWatches @@ -1802,7 +1720,7 @@ private command debuggerCleanWatches pObject # otherwise we're cleaning the global watches, so we don't perform this check. if pObject is not empty then try - get debuggerResolveId(item 1 of tWatch, tStack) + get __ResolveId(item 1 of tWatch, tStack) catch tError # debuggerResolveId will fail if the watch cannot be resolved, # this means the object has somehow been deleted, moved etc without @@ -1812,7 +1730,7 @@ private command debuggerCleanWatches pObject end if # Remove duplicates - if debuggerWatchOffset(tWatch, tCleanedWatches) <> 0 then + if __WatchOffset(tWatch, tCleanedWatches) <> 0 then next repeat end if @@ -1825,7 +1743,7 @@ private command debuggerCleanWatches pObject revMetadataSet tStack, tMetadataType, "watches", tCleanedWatches revMetadataSet tStack, tMetadataType, "watchstates", tCleanedStates -end debuggerCleanWatches +end __CleanWatches # Parameters # pStack : reference to the stack to clean breakpoints for @@ -1833,7 +1751,7 @@ end debuggerCleanWatches # Cleans up the specified stack's breakpoint related metadata by removing # breakpoints that cannot be resolved (e.g. because the object was deleted) # and removing any duplicates. -private command debuggerCleanBreakpoints pStack +private command __CleanBreakpoints pStack local tBreakpoints put revMetadataGet(pStack, kMetadataType, "breakpoints") into tBreakpoints @@ -1849,7 +1767,7 @@ private command debuggerCleanBreakpoints pStack local tCleanedBreakpoints, tCleanedStates, tCleanedConditions repeat for each line tBreakpoint in tBreakpoints try - get debuggerResolveId(item 1 of tBreakpoint, pStack) + get __ResolveId(item 1 of tBreakpoint, pStack) catch tError # debuggerResolveId will fail if the breakpoint cannot be resolved, # this means the object has somehow been deleted, moved etc without @@ -1875,7 +1793,7 @@ private command debuggerCleanBreakpoints pStack revMetadataSet pStack, kMetadataType, "breakpoints", tCleanedBreakpoints revMetadataSet pStack, kMetadataType, "breakpointstates", tCleanedStates revMetadataSet pStack, kMetadataType, "breakpointconditions", tCleanedConditions -end debuggerCleanBreakpoints +end __CleanBreakpoints # Parameters # pStack : reference to the stack to update @@ -1883,12 +1801,12 @@ end debuggerCleanBreakpoints # pStatus : the breakpoint status to set. This can be "active" or "inactive". # Description # Sets a breakpoint's status to pStatus. -private command debuggerUpdateBreakpointStatus pStack, pBreakpointNumber, pStatus +private command __UpdateBreakpointStatus pStack, pBreakpointNumber, pStatus local tObjectBreakpointStatus put revMetadataGet(pStack, kMetadataType, "breakpointstates") into tObjectBreakpointStatus put pStatus into line pBreakpointNumber of tObjectBreakpointStatus revMetadataSet pStack, kMetadataType, "breakpointstates", tObjectBreakpointStatus -end debuggerUpdateBreakpointStatus +end __UpdateBreakpointStatus # Parameters # pStack : reference to the stack to update @@ -1897,19 +1815,19 @@ end debuggerUpdateBreakpointStatus # breakpoint's context and should evaluate to true or false. # Description # Sets a breakpoint's condition to pCondition. -private command debuggerUpdateBreakpointCondition pStack, pBreakpointNumber, pCondition +private command __UpdateBreakpointCondition pStack, pBreakpointNumber, pCondition local tConditions put revMetadataGet(pStack, kMetadataType, "breakpointconditions") into tConditions put pCondition into line pBreakpointNumber of tConditions revMetadataSet pStack, kMetadataType, "breakpointconditions", tConditions -end debuggerUpdateBreakpointCondition +end __UpdateBreakpointCondition -private command debuggerUpdateWatchStatus pObject, pWatchNumber, pStatus +private command __UpdateWatchStatus pObject, pWatchNumber, pStatus local tStack - put debuggerGetWatchDataStoreForObject(pObject) into tStack + put __GetWatchDataStoreForObject(pObject) into tStack local tMetadataType - put debuggerGetWatchDataStoreTypeForObject(pObject) into tMetadataType + put __GetWatchDataStoreTypeForObject(pObject) into tMetadataType local tStates put revMetadataGet(tStack, tMetadataType, "watchstates") into tStates @@ -1917,7 +1835,108 @@ private command debuggerUpdateWatchStatus pObject, pWatchNumber, pStatus put pStatus into line pWatchNumber of tStates revMetadataSet tStack, tMetadataType, "watchstates", tStates -end debuggerUpdateWatchStatus +end __UpdateWatchStatus + +private command __ActivateWatches pStack + local tWatches + put __GetWatchInformation(pStack, "watches") into tWatches + + local tWatchStates + put __GetWatchInformation(pStack, "watchstates") into tWatchStates + + local tLineNumber + put 1 into tLineNumber + repeat for each line tWatchState in tWatchStates + local tCurrentWatches + put the watchedVariables into tCurrentWatches + if the number of lines of tCurrentWatches >= kMaxActiveWatches then + return "Active watch limit reached" + end if + + if tWatchState is not "active" then + add 1 to tLineNumber + next repeat + end if + + local tWatch + put line tLineNumber of tWatches into tWatch + + local tWatchString + if item 1 of tWatch is empty then + put tWatch into tWatchString + else + put __ResolveId(item 1 of tWatch, pStack) & comma & item 2 to -1 of tWatch into tWatchString + end if + + if tCurrentWatches is empty then + set the watchedVariables to tWatchString + else + if tWatchString is not among the lines of tCurrentWatches then + set the watchedVariables to tCurrentWatches & return & tWatchString + end if + end if + + add 1 to tLineNumber + end repeat +end __ActivateWatches + +# Parameters +# pStack : reference to the stack to activate breakpoints for +# pObject : reference to an object on the stack +# Description +# Activates breakpoints stored on pStack. If pObject is empty then all breakpoints +# are activated, otherwise only those breakpoints that are in the script of pObject +# are activated. +private command __ActivateBreakpoints pStack, pObject + local tStack + if pObject is not empty then + put __TargetStack(pObject) into tStack + if the long id of tStack is not the long id of pStack then + return "invalid object" + end if + end if + + local tLineNumber + put 1 into tLineNumber + + local tStackBreakpoints + put revMetadataGet(pStack, kMetadataType, "breakpoints") into tStackBreakpoints + + local tStates + put revMetadataGet(pStack, kMetadataType, "breakpointstates") into tStates + + local tBreakpointsToActivate + repeat for each line tBreakpoint in tStackBreakpoints + if pObject is empty or item 1 of tBreakpoint is __GetId(pObject) then + local tState + put line tLineNumber of tStates into tState + + if tState is "active" then + put __ResolveId(item 1 of tBreakpoint, pStack) & comma & item 2 of tBreakpoint & return after tBreakpointsToActivate + end if + end if + end repeat + delete the last char of tBreakpointsToActivate + + # If the breakpoints property is allowed to contain duplicates, then the lines with duplicate breakpoints on + # will break more than once, i.e. multiple traceBreak messages. We should ensure that this doesn't happen, + # as there is no good reason for it and it will just cause annoyance. + local tBreakpointsNotActivated + repeat for each line tBreakpoint in tBreakpointsToActivate + if tBreakpoint is among the lines of the breakpoints then + next repeat + end if + put tBreakpoint & return after tBreakpointsNotActivated + end repeat + delete the last char of tBreakpointsNotActivated + put tBreakpointsNotActivated into tBreakpointsToActivate + + if the breakpoints is empty then + set the breakpoints to tBreakpointsToActivate + else + set the breakpoints to the breakpoints & return & tBreakpointsToActivate + end if +end __ActivateBreakpoints # Paramaeters # pId : the debugger id of an object used to store a breakpoint. @@ -1927,18 +1946,20 @@ end debuggerUpdateWatchStatus # Description # pId is either the short id of a control in pStack, or 0 if the breakpoint # being resolved is in the stack script. -private function debuggerResolveId pId, pStack +private function __ResolveId pId, pStack + local tID if pId is 0 then - return the long id of pStack + put the long id of pStack into tID else # As the object could be a card, we attempt that first if there is a card id pId of pStack then - return the long id of card id pId of pStack + put the long id of card id pId of pStack into tID else - return the long id control id pId of pStack + put the long id of control id pId of pStack into tID end if end if -end debuggerResolveId + return tID +end __ResolveId # Parameters # pObject : reference to the object to get the debugger id for @@ -1947,31 +1968,35 @@ end debuggerResolveId # with breakpoints set on the object, and used to determine which object each # breakpoint is associated with. The debugger id is the short id of the object if # it is a control or a card. If the object is a stack, the debugger id is 0. -private function debuggerGetId pObject +private function __GetId pObject if word 1 of the name of pObject is "stack" then return 0 end if return the id of pObject -end debuggerGetId +end __GetId # Returns # Whether or not the debugger is enabled. This is currently determined by the "Script Debug Mode" # setting in the LiveCode preferences stack. -private function debuggerEnabled - return revIDEGetPreference("cREVScriptDebugMode") -end debuggerEnabled +private function __Enabled + if the environment is "development" then + return revIDEGetPreference("cREVScriptDebugMode") + end if + + return false +end __Enabled # Parameters # pStack : reference to a stack # Returns # Whether or not the debugger is allowed to debug the specified stack in # the current circumstances. -private function debuggerStackAllowed pStack +private function __StackAllowed pStack global gREVDevelopment - if gREVDEvelopment then + if "development" is not in the environment or gREVDEvelopment then # With gREVDevelopment allow all stacks to be debugged except the debugger, as doing this will probably not work anyway. - if the short name of pStack is "revDebuggerLibrary" then + if the short name of pStack is among the items of "revDebuggerLibrary,com.livecode.library.remotedebugger" then return false else return true @@ -1984,7 +2009,20 @@ private function debuggerStackAllowed pStack else return true end if -end debuggerStackAllowed +end __StackAllowed + +function revDebuggerObjectName pObject + return the name of pObject +end revDebuggerObjectName + +function revDebuggerObjectLongName pObject + return the long name of pObject +end revDebuggerObjectLongName + +private command __UpdateScriptEditor pObject, pHandler, pLine, pState, pError + put revDebuggerContexts() into sLastDisplayedContexts + revDebuggerUpdateScriptEditor pObject, pHandler, pLine, pState, pError +end __UpdateScriptEditor # Parameters # pObject : reference to the object owning the executing code @@ -1996,15 +2034,19 @@ end debuggerStackAllowed # of code is about to be executed in the debugger. If there is no script # editor open for pObject then does nothing. # Otherwise tells the script editor to display the appropriate line etc. -private command debuggerUpdateScriptEditor pObject, pHandler, pLine, pState +command revDebuggerUpdateScriptEditor pObject, pHandler, pLine, pState, pError + + if there is not a pObject then + return empty + end if + local tScriptEditor put revScriptEditor(the long id of pObject) into tScriptEditor if tScriptEditor is empty then - debuggerShowScript pObject + __ShowScript pObject end if put revScriptEditor(the long id of pObject) into tScriptEditor - put revDebuggerContexts() into sLastDisplayedContexts local tMode send "revSEGetMode" to stack tScriptEditor @@ -2018,6 +2060,10 @@ private command debuggerUpdateScriptEditor pObject, pHandler, pLine, pState local tFalseString put "false" into tFalseString + -- force the context to be that which we want to be displayed otherwise when gRevDevelopment + -- is true the other contexts are returned + put line 1 of sLastDisplayedContexts into sContext + # These must be sent in time to allow the script editor a chance to set its current object, # otherwise an infinite loop could occur. send "revSEGoExecutionPoint pObject, pLine, true" to stack tScriptEditor in 0 milliseconds @@ -2025,57 +2071,70 @@ private command debuggerUpdateScriptEditor pObject, pHandler, pLine, pState # OK-2008-08-18 : Bug 6935 - Toplevel / uniconify the script editor here. revGoScriptEditor the name of stack tScriptEditor -end debuggerUpdateScriptEditor + + if pError is not empty then + if the number of items of pError is 1 then + put comma & pLine after pError + end if + # OK-2008-07-10 : This needs to be sent in time so that it arrives after the script + # editor has finished initializing itself. + send "revSEDisplayExecutionError pError, pObject" to stack tScriptEditor in 0 milliseconds + end if +end revDebuggerUpdateScriptEditor -private function debuggerErrorsSuppressed +private function __ErrorsSuppressed global gREVSuppressErrors return (gREVSuppressErrors is true) -end debuggerErrorsSuppressed +end __ErrorsSuppressed private function revScriptEditors return revListScriptEditors() end revScriptEditors -private command debuggerShowScript pObject +private command __ShowScript pObject edit the script of pObject -end debuggerShowScript +end __ShowScript -private command log pMessage - put pMessage & return after msg -end log +private command __Log pMessage + if the environment contains "development" then + put pMessage & return after msg + else + write pMessage & return to stdout + end if +end __Log # Description # Shows revErrorDisplay in response to a trace error. # This has been hacked in for now to avoid modifying revErrorDisplay. -private command debuggerShowErrorDialog pObject, pHandler, pLine, pError +private command __ShowErrorDialog pObject, pHandler, pLine, pError answer error "An execution error ocurred in the script of the object : " & the short name of pObject & return & \ - "The error was on line " & pLine & " in the " & pHandler & " handler. The error was: " & return & \ - pError & " What would you like to do?" with "Ignore" or "Debug" or "Script" + "The error was on line " & pLine & " in the " & pHandler & " handler. The error was: " & return & \ + pError & " What would you like to do?" with "Ignore" or "Debug" or "Script" if it is "Ignore" then revDebuggerStop - exit debuggerShowErrorDialog + exit __ShowErrorDialog end if if it is "Script" then revDebuggerStop - debuggerUpdateScriptEditor pObject, pHandler, pLine, "edit" + __UpdateScriptEditor pObject, pHandler, pLine, "edit" end if if it is "Debug" then - debuggerUpdateScriptEditor pObject, pHandler, pLine, "debug" + __UpdateScriptEditor pObject, pHandler, pLine, "debug" end if -end debuggerShowErrorDialog +end __ShowErrorDialog # Parameters # pTarget : the long id of the target of the message # pContextLine : the complete line of the executionContexts that represents the code in the user stack about to run. # Returns # The target object that contains the line of script about to run, taking parentScripts into account. -private function debuggerResolveTarget pTarget, pContextLine +private function __ResolveTarget pTarget, pContextLine # OK-2009-06-23: Bug 7954 local tArray - put parseExecutionContext(pContextLine) into tArray + put __ParseExecutionContext(pContextLine) into tArray if tArray["behavior"] is not empty then return tArray["behavior"] @@ -2088,14 +2147,14 @@ private function debuggerResolveTarget pTarget, pContextLine -- else -- return pTarget -- end if -end debuggerResolveTarget +end __ResolveTarget # Parameters # pContextLine: the complete line of the executionContexts that represents the code in the user stack about to run. -private function debuggerResolveHandler pContextLine +private function __ResolveHandler pContextLine # OK-2009-06-23 : Bug 7954 local tArray - put parseExecutionContext(pContextLine) into tArray + put __ParseExecutionContext(pContextLine) into tArray return tArray["handler"] -- if the number of items of pContextLine = 5 then @@ -2103,15 +2162,22 @@ private function debuggerResolveHandler pContextLine -- else -- return item -2 of pContextLine -- end if -end debuggerResolveHandler +end __ResolveHandler -private function debuggerTargetIsModal pTarget - return (the mode of stack (revTargetStack(pTarget)) = 5) -end debuggerTargetIsModal +private function __ModalPresented + local tStack + repeat for each line tStack in the openStacks + if the mode of stack tStack is 5 then + return true + end if + end repeat + + return false +end __ModalPresented -private command debuggerShowModalWarning +private command __ShowModalWarning -end debuggerShowModalWarning +end __ShowModalWarning ################################################################################ # @@ -2119,6 +2185,23 @@ end debuggerShowModalWarning # ################################################################################ +# CW-2015-10-05: [[ Bug 16079 ] Activate breakpoints now in case there are any in preOpenStack handlers +on preOpenStack + if revDebuggerEnabled() then + local tTarget + put the long id of the target into tTarget + + local tStack + put revTargetStack(tTarget) into tStack + + if tTarget is not the long id of me then + __ActivateBreakpoints the long id of stack tStack + __ActivateWatches the long id of stack tStack + end if + end if + pass preOpenStack +end preOpenStack + local sLastAllowedContext # Description @@ -2132,16 +2215,18 @@ local sLastAllowedContext # was called from, then updates the script editor. If the last debug action # was "Step Into", always updates the script editor. on trace pHandler, pLine, pPosition + delete variable sLastBreakInfo + local tTarget - put debuggerResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget + put __ResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget local tStack - put debuggerTargetStack(tTarget) into tStack + put __TargetStack(tTarget) into tStack local tCurrentContexts put revDebuggerContexts() into tCurrentContexts - if not debuggerStackAllowed(tStack) then + if not __StackAllowed(tStack) then # OK-2009-03-13 : Instead of stepping out, instead we just ignore this and wait for the next # trace message. This will result in the debugger being slower as some of the advantage of using # traceUntil will be lost. @@ -2168,13 +2253,13 @@ on trace pHandler, pLine, pPosition local tNextContextCount if sLastTraceMode is "Step Into" then - debuggerUpdateScriptEditor tTarget, pHandler, pLine, "debug" + __UpdateScriptEditor tTarget, pHandler, pLine, "debug" else if sLastTraceMode is "Step Over" then local tLastHandler - put debuggerResolveHandler(line 1 of sLastDisplayedContexts) into tLastHandler + put __ResolveHandler(line 1 of sLastDisplayedContexts) into tLastHandler if line 2 to -1 of sLastDisplayedContexts is line 2 to -1 of tCurrentContexts and pHandler is tLastHandler then - debuggerUpdateScriptEditor tTarget, pHandler, pLine, "debug" + __UpdateScriptEditor tTarget, pHandler, pLine, "debug" set the traceStack to the name of tStack else # Calculate the number of execution contexts that there should be before we get the next trace message. @@ -2188,10 +2273,10 @@ on trace pHandler, pLine, pPosition else if sLastTraceMode is "Step Out" then # OK-2009-06-23 : Bug 7954 local tArray - put parseExecutionContext(line 2 of sLastDisplayedContexts) into tArray + put __ParseExecutionContext(line 2 of sLastDisplayedContexts) into tArray - if line 3 to -1 of sLastDisplayedContexts is line 2 to -1 of revDebuggerContexts() and pHandler is tArray["handler"] then - debuggerUpdateScriptEditor tTarget, pHandler, pLine, "debug" + if line 3 to -1 of sLastDisplayedContexts is line 2 to -1 of tCurrentContexts and pHandler is tArray["handler"] then + __UpdateScriptEditor tTarget, pHandler, pLine, "debug" else put item 1 line 1 of tCurrentContexts - 2 into tNextContextCount set the traceUntil to tNextContextCount @@ -2206,13 +2291,13 @@ end trace # all open script editors to switch to edit mode, then does the debugger run # action. on traceDone + delete variable sLastBreakInfo + # OK-2009-03-13 : Once we've got a traceDone, shut down the debugger first, # as otherwise we have to trace through all the script editor code which slows things down. revDebuggerRun - repeat for each line tScriptEditor in revScriptEditors() - send "revSESetMode edit" to tScriptEditor - end repeat + revDebuggerReturnToEditMode end traceDone constant kErrorRecursionLimit = 2 @@ -2228,10 +2313,27 @@ constant kErrorRecursionLimit = 2 # via the throw command, or messages are suppressed, exits to top. # Otherwise, launches the debugger, showing the current execution context. on traceError pHandler, pLine, pPosition, pError + if the environment contains "development" and revTestEnvironment() then + pass traceError + end if + + -- shield from same message with error being repeatedly called + local tBreakInfo + put the long id of the target into tBreakInfo["target"] + put pHandler into tBreakInfo["handler"] + put pLine into tBreakInfo["line"] + put pPosition into tBreakInfo["position"] + put pError into tBreakInfo["error"] + if tBreakInfo is sLastBreakInfo then + pass traceError + else + put tBreakInfo into sLastBreakInfo + end if + if item 1 of pError is kErrorRecursionLimit then local tMessage put "The handler: " & pHandler & " has reached the recursion limit of: " & the recursionLimit & "." & return & \ - "Execution will be terminated to prevent hang" into tMessage + "Execution will be terminated to prevent hang" into tMessage answer error tMessage revDebuggerStop @@ -2239,62 +2341,57 @@ on traceError pHandler, pLine, pPosition, pError end if local tTarget - put debuggerResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget + put __ResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget close printing - if not debuggerEnabled() then + if not revDebuggerEnabled() then pass traceError end if - if debuggerTargetIsModal(tTarget) then - debuggerShowModalWarning + if "development" is in the environment and __ModalPresented() then + __ShowModalWarning pass traceError end if local tStack - put debuggerTargetStack(tTarget) into tStack + put __TargetStack(tTarget) into tStack # OK-2008-11-05 : If the target of the debugger message is modal, then act as though the debugger # is disabled. This is not ideal, but beats allowing the IDE to lock up. - if the mode of tStack >= 5 then - pass traceError - end if - - -- We can not flush moveStack and resizeStack messages so the IDE will lock up if we try and trace - local tContexts - put the executionContexts into tContexts - local tLine - repeat for each line tLine in tContexts - if item -2 of tLine is among the words of "moveStack resizeStack" then + if the environment contains "development" then + if the mode of tStack >= 5 then pass traceError end if - end repeat + + -- The IDE will lock up if we try and trace messages repeatedly coming from OS + local tContexts + put the executionContexts into tContexts + local tLine + repeat for each line tLine in tContexts + if item -2 of tLine is among the words of kUndebuggableHandlers then + pass traceError + end if + end repeat + end if if pError is empty then revDebuggerStop exit traceError end if - if debuggerErrorsSuppressed() or the waitDepth > 2 then + if __ErrorsSuppressed() or the waitDepth > 2 then exit to top end if - if not debuggerStackAllowed(tStack) then + if not __StackAllowed(tStack) then revDebuggerStop exit traceError end if - debuggerUpdateScriptEditor tTarget, pHandler, pLine, "debug" + __UpdateScriptEditor tTarget, pHandler, pLine, "debug", pError set the traceStack to the short name of tStack - - local tEditor - put revScriptEditor(tTarget) into tEditor - - # OK-2008-07-10 : This needs to be sent in time so that it arrives after the script - # editor has finished initializing itself. - send "revSEDisplayExecutionError pError, tTarget" to stack tEditor in 0 milliseconds end traceError # Parameters @@ -2305,43 +2402,60 @@ end traceError # nothing. Otherwise, opens a script editor for the object (unless one is # already open) and updates it appropriately. on traceBreak pHandler, pLine + if the environment contains "development" and revTestEnvironment() then + pass traceBreak + end if + + -- shield from same message with breakpoint being repeatedly called + local tBreakInfo + put the long id of the target into tBreakInfo["target"] + put pHandler into tBreakInfo["handler"] + put pLine into tBreakInfo["line"] + if tBreakInfo is sLastBreakInfo then + pass traceBreak + else + put tBreakInfo into sLastBreakInfo + end if + local tTarget - put debuggerResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget + put __ResolveTarget(the long id of the target, line -2 of the executionContexts) into tTarget - if not debuggerEnabled() then + if not revDebuggerEnabled() then pass traceBreak end if - if debuggerTargetIsModal(tTarget) then - debuggerShowModalWarning + if "development" is in the environment and __ModalPresented() then + __ShowModalWarning pass traceBreak end if local tStack - put debuggerTargetStack(tTarget) into tStack - if not debuggerStackAllowed(tStack) then + put __TargetStack(tTarget) into tStack + if not __StackAllowed(tStack) then revDebuggerRun exit traceBreak end if - -- We can not flush moveStack and resizeStack messages so the IDE will lock up if we try and trace - local tContexts - put the executionContexts into tContexts - local tLine - repeat for each line tLine in tContexts - if item -2 of tLine is among the words of "moveStack resizeStack" then - pass traceBreak - end if - end repeat + if "development" is in the environment then + -- The IDE will lock up if we try and trace messages repeatedly coming from OS + local tContexts + put the executionContexts into tContexts + local tLine + repeat for each line tLine in tContexts + if item -2 of tLine is among the words of kUndebuggableHandlers then + pass traceBreak + end if + end repeat + end if local tContext put tTarget & comma & pHandler & comma & pLine into tContext - if debuggerEvaluateCondition(tTarget, pLine, tContext) then - set the traceStack to the short name of debuggerTargetStack(the long id of the target) - debuggerShowScript tTarget - debuggerUpdateScriptEditor tTarget, pHandler, pLine, "debug" + if __EvaluateCondition(tTarget, pLine, tContext) then + set the traceStack to the short name of __TargetStack(the long id of the target) + __UpdateScriptEditor tTarget, pHandler, pLine, "debug" else + delete variable sLastBreakInfo set the traceReturn to true end if end traceBreak @@ -2350,13 +2464,3 @@ end traceBreak on updateVariable pLine, pHandler, pValue traceBreak pHandler, pLine end updateVariable - - - - - - - - - - diff --git a/Toolset/libraries/revdeploylibrary.livecodescript b/Toolset/libraries/revdeploylibrary.livecodescript index 8b5d916665..5477473d6a 100644 --- a/Toolset/libraries/revdeploylibrary.livecodescript +++ b/Toolset/libraries/revdeploylibrary.livecodescript @@ -1,16 +1,16 @@ script "revDeployLibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +25,7 @@ end revUnloadLibrary -- history for which the stack is configured. This is then used to pick the last chosen -- target for this platform. -constant kSupportedPlatforms = "iOS Android" +constant kSupportedPlatforms = "iOS Android Desktop Emscripten" -- The mapping from deploy target to platform local sDeployTargetPlatforms @@ -74,7 +74,7 @@ command revIDEDeployAction put "Unknown deployment platform - " & tPlatform into tError end if - -- Report an error if one occured + -- Report an error if one occurred if tError is not empty then if revTestEnvironment() then return tError @@ -103,6 +103,10 @@ end revIDEDeployBuild function revIDEDeployListTargets local tTargets repeat for each word tPlatform in kSupportedPlatforms + if there is not a stack ("revDeployLibrary" & tPlatform) then + next repeat + end if + dispatch function "deployListTargets" to stack ("revDeployLibrary" & tPlatform) if it is "handled" and the result is not empty then put the result into tTargets[tPlatform] @@ -132,6 +136,19 @@ function revIDEDeployGetTarget if the cRevStandaloneSettings[tPlatform] of stack tStack then return sDeployTargets[tPlatform] end if + + if there is a stack ("revDeployLibrary" & tPlatform) then + dispatch function "deployListTargets" to stack ("revDeployLibrary" & tPlatform) + if it is "handled" and the result is not empty then + + local tTarget + repeat for each line tTarget in the result + if the cRevStandaloneSettings[tTarget] of stack tStack then + return sDeployTargets[tPlatform] + end if + end repeat + end if + end if end repeat end if @@ -147,13 +164,34 @@ function revIDEDeployIsPossible pPlatform local tStack put the mainStack of the topStack into tStack - return the cRevStandaloneSettings[pPlatform] of stack tStack + if the cRevStandaloneSettings[pPlatform] of stack tStack then + return true + end if + + if there is a stack ("revDeployLibrary" & pPlatform) then + dispatch function "deployListTargets" to stack ("revDeployLibrary" & pPlatform) + if it is "handled" and the result is not empty then + + local tTarget + repeat for each line tTarget in the result + if the cRevStandaloneSettings[tTarget] of stack tStack then + return true + end if + end repeat + end if + end if + + return false end revIDEDeployIsPossible -- This method is called on startup to initialize the deployment library. This includes -- attempting to auto-configure any SDKs and such if necessary. command revIDEDeployInitialize repeat for each word tPlatform in kSupportedPlatforms + if there is not a stack ("revDeployLibrary" & tPlatform) then + next repeat + end if + dispatch command "deployInitialize" to stack ("revDeployLibrary" & tPlatform) end repeat @@ -172,6 +210,10 @@ end revIDEDeployInitialize on revIDEDeployTargetsChanged put empty into sDeployTargetPlatforms repeat for each word tPlatform in kSupportedPlatforms + if there is not a stack ("revDeployLibrary" & tPlatform) then + next repeat + end if + dispatch function "deployListTargets" to stack ("revDeployLibrary" & tPlatform) if it is "handled" and the result is not empty then repeat for each line tTarget in the result @@ -231,10 +273,10 @@ function revIDEDeployIOSGetDeviceSDK pVersion return the result end revIDEDeployIOSGetDeviceSDK -function revIDEDeployIOSSanatizeSystemVersion - dispatch function "deploySanatizeSystemVersion" to stack "revDeployLibraryiOS" +function revIDEDeployIOSSanitizeSystemVersion + dispatch function "deploySanitizeSystemVersion" to stack "revDeployLibraryiOS" return the result -end revIDEDeployIOSSanatizeSystemVersion +end revIDEDeployIOSSanitizeSystemVersion //SN-2015-04-30: [[ Bug 15300 ]] Refactor functions used from revDeployLibraryIOS function revIDEDeployIOSGetInvalidityMessage piOSXcodePairs @@ -286,8 +328,11 @@ end revIDEDeployAndroidInitialize // SN-2015-05-13: [[ AndroidVersions ]] Make the available Android minimum versions // something changeable from a script-only stack function revIDEDeployAndroidGetVersionsList - dispatch function "deployGetVersionsList" to stack "revDeployLibraryAndroid" - return the result + local tMap + dispatch function "deployGetVersionsMap" to stack "revDeployLibraryAndroid" + put the result into tMap + combine tMap with return + return tMap end revIDEDeployAndroidGetVersionsList function revIDEDeployAndroidApiFromVersion pVersion @@ -296,8 +341,13 @@ function revIDEDeployAndroidApiFromVersion pVersion end revIDEDeployAndroidApiFromVersion function revIDEDeployAndroidGetAPIsList - dispatch function "deployGetAPIsList" to stack "revDeployLibraryAndroid" - return the result + local tMap,tAPIs + dispatch function "deployGetVersionsMap" to stack "revDeployLibraryAndroid" + put the result into tMap + put the keys of tMap into tAPIs + replace return with comma in tAPIs + sort items of tAPIs numeric ascending + return tAPIs end revIDEDeployAndroidGetAPIsList //////////////////////////////////////////////////////////////////////////////// diff --git a/Toolset/libraries/revfrontscriptlibrary.livecodescript b/Toolset/libraries/revfrontscriptlibrary.livecodescript index b8823512b9..0333ce5983 100644 --- a/Toolset/libraries/revfrontscriptlibrary.livecodescript +++ b/Toolset/libraries/revfrontscriptlibrary.livecodescript @@ -1,20 +1,19 @@ script "revfrontscriptlibrary" -on revLoadLibrary +on extensionInitialize if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is not me then - pass "revUnloadLibrary" + pass "extensionFinalize" end if remove the script of me from front -end revUnloadLibrary +end extensionFinalize -global gREVStackStatus global gREVSuppressMessages local lRefreshAOTimerID @@ -24,8 +23,9 @@ on saveStackRequest repeat for each line l in gREVMessageDispatch["revSaveStackRequest"] send "revSaveStackRequest" to this cd of stack l end repeat + + revIDESetUnedited the short name of revIDEStackOfObject(the long id of the target) - put empty into gREVStackStatus[revTargetStack(the target)] if "revReshapeLibrary" is in revInternal__ListLoadedLibraries() then select empty send "revSetMarkers true" to stack "revReshapeLibrary" @@ -234,26 +234,18 @@ end revSetActiveStacks # handler that deals with the opening of new stacks. on preOpenStack revIDEHandleNewStack the long id of the target - + local tScaleFactor put the cREVGeneral["scalefactor"] of this stack into tScaleFactor if tScaleFactor is a number and tScaleFactor is not 1 then set the scalefactor of this stack to tScaleFactor end if - - # CW-2015-10-05: [[ Bug 16079 ] Activate breakpoints now in case there are any in preOpenStack handlers - + local tTarget put the long id of the target into tTarget local tStack put revTargetStack(tTarget) into tStack - - if tTarget is not the long id of me then - if revDebuggerEnabled() then - revDebuggerActivateBreakpoints the long id of stack tStack - end if - end if if revIDEObjectIsOnIDEStack(tTarget) then # IM-2016-03-01: [[ Bug 16244 ]] IDE stacks should always hide invisible objects @@ -401,9 +393,14 @@ on closeStack put revTargetStack() into tStackName local tFileName + + local tIsBuildingStandalone + put (there is a stack "revStandaloneProgress" and \ + the mode of stack "revStandaloneProgress" > 0) into tIsBuildingStandalone + # OK-2008-08-05 : Bug 6562 - Bug where the user was being prompted to delete the home stack on startup, # caused by revIDEStack returning true/false instead of empty/non-empty. - if tAllClosed and not revIDEStack(the effective filename of stack tStackName) then + if not tIsBuildingStandalone and tAllClosed and not revIDEStackNameIsIDEStack(tStackName) then put the effective fileName of gREVTargetStack into tFileName # TH - 7689 improved wording of warning message @@ -432,10 +429,6 @@ on closeStack send "revCloseStack" to this cd of stack l end repeat - # LG-2008-04-22 - revIDEStartCenterCheckOnStackClose tStack - -------------------------------------------------- - if not gREVSuppressMessages or (gREVSuppressMessages and revOKTarget()) then pass closeStack end closeStack @@ -516,10 +509,6 @@ on mouseDown pWhich end switch end mouseDown -on revSetEdited pWhich - if the mode of stack "revSaving" is 0 then put "edited" into gREVStackStatus[pWhich] -end revSetEdited - on mouseUp pWhich local tTarget put the long id of the target into tTarget @@ -553,10 +542,12 @@ on mouseDoubleUp pButtonNo, pTarget end mouseDoubleUp on openField - local tTargetStack - put revTargetStack() into tTargetSTack - if the mode of stack tTargetStack is 1 and the mode of stack "revSaving" is 0 then put "edited" into gREVStackStatus[tTargetSTack] - if not gREVSuppressMessages or (gREVSuppressMessages and revOKTarget()) then pass openField + local tStack + put revIDEStackOfObject(the long id of the target) into tStack + if the mode of tStack is 1 then + revIDESetEdited the short name of tStack + end if + if not gREVSuppressMessages or (gREVSuppressMessages and revOKTarget()) then pass openField end openField on closeField diff --git a/Toolset/libraries/revgeometrylibrary.livecodescript b/Toolset/libraries/revgeometrylibrary.livecodescript index 85ddf714f1..8d61d1e91d 100644 --- a/Toolset/libraries/revgeometrylibrary.livecodescript +++ b/Toolset/libraries/revgeometrylibrary.livecodescript @@ -1,16 +1,16 @@ script "revgeometrylibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize # OK-2007-08-10 : Added variable declarations and quotes round literals to this script, also tidied up some code and fixed some bugs. @@ -825,6 +825,7 @@ on revCalculateGeometryDistances pWhichNumber if lOrigWidth is empty then put the width of this stack into lOrigWidth if lOrigHeight is empty then put the height of this stack into lOrigHeight repeat for each item tEdge in "left,right,top,bottom" + if revGetGeometry("scale" & tEdge) is not true then next repeat if revGetGeometry("scale" & tEdge & "Absolute") is false then --we need to calculate the distance as it stands as a percentage of card width or height get revCalculateScaleDistance(tEdge) @@ -844,6 +845,7 @@ on revCalculateGeometryDistances pWhichNumber end if end repeat repeat for each item tDimension in "h,v" + if revGetGeometry("move" & tDimension) is not true then next repeat if revGetGeometry("move" & tDimension & "Absolute") is false then --we need to calculate the distance as it stands as a percentage of card width or height get revCalculateMoveDistance(tDimension) @@ -1101,3 +1103,40 @@ function revUniqueIDToName pWhich end if end repeat end revUniqueIDToName + +# Clears any extra keys from the current profile's geometry settings. If no settings +# are found, removes the key for the profile. +command revClearExtraGeometrySettings + local tProfileName + put the cREVGeneral["profile"] of lGeometryObject into tProfileName + if tProfileName is empty or tProfileName is the cREVGeneral["masterName"] of lGeometryObject \ + then put "Master" into tProfileName + + local tGeometry, tKeys, tSettingsUsed + put the customProperties["cRevGeometry"] of lGeometryObject into tGeometry + put the keys of tGeometry into tKeys + put 0 into tSettingsUsed + + local tExtraKeys + repeat for each item tSetting in "moveH,moveV,scaleLeft,scaleRight,scaleTop,scaleBottom" + --check to see if each geometry setting is used + if tGeometry[tProfileName & "," & tSetting] then + add 1 to tSettingsUsed + next repeat + end if + --since the setting is not used, clear associated keys + filter tKeys with (tProfileName & "," & tSetting & "*") into tExtraKeys + repeat for each line tKey in tExtraKeys + delete variable tGeometry[tKey] + end repeat + end repeat + if tSettingsUsed is 0 then + --no geometry settings are used, clear everything else + delete variable tGeometry[tProfileName] + filter tKeys with (tProfileName & ",*") into tExtraKeys + repeat for each line tKey in tExtraKeys + delete variable tGeometry[tKey] + end repeat + end if + set the customProperties["cRevGeometry"] of lGeometryObject to tGeometry +end revClearExtraGeometrySettings diff --git a/Toolset/libraries/revidedeveloperextensionlibrary.livecodescript b/Toolset/libraries/revidedeveloperextensionlibrary.livecodescript index 1cd5941614..7fed70bcc4 100644 --- a/Toolset/libraries/revidedeveloperextensionlibrary.livecodescript +++ b/Toolset/libraries/revidedeveloperextensionlibrary.livecodescript @@ -1,19 +1,19 @@ script "revIDEDeveloperExtensionLibrary" local sExtensionDetailsA -private on __revIDEDeveloperExtensionSendWarning pWarning +private command __revIDEDeveloperExtensionSendWarning pWarning ideMessageSend "ideExtensionLog", "Warning:" && pWarning end __revIDEDeveloperExtensionSendWarning -private on __revIDEDeveloperExtensionSendError pError +private command __revIDEDeveloperExtensionSendError pError ideMessageSend "ideExtensionLog", "Error:" && pError end __revIDEDeveloperExtensionSendError -private on __revIDEDeveloperExtensionLog pLog +private command __revIDEDeveloperExtensionLog pLog ideMessageSend "ideExtensionLog", pLog end __revIDEDeveloperExtensionLog -private on __revIDEDeveloperCompilationError pError, pFile +private command __revIDEDeveloperCompilationError pError, pFile local tLineNo, tChar, tEndChar, tLine # Parse out the error details to provide more meaningful feedback repeat for each line tErrLine in pError @@ -30,35 +30,29 @@ private on __revIDEDeveloperCompilationError pError, pFile ideMessageSend "ideExtensionLog", "Error:" && pError end __revIDEDeveloperCompilationError -private function __revIDEDeveloperExtensionShouldRecompile pFolder, pFile +private function __revIDEDeveloperExtensionShouldRecompile pFolder, pFile, pType # To avoid excessive recompilation, test to see if the compiled module exists and is up to date. local tCompileInputs, tCompileOutputs, tNeedUpdate, tError put pFolder & slash & pFile into tCompileInputs[1] put pFolder & slash & "manifest.xml" into tCompileOutputs[1] - put pFolder & slash & "module.lcm" into tCompileOutputs[2] - + if pType is "lcb" then + put pFolder & slash & revIDEExtensionBytecodeFilename(true) into tCompileOutputs[2] + end if put revIDEIsFilesetStale(tCompileInputs, tCompileOutputs, false, tError) \ into tNeedUpdate - if tNeedUpdate is false then - -- read the file version string just to make sure - -- in the future we should add an --outputversion option to lc-compile to automate this - local tBytes - open file tCompileOutputs[2] for binary read - read from file tCompileOutputs[2] for 4 - -- Version 8.1 requires a LCB file version 1.0 - put not(byteToNum(byte 3 of it) is 1 and byteToNum(byte 4 of it) is 0) into tNeedUpdate - close file tCompileOutputs[2] + if pType is "lcb" and tNeedUpdate is false then + put not extensionCheckModuleVersion("", tCompileInputs[1]) into tNeedUpdate end if return tNeedUpdate is not false end __revIDEDeveloperExtensionShouldRecompile -private on __revIDEDeveloperExtensionRemoveFolder pFolder +private command __revIDEDeveloperExtensionRemoveFolder pFolder local tDeveloperExtensionsFolders - put revIDEGetPreference("cDeveloperExtensionsFolders") into tDeveloperExtensionsFolders + put revIDEDeveloperExtensionsFolders() into tDeveloperExtensionsFolders set the itemdelimiter to slash local tRootFolder @@ -68,13 +62,13 @@ private on __revIDEDeveloperExtensionRemoveFolder pFolder put lineOffset(tRootFolder, tDeveloperExtensionsFolders) into tLine if tLine is not 0 then delete line tLine of tDeveloperExtensionsFolders - revIDESetPreference "cDeveloperExtensionsFolders", tDeveloperExtensionsFolders + revIDEDeveloperExtensionsSetFolders tDeveloperExtensionsFolders end if end __revIDEDeveloperExtensionRemoveFolder -private on __revIDEDeveloperExtensionAddFolder pFolder +private command __revIDEDeveloperExtensionAddFolder pFolder local tDeveloperExtensionsFolders - put revIDEGetPreference("cDeveloperExtensionsFolders") into tDeveloperExtensionsFolders + put revIDEDeveloperExtensionsFolders() into tDeveloperExtensionsFolders set the itemdelimiter to slash local tRootFolder @@ -87,7 +81,7 @@ private on __revIDEDeveloperExtensionAddFolder pFolder end if end if - revIDESetPreference "cDeveloperExtensionsFolders", tDeveloperExtensionsFolders + revIDEDeveloperExtensionsSetFolders tDeveloperExtensionsFolders end __revIDEDeveloperExtensionAddFolder /* @@ -95,9 +89,9 @@ Summary: Returns an array of details of the extensions found in user folders Returns (array): { key: The path to the folder containing the extensions value (array): The array of details pertaining to the extension -{ key: "id" +{ key: "name" value: The extension ID -key: "name" +key: "title" value: The title of the extension key: "author" value: The author of the extension @@ -111,7 +105,6 @@ key: "retina_icon" value: The path to the retina icon of this extension } } */ function revIDEDeveloperExtensions - revIDEPushDefaultFolder local tExtensionDetailsA local tFolders @@ -123,7 +116,7 @@ function revIDEDeveloperExtensions # Look for extension examples in previously selected user folders. local tUserFolders - put revIDEGetPreference("cDeveloperExtensionsFolders") into tUserFolders + put revIDEDeveloperExtensionsActiveFolders() into tUserFolders repeat for each line tLine in tUserFolders if tLine is among the lines of tFolders then next repeat @@ -142,15 +135,14 @@ function revIDEDeveloperExtensions if tFolder is empty then next repeat end if - set the defaultfolder to tFolder - put the folders into tExtensionFolders + put folders(tFolder) into tExtensionFolders repeat for each line tExtensionFolder in tExtensionFolders if tExtensionFolder is ".." then next repeat end if local tExtensionA # On first run, don't compile. - put revIDEDeveloperExtensionNoCompile(tFolder & slash & tExtensionFolder) into tExtensionA + put revIDEDeveloperExtensionNoCompile(tFolder & slash & tExtensionFolder) into tExtensionA if tExtensionA is not empty then put tExtensionA into tExtensionDetailsA[tFolder & slash & tExtensionFolder] put true into tFolderHasModule @@ -161,212 +153,86 @@ function revIDEDeveloperExtensions end if end repeat - revIDEPopDefaultFolder - return tExtensionDetailsA end revIDEDeveloperExtensions -private function __revIDEDeveloperExtensionFetchModuleInFolder pFolder - revIDEPushDefaultFolder pFolder - - local tFiles - put the files into tFiles - filter tFiles with "*.lcb" - - revIDEPopDefaultFolder +private command __revIDEDeveloperExtensionFetchExtensionSourceInFolder pFolder, @rFile, @rSupportFiles, @rType + local tMainFile, tType, tSupportFiles + extensionFetchSourceFromFolder pFolder, tMainFile, tSupportFiles, tType - local tFile - # For now, if there are multiple lcb files in one folder, just use the first one. - if the number of lines of tFiles > 1 then - put replaceText(tFiles, return, ",") into tFiles - __revIDEDeveloperExtensionSendError "multiple lcb files in folder" && pFolder & ":" && tFiles - return empty - else - put tFiles into tFile + if the result is not empty then + __revIDEDeveloperExtensionSendError the result end if - return tFile -end __revIDEDeveloperExtensionFetchModuleInFolder + + put tMainFile into rFile + put tSupportFiles into rSupportFiles + put tType into rType +end __revIDEDeveloperExtensionFetchExtensionSourceInFolder function revIDEDeveloperExtensionNoCompile pFolder - local tFile - put __revIDEDeveloperExtensionFetchModuleInFolder(pFolder) into tFile - - if tFile is empty then - return empty - end if - - local tDataA - __revIDEDeveloperExtensionFetchMetadata (pFolder & slash & "manifest.xml"), tDataA - - if the result is not empty then - put tFile into tDataA["file"] - end if - return tDataA + return extensionFetchFolderDetails(pFolder, true) end revIDEDeveloperExtensionNoCompile +function revIDEDeveloperExtensionsFolders + return revIDEGetPreference("cDeveloperExtensionsFolders") +end revIDEDeveloperExtensionsFolders + +command revIDEDeveloperExtensionsSetFolders pFolders + revIDESetPreference "cDeveloperExtensionsFolders", pFolders +end revIDEDeveloperExtensionsSetFolders + +function revIDEDeveloperExtensionsActiveFolders + return revIDEGetPreference("cDeveloperExtensionsActiveFolders") +end revIDEDeveloperExtensionsActiveFolders + +command revIDEDeveloperExtensionsActiveFolders pFolders + revIDESetPreference "cDeveloperExtensionsActiveFolders", pFolders +end revIDEDeveloperExtensionsActiveFolders + function revIDEDeveloperExtension pFolder - local tFile - put __revIDEDeveloperExtensionFetchModuleInFolder(pFolder) into tFile - - if tFile is empty then - return empty - end if - - return __revIDEDeveloperExtensionDetailsFromFile(pFolder, tFile) + return __revIDEDeveloperExtensionCompileAndFetchDetails(pFolder, true) end revIDEDeveloperExtension -private function __revIDEDeveloperExtensionFetchFolderDetails pFolder, pFile - local tDetailsA - - # Check timestamps to see if API is out of date. - local tLastGenerated, tLastModified, tAPIFolder - if there is a folder (pFolder & slash & "docs" & slash & "api") then - put pFolder & slash & "docs" & slash & "api" into tAPIFolder - else - put pFolder into tAPIFolder - end if - revIDEExtensionUpdateAPI tAPIFolder, pFile - - local tAPI - if the result is empty then - # Check to see if we've already parsed to a docs library array - put sExtensionDetailsA[pFolder]["api"] into tAPI - end if - - if tAPI is empty then - local tData - put url ("binfile:" & pFolder & slash & "api.lcdoc") into tData - put textDecode(tData, "utf-8") into tData - - # If either we had to generate the new docs data or get it from the file, parse to a docs library array - local tLibraryA - dispatch function "revDocsParseDocTextToLibraryArray" to stack "revDocsParser" with tData, tDetailsA["name"], tDetailsA["author"] - put the result into tLibraryA - put tLibraryA["doc"] into tDetailsA["api"] - put tAPIFolder & slash & "api.lcdoc" into tDetailsA["api_file"] - end if - - if there is a file (pFolder & slash & "support" & slash & "icon.png") then - put (pFolder & slash & "support" & slash & "icon.png") into tDetailsA["icon"] - else if there is a file (pFolder & slash & "icon.png") then - put (pFolder & slash & "icon.png") into tDetailsA["icon"] - else - put empty into tDetailsA["icon"] - end if - - if there is a file (pFolder & slash & "support" & slash & "icon@extra-high.png") then - put (pFolder & slash & "support" & slash & "icon@extra-high.png") into tDetailsA["retina_icon"] - else if there is a file (pFolder & slash & "icon@extra-high.png") then - put (pFolder & slash & "icon@extra-high.png") into tDetailsA["retina_icon"] - else - put empty into tDetailsA["retina_icon"] - end if - - local tGuide, tGuideFile - if there is a file (pFolder & slash & "docs" & slash & "guide" & slash & "guide.md") then - put pFolder & slash & "docs" & slash & "guide" & slash & "guide.md" into tGuideFile - else if there is a file (pFolder & slash & "guide.md") then - put pFolder & slash & "guide.md" into tGuideFile - end if - - if tGuideFile is not empty then - put tGuideFile into tDetailsA["guide_file"] - put url ("binfile:" & tGuideFile) into tGuide - put textDecode(tGuide, "utf-8") into tGuide - end if - - put tGuide into tDetailsA["guide"] - - // AL-2015-02-23: [[ Bug 14552 ]] Find resource folder and return details - local tResourceFolder, tResources - put pFolder & slash & "resources" into tResourceFolder - if there is a folder tResourceFolder then - put __revIDEDeveloperExtensionListResourcesRecursive(tResourceFolder, "") into tResources - put tResources into tDetailsA["resources"] - end if - - # Default script - put revIDEExtensionFetchDefaultScript(pFolder, tDetailsA["id"], false) into tDetailsA["defaultscript"] - if tDetailsA["defaultscript"] is not empty then - put pFolder & "/support/defaultscript.livecodescript" into tDetailsA["defaultscript_file"] - end if - return tDetailsA -end __revIDEDeveloperExtensionFetchFolderDetails - -private function __revIDEDeveloperExtensionListResourcesRecursive pFolder, pPrefix - revIDEPushDefaultFolder pFolder - local tResources, tResource, tPrefix - if pPrefix is not empty then - put pPrefix & slash into tPrefix - end if - - # Add files to the list of resources - repeat for each line tResource in the files - if tResource begins with "." then next repeat - if tResources is empty then - put tPrefix & tResource into tResources - else - put return & tPrefix & tResource after tResources - end if - end repeat - - # Add folders to the list of resources - repeat for each line tResourceFolder in the folders - if tResourceFolder begins with "." then next repeat - local tRecursive - put __revIDEDeveloperExtensionListResourcesRecursive(pFolder & slash & tResourceFolder, tPrefix & tResourceFolder) into tRecursive - if tRecursive is not empty then - if tResources is empty then - put tRecursive into tResources - else - put return & tRecursive after tResources +private function __revIDEDeveloperExtensionCompileAndFetchDetails pFolder, \ + pForceReparseManifest + local tSource, tSupport, tType + extensionFetchSourceFromFolder pFolder, tSource, tSupport, tType + + revIDEExtensionUpdateAPI pFolder, tSource + + local tReparseManifest + if __revIDEDeveloperExtensionShouldRecompile(pFolder, tSource, tType) then + if tType is "lcb" then + # The compiled module or manifest is not up to date, so compile. + __revIDEDeveloperExtensionLog "Compiling module" && pFolder & slash & tSource + __revIDEDeveloperCompileModule pFolder, tSource, tSupport, pFolder + if the result is not empty then + # This may be better as a warning, and try to parse info direct from the file. + __revIDEDeveloperExtensionSendError the result + put false into tReparseManifest + else + put true into tReparseManifest end if + else + __revIDEDeveloperExtensionLog "Creating manifest for extension" && pFolder & slash & tSource + extensionGenerateManifestForLCSExtension "revDocsParser", pFolder + put true into tReparseManifest end if - end repeat - revIDEPopDefaultFolder - return tResources -end __revIDEDeveloperExtensionListResourcesRecursive - -private function __revIDEDeveloperExtensionDetailsFromFile pFolder, pFile - local tDetailsA - put __revIDEDeveloperExtensionFetchFolderDetails(pFolder, pFile) into tDetailsA - - put pFile into tDetailsA["file"] - if not __revIDEDeveloperExtensionShouldRecompile(pFolder, pFile) then - __revIDEDeveloperExtensionLog "Skipping recompilation of" && pFolder & slash & "module.lcm - module is up to date" - # The stored info is up to date. - if sExtensionDetailsA[pFolder] is not empty then - union tDetailsA with sExtensionDetailsA[pFolder] - put tDetailsA into sExtensionDetailsA[pFolder] - return sExtensionDetailsA[pFolder] - end if - # The compiled module and manifest are up to date, but we haven't fetched the information yet. else - # The compiled module or manifest is not up to date, so compile. - __revIDEDeveloperExtensionLog "Compiling module" && pFolder & slash & pFile - __revIDEDeveloperCompileModule pFolder & slash & pFile, pFolder - - if the result is not empty then - # This may be better as a warning, and try to parse info direct from the file. - __revIDEDeveloperExtensionSendError the result - return tDetailsA - end if + __revIDEDeveloperExtensionLog "Skipping rebuild of" && \ + pFolder & slash & tSource && "- extension is up to date" + put false into tReparseManifest end if - __revIDEDeveloperExtensionLog "Fetching metadata from" && pFolder & slash & "manifest.xml" - local tMetadataA - __revIDEDeveloperExtensionFetchMetadata (pFolder & slash & "manifest.xml"), tMetadataA - union tDetailsA with tMetadataA - - if the result is not empty then - __revIDEDeveloperExtensionSendError the result - return tDetailsA - end if + put tReparseManifest or pForceReparseManifest into \ + tReparseManifest + local tDetailsA + put extensionFetchFolderDetails(pFolder, tReparseManifest) into tDetailsA + union tDetailsA with sExtensionDetailsA[pFolder] put tDetailsA into sExtensionDetailsA[pFolder] return sExtensionDetailsA[pFolder] - -end __revIDEDeveloperExtensionDetailsFromFile +end __revIDEDeveloperExtensionCompileAndFetchDetails on revIDEDeveloperExtensionAddResourceFile pExtensionFolder, pResourcePath, pType if there is not a file pResourcePath then @@ -417,7 +283,16 @@ on revIDEDeveloperExtensionAddResourceFolder pExtensionFolder, pResourceFolder end if end revIDEDeveloperExtensionAddResourceFolder -on revIDEDeveloperExtensionTest pPath +local sLoadedExtension +function revIDEDeveloperExtensionCurrentlyTesting + return sLoadedExtension is not empty +end revIDEDeveloperExtensionCurrentlyTesting + +command revIDEDeveloperExtensionStopTesting + __ClearTestExtension +end revIDEDeveloperExtensionStopTesting + +command revIDEDeveloperExtensionTest pPath local tDetailsA put revIDEDeveloperExtension(pPath) into tDetailsA @@ -427,21 +302,34 @@ on revIDEDeveloperExtensionTest pPath end if # AL-2015-07-15: [[ Bug ]] If the details of the extension doesn't include an ID, then the compile failed - if tDetailsA["id"] is empty then + if tDetailsA["name"] is empty then __revIDEDeveloperExtensionSendError "Could not compile module" && pPath exit revIDEDeveloperExtensionTest end if - if there is not a file (pPath & slash & "module.lcm") then + if tDetailsA["source_type"] is "lcb" \ + and there is not a file \ + (pPath & slash & revIDEExtensionBytecodeFilename(true)) then __revIDEDeveloperExtensionSendError "No compiled module in" && pPath exit revIDEDeveloperExtensionTest end if - __revIDEDeveloperExtensionLog "Launching in Test Window" + __ClearTestExtension - __revIDEDeveloperExtensionLaunchTestStack pPath, tDetailsA + revIDEExtensionLoad tDetailsA["source_type"], tDetailsA["name"], pPath, \ + tDetailsA["version"], "installed", "", false, tDetailsA["file"] + + local tResult + put the result into tResult + if tResult is not empty then + __revIDEDeveloperExtensionSendError tResult + exit revIDEDeveloperExtensionTest + end if + + __LaunchTestExtension pPath, tDetailsA end revIDEDeveloperExtensionTest +local sRectsA private function __testStackRects local tDataA if there is a stack "LiveCode Extension Test Window" then @@ -473,15 +361,8 @@ private function __testStackScript return tScript end __testStackScript -private on __revIDEDeveloperExtensionLaunchTestStack pPath, pDetailsA - local tRectsA - put __testStackRects() into tRectsA - - if there is a stack "LiveCode Extension Test Window" then - revIDEDeveloperExtensionClearTestStack - end if - - revIDEDeveloperExtensionCreateTestStack pPath, tRectsA, pDetailsA +private command __revIDEDeveloperExtensionLaunchTestStack pPath, pDetailsA + revIDEDeveloperExtensionCreateTestStack pPath, sRectsA, pDetailsA end __revIDEDeveloperExtensionLaunchTestStack on revIDEDeveloperExtensionClearTestStack @@ -493,15 +374,7 @@ on revIDEDeveloperExtensionCreateTestStack pPath, pRectsA, pDetailsA end revIDEDeveloperExtensionCreateTestStack on __revIDEDeveloperExtensionDoCreateTestStack pPath, tRectsA, pDetailsA - revIDEExtensionLoad pDetailsA["id"], pPath, pDetailsA["version"] - - local tResult - put the result into tResult - if tResult is not empty then - __revIDEDeveloperExtensionSendError tResult - exit __revIDEDeveloperExtensionDoCreateTestStack - end if - + __revIDEDeveloperExtensionLog "Launching in Test Window" if there is a stack (pPath & slash & "test.livecode") then go stack (pPath & slash & "test.livecode") else @@ -510,19 +383,20 @@ on __revIDEDeveloperExtensionDoCreateTestStack pPath, tRectsA, pDetailsA create stack "LiveCode Extension Test Window" if tRectsA["rect"] is not empty then set the rect of stack "LiveCode Extension Test Window" to tRectsA["rect"] - else + else if tRectsA["loc"] is not empty then set the loc of stack "LiveCode Extension Test Window" to tRectsA["loc"] end if set the destroyStack of stack "LiveCode Extension Test Window" to true - set the title of it to pDetailsA["name"] + set the title of it to pDetailsA["title"] set the script of it to __testStackScript() go stack "LiveCode Extension Test Window" - create widget as pDetailsA["id"] + revIDECreateObject pDetailsA["name"], the long id of the defaultStack, \ + (the width of the defaultStack / 2) & comma & (the height of the defaultStack / 2) unlock messages end if if there is not a widget 1 of stack "LiveCode Extension Test Window" then - __revIDEDeveloperExtensionSendError "failed to create widget" && pDetailsA["id"] + __revIDEDeveloperExtensionSendError "failed to create widget" && pDetailsA["name"] __revIDEDeveloperExtensionDoClearTestStack exit __revIDEDeveloperExtensionDoCreateTestStack end if @@ -531,21 +405,44 @@ on __revIDEDeveloperExtensionDoCreateTestStack pPath, tRectsA, pDetailsA set the rect of widget 1 of stack "LiveCode Extension Test Window" to tRectsA["wrect"] end if - set the cCurExtension of stack "LiveCode Extension Test Window" to pDetailsA["id"] unlock screen end __revIDEDeveloperExtensionDoCreateTestStack +private command __LaunchTestExtension pPath, pDetailsA + -- Only launch a test window if a widget + if pDetailsA["type"] is "widget" then + __revIDEDeveloperExtensionLaunchTestStack pPath, pDetailsA + else + __revIDEDeveloperExtensionLog "Loaded library" && sLoadedExtension + end if + put pDetailsA["name"] into sLoadedExtension + ideMessageSend "ideExtensionStatusChanged" +end __LaunchTestExtension + +private command __ClearTestExtension + if there is a stack "LiveCode Extension Test Window" then + put __testStackRects() into sRectsA + __revIDEDeveloperExtensionDoClearTestStack + else + __UnloadTestExtension + end if + ideMessageSend "ideExtensionStatusChanged" +end __ClearTestExtension + +private command __UnloadTestExtension + if sLoadedExtension is not empty then + __revIDEDeveloperExtensionUnload sLoadedExtension + __revIDEDeveloperExtensionLog "Unloading" && sLoadedExtension + put empty into sLoadedExtension + end if +end __UnloadTestExtension + on __revIDEDeveloperExtensionDoClearTestStack repeat while there is a widget 1 of stack "LiveCode Extension Test Window" delete widget 1 of stack "LiveCode Extension Test Window" end repeat - local tExtension - put the cCurExtension of stack "LiveCode Extension Test Window" into tExtension delete stack "LiveCode Extension Test Window" - if tExtension is not empty then - __revIDEDeveloperExtensionUnload tExtension - __revIDEDeveloperExtensionLog "Unloading..." - end if + __UnloadTestExtension end __revIDEDeveloperExtensionDoClearTestStack local sInstalledExtension @@ -556,58 +453,88 @@ on __revIDEDeveloperExtensionUnload pExtension end if end __revIDEDeveloperExtensionUnload -on revIDEDeveloperExtensionInstall pFolder +command revIDEDeveloperExtensionInstall pFolder local tPackage __revIDEDeveloperExtensionBuildPackage pFolder, "", tPackage - revIDEInstallExtension tPackage - put pFolder & slash & "module.lcm" into sInstalledExtension + if the result is not empty then + exit revIDEDeveloperExtensionInstall + end if + revIDEExtensionInstall tPackage + put pFolder & slash & revIDEExtensionBytecodeFilename(true) \ + into sInstalledExtension end revIDEDeveloperExtensionInstall -on revIDEDeveloperExtensionUninstall pPath +command revIDEDeveloperExtensionUninstall pPath local tDetailsA put revIDEDeveloperExtension(pPath) into tDetailsA - if tDetailsA["id"] is empty then + if tDetailsA["name"] is empty then __revIDEDeveloperExtensionSendError "Extension id lost from" && pPath & ": cannot uninstall" exit revIDEDeveloperExtensionUninstall end if - revIDEUninstallExtension tDetailsA["id"] + revIDEExtensionUninstall tDetailsA["name"] end revIDEDeveloperExtensionUninstall on revIDEDeveloperExtensionEditScript pFolder - local tFile - put pFolder & slash & __revIDEDeveloperExtensionFetchModuleInFolder(pFolder) into tFile - + local tFile, tSupportFiles, tType + __revIDEDeveloperExtensionFetchExtensionSourceInFolder pFolder, tFile, tSupportFiles, tType + if tType is "lcb" then + __revIDEDeveloperExtensionEditLCBScript pFolder & slash & tFile + repeat for each line tLine in tSupportFiles + __revIDEDeveloperExtensionEditLCBScript pFolder & slash & tLine + end repeat + else + if there is a stack (pFolder & slash & tFile) then + edit script of stack (pFolder & slash & tFile) + end if + repeat for each line tLine in tSupportFiles + if there is a stack (pFolder & slash & tLine) then + edit script of stack (pFolder & slash & tLine) + end if + end repeat + end if +end revIDEDeveloperExtensionEditScript + +private command __revIDEDeveloperExtensionEditLCBScript pFile # AL-2015-04-01: [[ Bug 15130 ]] First check to see if there is an existing association - launch document tFile - if the result is not empty then + local tResult + launch document pFile + put the result into tResult + if tResult is not empty then # AL-2015-04-01: [[ Bug 15130 ]] Check to see if the text editor preference is set local tEditor put revIDEGetPreference("LCB_textEditor") into tEditor if tEditor is not empty then - launch tFile with tEditor + launch pFile with tEditor + put the result into tResult end if end if - if the result is "no association" or the result is "request failed" then + if tResult is "no association" or tResult is "request failed" \ + or tResult is "no such program" then answer file "Select text editor..." - if it is not empty then - launch tFile with it + put it into tEditor + if tEditor is not empty then + launch pFile with tEditor + put the result into tResult + if tResult is empty then + # AL-2015-04-01: [[ Bug 15130 ]] If the new text editor launch was successful, set the preference + revIDESetPreference "LCB_textEditor", tEditor + end if end if end if - if the result is not empty then - __revIDEDeveloperExtensionSendError "Could not open" && tFile & ":" && the result - else if it is not empty then - # AL-2015-04-01: [[ Bug 15130 ]] If the new text editor launch was successful, set the preference - revIDESetPreference "LCB_textEditor", it + if tResult is not empty and tResult is not tEditor then + __revIDEDeveloperExtensionSendError "Could not open" && pFile & ":" && tResult end if -end revIDEDeveloperExtensionEditScript +end __revIDEDeveloperExtensionEditLCBScript on revIDEDeveloperExtensionOpen pFolder - if __revIDEDeveloperExtensionFetchModuleInFolder(pFolder) is empty then + local tFile, tType, tSupportFiles + __revIDEDeveloperExtensionFetchExtensionSourceInFolder pFolder, tFile, tSupportFiles, tType + if tFile is empty then exit revIDEDeveloperExtensionOpen end if @@ -637,152 +564,42 @@ on revIDEDeveloperExtensionNew pDataA put merge(tTemplate) into url("file:" & pDataA["path"] & slash & pDataA["name"] & ".lcb") end revIDEDeveloperExtensionNew -private on __revIDEDeveloperExtensionFetchMetadata pManifestPath, @rDataA - local tDataA - - local tManifestContents, tId - put url ("file:" & pManifestPath) into tManifestContents - put revXMLCreateTree(tManifestContents,true,true,false) into tId - - if tId begins with "xmlerr" then - return "Error: invalid xml in manifest" - end if - - local tTargetType - put textDecode(revXMLNodeContents(tId, "/package/type"), "utf-8") into tTargetType - - if tTargetType begins with "xmlerr" then - __revIDEDeveloperExtensionSendError "couldn't retrieve extension type from manifest" && pManifestPath - exit __revIDEDeveloperExtensionFetchMetadata - end if - put tTargetType into tDataA["type"] - - local tTargetName - put textDecode(revXMLNodeContents(tId, "/package/name"), "utf-8") into tTargetName - - if tTargetName begins with "xmlerr" then - __revIDEDeveloperExtensionSendError "couldn't retrieve extension name from manifest" && pManifestPath - exit __revIDEDeveloperExtensionFetchMetadata - end if - - set the itemdelimiter to "." - if not tTargetName begins with "community.livecode" or the number of items of tTargetName < 4 then - __revIDEDeveloperExtensionSendWarning "extension name has invalid identifier (" & tTargetName & ") - must be community.livecode.." - end if - put tTargetName into tDataA["id"] - - # If we have a library, we don't require various packaged elements - if tTargetType is "widget" then - local tTargetTitle - put textDecode(revXMLNodeContents(tId, "/package/title"), "utf-8") into tTargetTitle - - if tTargetTitle is empty or tTargetTitle begins with "xmlerr" then - __revIDEDeveloperExtensionSendWarning "couldn't retrieve title from" && tTargetName && "manifest - ensure .lcb file has 'metadata title is " & quote & "" & quote & "'" - put empty into tTargetTitle - end if - put tTargetTitle into tDataA["name"] - end if - - local tTargetVersion - put textDecode(revXMLNodeContents(tId, "/package/version"), "utf-8") into tTargetVersion - - if tTargetVersion is empty or tTargetVersion begins with "xmlerr" then - __revIDEDeveloperExtensionSendWarning "couldn't retrieve version from" && tTargetName && "manifest - ensure .lcb file has 'metadata version is " & quote & "<version>" & quote & "'" - put empty into tTargetVersion - end if - - if the number of items of tTargetVersion is not 3 then - __revIDEDeveloperExtensionSendWarning "extension name has invalid identifier (" & tTargetVersion & ") - must be <major>.<minor>.<revision>" - end if - put tTargetVersion into tDataA["version"] - - local tTargetAuthor - put textDecode(revXMLNodeContents(tId, "/package/author"), "utf-8") into tTargetAuthor - - if tTargetAuthor is empty or tTargetAuthor begins with "xmlerr" then - __revIDEDeveloperExtensionSendWarning "couldn't retrieve author from" && tTargetName && "manifest - ensure .lcb file has 'metadata author is " & quote & "<author_name>" & quote & "'" - put empty into tTargetAuthor - end if - put tTargetAuthor into tDataA["author"] - - put tDataA into rDataA - return empty -end __revIDEDeveloperExtensionFetchMetadata -private function shellFormat pArg, pSwitch - local tOutput - - if pSwitch is not empty then - put "--" & pSwitch & " " into tOutput - end if +private function __fetchMetadatum pXmlId, pKey + local tNode - return tOutput & quote & pArg & quote & " " -end shellFormat - -private function __revIDEDDeveloperExtensionResourcePath - if revEnvironmentIsInstalled() is false then - return revEnvironmentBinariesPath() + if pKey is among the items of "name,type,title,author,description,version,platforms,os" then + -- Some metadata are placed into specifically-named top-level XML + -- elements in the manifest. This list must be kept up-to-date + -- with the list of special-cased metadatum keys listed in the + -- "GenerateManifestDefinitions" action in lc-compile's + -- "generate.g" + put "/package/" & pKey into tNode + else - return revIDESpecialFolderPath("Toolchain") + -- Find a corresponding node for a generic metadatum + put revXmlMatchingNode(pXmlId, "/package", "metadata", "key", pKey, 1) into tNode + end if -end __revIDEDDeveloperExtensionResourcePath - -private function __revIDEDeveloperExtensionCompilerPath - # The actual compile command - if the platform is "win32" then - return __revIDEDDeveloperExtensionResourcePath() & slash & "lc-compile.exe" - else - return __revIDEDDeveloperExtensionResourcePath() & slash & "lc-compile" + + if tNode is empty or tNode begins with "xmlerr" then + return tNode end if -end __revIDEDeveloperExtensionCompilerPath + return textDecode(revXMLNodeContents(pXmlId, tNode), "utf-8") +end __fetchMetadatum -private command __revIDEDeveloperCompileModule pFile, pTargetFolder - # The manifest is currently always generated from the source - if there is a file (pTargetFolder & slash & "manifest.xml") then - delete file (pTargetFolder & slash & "manifest.xml") - end if +private command __revIDEDeveloperCompileModule pFolder, pFile, pSupportFiles, pTargetFolder + revIDEExtensionCompile pFolder, pFile, pSupportFiles, pTargetFolder - # Build the shell command - local tShellCommand - put shellFormat(__revIDEDeveloperExtensionCompilerPath()) into tShellCommand - - # The folder to put the .lci file - put shellFormat(pTargetFolder, "modulepath") after tShellCommand - - # The built-in module path - put shellFormat(__revIDEDDeveloperExtensionResourcePath() & slash & "modules/lci", "modulepath") after tShellCommand - - # Installed module path - put shellFormat(revIDESpecialFolderPath("user extensions") & slash & "interface", "modulepath") after tShellCommand - - # The manifest target - put shellFormat(pTargetFolder & slash & "manifest.xml", "manifest") after tShellCommand - - # The output - put shellFormat(pTargetFolder & slash & "module.lcm", "output") after tShellCommand - - # The target .lcb file - put shellFormat(pFile) after tShellCommand - - # AL-2015-06-15: [[ Bug 15001 ]] Don't show console window when executing shell command - local tHideConsoleWindows - put the hideConsoleWindows into tHideConsoleWindows - set the hideConsoleWindows to true - - local tShellOutput, tShellResult - put shell(tShellCommand) into tShellOutput - put the result into tShellResult - - set the hideConsoleWindows to tHideConsoleWindows - - if tShellResult is not 0 then - __revIDEDeveloperCompilationError tShellOutput + if the result is not empty then + __revIDEDeveloperCompilationError the result return "failed to compile module" end if - __revIDEDeveloperExtensionLog tShellOutput + __revIDEDeveloperExtensionLog it - if there is not a file (pTargetFolder & slash & "module.lcm") then + if there is not a file \ + (pTargetFolder & slash & revIDEExtensionBytecodeFilename(true)) then return "failed to compile module" end if @@ -802,240 +619,24 @@ on revIDEDeveloperExtensionBuildPackage pFolder end if end revIDEDeveloperExtensionBuildPackage -private on __revIDEDeveloperExtensionBuildPackage pFolder, pTargetFolder, @rBuiltLocation - local tDetailsA - put revIDEDeveloperExtension(pFolder) into tDetailsA - - local tFullPath - put pFolder & slash & tDetailsA["file"] into tFullPath - - if there is not a file tFullPath then - return "Error: missing file" && tFullPath - end if - - local tTargetFolder - if pTargetFolder is empty then - put pFolder into tTargetFolder - else - put pTargetFolder into tTargetFolder - end if - - local tTargetName - if tDetailsA["id"] is empty then - __revIDEDeveloperExtensionSendError "no id found in " && tFullpath - return "no id found" - end if - put tDetailsA["id"] into tTargetName - - local tTargetVersion - if tDetailsA["version"] is empty then - __revIDEDeveloperExtensionSendError "no version found in " && tFullpath - return "no version found" - end if - put tDetailsA["version"] into tTargetVersion - - local tArchive - put tTargetFolder & slash & tTargetName & "." & tTargetVersion & ".lce" into tArchive - - if there is a file tArchive then - delete file tArchive - end if - revZipOpenArchive tArchive, "write" - - if the result begins with "ziperr" then - __revIDEDeveloperExtensionSendError "couldn't open zip archive" && tArchive - return "couldn't open zip archive" && tArchive - end if - - local tError - - # AL-2015-05-22: [[ Bug 14919 ]] Use default widget and library icons if none are provided - local tIcon - if tError is empty then - put tDetailsA["icon"] into tIcon - if tIcon is empty or there is not a file tIcon then - answer file "Select icon file" with type "|png|" - if it is empty then - __revIDEDeveloperExtensionLog "Using default icon" - get revIDEDefaultExtensionIcon(tDetailsA["type"], false) - end if - put it into tIcon - end if - end if - - local tRetinaIcon - if tError is empty then - put tDetailsA["retina_icon"] into tRetinaIcon - if tRetinaIcon is empty or there is not a file tRetinaIcon then - answer file "Select retina icon file" with type "|png|" - if it is empty then - __revIDEDeveloperExtensionLog "Using default retina icon" - get revIDEDefaultExtensionIcon(tDetailsA["type"], true) - end if - put it into tRetinaIcon - end if - end if - - local tGuide - put tDetailsA["guide_file"] into tGuide - if there is not a file tGuide then - put empty into tGuide - end if - - local tDocs - put tDetailsA["api_file"] into tDocs - if there is not a file tDocs then - put empty into tDocs - end if - - local tResources - put (pFolder & slash & "resources") into tResources - if there is not a folder tResources then - put empty into tResources - end if - - # AL-2015-03-18: [[ Bug 15007 ]] Include interface file if present - local tInterfaceFile - if there is a file (pFolder & slash & tTargetName & ".lci") then - put pFolder & slash & tTargetName & ".lci" into tInterfaceFile - end if - - local tDefaultScript - put tDetailsA["defaultscript_file"] into tDefaultScript - if there is not a file tDefaultScript then - put empty into tDefaultScript - end if - - if tError is empty then - put __revIDEDeveloperExtensionAddSpecifiedFilesToPackage(tFullPath, pFolder, tArchive, pFolder & slash & "module.lcm", tIcon, tRetinaIcon, tGuide, tDocs, tResources, tInterfaceFile, tDefaultScript) into tError - end if - - revZipCloseArchive tArchive - - if tError is empty then - if the result begins with "ziperr" then - put "Error: couldn't close zip archive" into tError - end if - end if - - if tError is not empty then - __revIDEDeveloperExtensionSendError tError - return tError +private command __revIDEDeveloperExtensionBuildPackage pFolder, pTargetFolder, @rBuiltLocation + extensionPackage pFolder, "", pTargetFolder, false + if the result is not empty then + __revIDEDeveloperExtensionSendError the result + return the result end if - put tArchive into rBuiltLocation + put it into rBuiltLocation return empty end __revIDEDeveloperExtensionBuildPackage -private function __revIDEDeveloperExtensionAddSpecifiedFilesToPackage pSource, pFolder, pArchive, pModule, pIcon, pRetinaIcon, pGuide, pDocs, pResourcesFolder, pInterfaceFile, pDefaultScript - local tError - - set the itemdelimiter to slash - # Add source into package - revZipAddItemWithFile pArchive, item -1 of pSource, pSource - - if the result begins with "ziperr" then - put "couldn't add source" into tError - end if - - # Add module into package - revZipAddItemWithFile pArchive, "module.lcm", pModule - - if the result begins with "ziperr" then - put "couldn't add module" into tError - end if - - # Add manifest into package - if tError is empty then - revZipAddItemWithFile pArchive, "manifest.xml", pFolder & slash & "manifest.xml" - - if the result begins with "ziperr" then - put "couldn't add manifest" into tError - end if - end if - - # Add user guide - if tError is empty then - // AL-2015-03-03: [[ Bug 14781 ]] If there is no guide, warn and don't try to add a file - if pGuide is empty then - __revIDEDeveloperExtensionSendWarning "no user guide found" - else - revZipAddItemWithFile pArchive, "docs/guide/guide.md", pGuide - end if - if the result begins with "ziperr" then - put "couldn't add guide" into tError - end if - end if - - # Add icons - if tError is empty then - revZipAddItemWithFile pArchive, "support/icon.png", pIcon - - if the result begins with "ziperr" then - put "couldn't add icon.png" into tError - end if - end if - - if tError is empty then - revZipAddItemWithFile pArchive, "support/icon@extra-high.png", pRetinaIcon - - if the result begins with "ziperr" then - put "couldn't add icon@extra-high.png" into tError - end if - end if - - # Add docs - if tError is empty then - if pDocs is empty then - __revIDEDeveloperExtensionSendWarning "docs formatting error. Docs may be empty" - else - revZipAddItemWithFile pArchive, "docs/api/api.lcdoc", pDocs - end if - if the result begins with "ziperr" then - put "couldn't add doc " & pDocs into tError - end if - end if - - # Add resources - if tError is empty and pResourcesFolder is not empty then - local tResources - put __revIDEDeveloperExtensionListResourcesRecursive(pResourcesFolder, "") into tResources - repeat for each line tLine in tResources - revZipAddItemWithFile pArchive, "resources/" & tLine, pResourcesFolder & slash & tLine - - if the result begins with "ziperr" then - __revIDEDeveloperExtensionSendWarning "couldn't add resource" && pResourcesFolder & slash & tLine - end if - end repeat - end if - - # AL-2015-03-18: [[ Bug 15007 ]] Include interface file if present - if tError is empty and pInterfaceFile is not empty then - revZipAddItemWithFile pArchive, item -1 of pInterfaceFile, pInterfaceFile - - if the result begins with "ziperr" then - __revIDEDeveloperExtensionSendWarning "couldn't add interface file" && pInterfaceFile - end if - end if - - # Add default script - if tError is empty and pDefaultScript is not empty then - revZipAddItemWithFile pArchive, "support/defaultscript.livecodescript", pDefaultScript - - if the result begins with "ziperr" then - __revIDEDeveloperExtensionSendWarning "couldn't add default script" && pDefaultScript - end if - end if - - return tError -end __revIDEDeveloperExtensionAddSpecifiedFilesToPackage - on revIDEDeveloperExtensionEditDefaultScript pFolder - local tDefaultScript, tTargetStack - put pFolder & "/support/defaultscript.livecodescript" into tDefaultScript + local tSupportFolder, tDefaultScript, tTargetStack + put pFolder & "/support" into tSupportFolder + put tSupportFolder & "/defaultscript.livecodescript" into tDefaultScript local tExpectedName - put sExtensionDetailsA[pFolder]["id"] & ".__DefaultScript" into tExpectedName + put sExtensionDetailsA[pFolder]["name"] & ".__DefaultScript" into tExpectedName if there is a file tDefaultScript then try # If we have a valid stack, open it and edit the script @@ -1059,6 +660,10 @@ on revIDEDeveloperExtensionEditDefaultScript pFolder revIDENewScriptOnlyStack tExpectedName if the result is empty then put it into tTargetStack + if there is not a folder tSupportFolder then + create folder tSupportFolder + end if + save stack tExpectedName as tDefaultScript else answer error the result end if @@ -1067,5 +672,5 @@ on revIDEDeveloperExtensionEditDefaultScript pFolder end revIDEDeveloperExtensionEditDefaultScript function revIDEDeveloperExtensionFetchDefaultScript pFolder - return revIDEExtensionFetchDefaultScript(pFolder, sExtensionDetailsA[pFolder]["id"], false) + return revIDEExtensionFetchDefaultScript(pFolder, sExtensionDetailsA[pFolder]["name"], false) end revIDEDeveloperExtensionFetchDefaultScript diff --git a/Toolset/libraries/revidedocumentationlibrary.livecodescript b/Toolset/libraries/revidedocumentationlibrary.livecodescript index 2b7d6f8f9f..560ff34cb9 100644 --- a/Toolset/libraries/revidedocumentationlibrary.livecodescript +++ b/Toolset/libraries/revidedocumentationlibrary.livecodescript @@ -1,15 +1,15 @@ script "revIDEDocumentationLibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove script of me from back end if -end revUnloadLibrary +end extensionFinalize private on ideDocsEnsureDatabase pLocation if there is not a file (pLocation & slash & "api.sqlite") then @@ -18,96 +18,109 @@ private on ideDocsEnsureDatabase pLocation end if end ideDocsEnsureDatabase -local sConnection -on ideDocsInitialize - if sConnection is not empty then - exit ideDocsInitialize +local sConnectionsA +command ideDocsInitialize pDistributed + If pDistributed is true and revEnvironmentIsInstalled() then + ideThrow "can't write to installed IDE" + return empty end if - local tCopyLocation - put revIDESpecialFolderPath("documentation cache") into tCopyLocation - ideDocsEnsureDatabase tCopyLocation + local tConnection, tLocation, tKey + if pDistributed is true then + put "ide" into tKey + put revIDESpecialFolderPath("API") into tLocation + else + put "cache" into tKey + put revIDESpecialFolderPath("documentation cache") into tLocation + ideDocsEnsureDatabase tLocation + end if + put sConnectionsA[tKey] into tConnection - local tConnection - dispatch "revDocsOpenAPIDatabase" to stack "revDocsParser" with revIDESpecialFolderPath("documentation cache") + if tConnection is among the items of revOpenDatabases() then + return tConnection + end if + + dispatch "revDocsOpenAPIDatabase" to stack "revDocsParser" with tLocation put the result into tConnection if tConnection is not a number then ideThrow "unable to open database", tConnection end if - put tConnection into sConnection - return empty + put tConnection into sConnectionsA[tKey] + return tConnection end ideDocsInitialize -private function __fetchDocsData pEntryName, pLibraryName, pType +private function __fetchDocsData pAPI, pLibraryName, pEntryName, pType # Ensure we have a connection + local tConnection try ideDocsInitialize + put the result into tConnection catch tError return tError end try - # Find the library id - local tSQL, tLibraryID, tResult - if pLibraryName is not empty then - # Get the library's escaped name - local tLibName - dispatch function "revDocsModifyForUrl" to stack "revDocsParser" with pLibraryName - put the result into tLibName - - put "SELECT library_id FROM libraries WHERE library_name = :1" into tSQL - put revDataFromQuery(comma, return, sConnection, tSQL, "tLibName") into tLibraryID + # Find the api id + local tSQL, tAPIID, tResult + if pAPI is not empty then + put "SELECT api_id FROM apis WHERE api_name = :1" into tSQL + put revDataFromQuery(comma, return, tConnection, tSQL, "pAPI") into tAPIID put the result into tResult if tResult is not a number then - return "error finding library id for" && pLibraryName & return & tResult + return "error finding api id for" && pAPI & return & tResult end if end if - local tRecordSet, tData, tDataSet, tParamCount + local tRecordSet, tDataSet, tParamCount - put "SELECT entry_data from dictionary_data" into tSQL + put "SELECT entry_data, library_name FROM dictionary_data" into tSQL local tWhere + if pAPI is not empty then + put "api_id" into tWhere[1] + end if + if pLibraryName is not empty then + put "library_name" into tWhere[2] + end if if pEntryName is not empty then - put "entry_name" into tWhere[1] + put "entry_name" into tWhere[3] end if if pType is not empty then - put "entry_type" into tWhere[2] - end if - if pLibraryName is not empty then - put "library_id" into tWhere[3] + put "entry_type" into tWhere[4] end if local tWhereString - repeat with x = 1 to 3 + repeat with x = 1 to 4 if tWhere[x] is not empty then if tWhereString is empty then put " WHERE" && tWhere[x] & "=:" & x into tWhereString else put " AND" && tWhere[x] & "=:" & x after tWhereString end if + put " COLLATE NOCASE" after tWhereString end if end repeat put tWhereString after tSQL - - local tEntryName - put tolower(pEntryName) into tEntryName - + # Execute the query, keeping the record set ID. - put revQueryDatabase(sConnection, tSql, "tEntryName", "pType", "tLibraryID") into tRecordSet + put revQueryDatabase(tConnection, tSql, "tAPIID", "pLibraryName", "pEntryName", "pType") into tRecordSet if the result is not a number then - return "entry" && tEntryName && "not found" & return & the result + return "entry" && pEntryName && "not found" & return & the result end if # Get the docs data from the record set - local tCount, tMoreRecords + local tCount, tMoreRecords, tData, tLibrary put true into tMoreRecords repeat while tMoreRecords - add 1 to tCount get revDatabaseColumnNamed(tRecordSet, "entry_data", "tData") - put tData into tDataSet[tCount] + if tData is not empty then + get revDatabaseColumnNamed(tRecordSet, "library_name", "tLibrary") + add 1 to tCount + put tData into tDataSet[tCount]["data"] + put tLibrary into tDataSet[tCount]["library"] + end if revMoveToNextRecord tRecordSet put the result into tMoreRecords end repeat @@ -118,40 +131,50 @@ private function __fetchDocsData pEntryName, pLibraryName, pType return tDataSet end __fetchDocsData -private function __ideDocsFetchData pEntryName, pLibraryName, pType +private function __ideDocsFetchData pAPI, pLibraryName, pEntryName, pType # Fetch the data - local tData - put __fetchDocsData(pEntryName, pLibraryName, pType) into tData - - if tData[1] is empty then - return empty - end if + local tDataA + put __fetchDocsData(pAPI, pLibraryName, pEntryName, pType) into tDataA - repeat for each key tCount in tData - put arrayDecode(tData[tCount]) into tData[tCount] + local tDecodedDataA + repeat for each key tCount in tDataA + put arrayDecode(tDataA[tCount]["data"]) into tDecodedDataA[tCount] + put tDataA[tCount]["library"] into tDecodedDataA[tCount]["library"] end repeat # Return the decoded array - return tData + return tDecodedDataA end __ideDocsFetchData -private function ideDocsFetchElementOfType pEntryName, pLibraryName, pType, pElement +private function ideDocsFetchElementOfType pAPI, pLibraryName, pEntryName, pType, pElement local tDataA - put __ideDocsFetchData(pEntryName, pLibraryName, pType) into tDataA + put __ideDocsFetchData(pAPI, pLibraryName, pEntryName, pType) into tDataA return tDataA[1][pElement] end ideDocsFetchElementOfType -private function ideDocsFetchDataOfType pEntryName, pLibraryName, pType +private function ideDocsFetchDataOfType pAPI, pLibraryName, pEntryName, pType local tDataA - put __ideDocsFetchData(pEntryName, pLibraryName, pType) into tDataA + put __ideDocsFetchData(pAPI, pLibraryName, pEntryName, pType) into tDataA return tDataA[1] end ideDocsFetchDataOfType -private function ideDocsFetchData pEntryName, pLibraryName - return __ideDocsFetchData(pEntryName, pLibraryName) +private function ideDocsFetchData pAPI, pLibraryName, pEntryName + return __ideDocsFetchData(pAPI, pLibraryName, pEntryName) end ideDocsFetchData +/* +Fetch the data for LCS entries with name <pEntryName>, including extensions + +Returns: +A numerically keyed array, each element of which is the array +of data +pertaining to a LiveCode Script API entry with the given name. +*/ +function ideDocsFetchScriptData pEntryName + return ideDocsFetchData("livecode_script", "", pEntryName) +end ideDocsFetchScriptData + /* Fetch the data for LiveCode script dictionary entries with name <pEntryName> @@ -161,7 +184,7 @@ of data pertaining to a LiveCode script dictionary entry with the given name. */ function ideDocsFetchLCSData pEntryName - return ideDocsFetchData(pEntryName, "LiveCode Script") + return ideDocsFetchData("livecode_script", "LiveCode Script", pEntryName) end ideDocsFetchLCSData /* @@ -174,7 +197,7 @@ of data pertaining to the unique LiveCode script dictionary entry with the given name and type. */ function ideDocsFetchLCSDataOfType pEntryName, pType - return ideDocsFetchDataOfType(pEntryName, "LiveCode Script", pType) + return ideDocsFetchDataOfType("livecode_script", "LiveCode Script", pEntryName, pType) end ideDocsFetchLCSDataOfType /* @@ -187,9 +210,20 @@ of data describing the element of the array of data pertaining to the LiveCode script dictionary entry with the given name and type. */ function ideDocsFetchLCSElementOfType pEntryName, pType, pElement - return ideDocsFetchElementOfType(pEntryName, "LiveCode Script", pType, pElement) + return ideDocsFetchElementOfType("livecode_script", "LiveCode Script", pEntryName, pType, pElement) end ideDocsFetchLCSElementOfType +/* +Fetch all docs element of the given type in the LiveCode script dictionary. + +Returns: +A numerically keyed array of data, each element of which is an array of data +pertaining to a LiveCode script dictionary entry with the given type. +*/ +function ideDocsFetchLCSElementsOfType pType + return __ideDocsFetchData("livecode_script", "LiveCode Script", "", pType) +end ideDocsFetchLCSElementsOfType + /* Fetch the data for LiveCode builder dictionary entries with name <pEntryName> @@ -199,7 +233,7 @@ of data pertaining to a LiveCode builder dictionary entry with the given name. */ function ideDocsFetchLCBData pEntryName - return ideDocsFetchData(pEntryName, "LiveCode Builder") + return ideDocsFetchData("livecode_builder", "LiveCode Builder", pEntryName) end ideDocsFetchLCBData /* @@ -212,7 +246,7 @@ of data pertaining to the unique LiveCode builder dictionary entry with the given name and type. */ function ideDocsFetchLCBDataOfType pEntryName, pType - return ideDocsFetchDataOfType(pEntryName, "LiveCode Builder", pType) + return ideDocsFetchDataOfType("livecode_builder", "LiveCode Builder", pEntryName, pType) end ideDocsFetchLCBDataOfType /* @@ -225,9 +259,20 @@ of data describing the element of the array of data pertaining to the LiveCode builder dictionary entry with the given name and type. */ function ideDocsFetchLCBElementOfType pEntryName, pType, pElement - return ideDocsFetchElementOfType(pEntryName, "LiveCode Builder", pType, pElement) + return ideDocsFetchElementOfType("livecode_builder", "LiveCode Builder", pEntryName, pType, pElement) end ideDocsFetchLCBElementOfType +/* +Fetch all docs element of the given type in the LiveCode builder dictionary. + +Returns: +A numerically keyed array of data, each element of which is an array of data +pertaining to a LiveCode builder dictionary entry with the given type. +*/ +function ideDocsFetchLCBElementsOfType pType + return __ideDocsFetchData("livecode_builder", "LiveCode Builder", "", pType) +end ideDocsFetchLCBElementsOfType + /* Fetch the data for entries in the API for extension <pID> with name <pEntryName> @@ -237,9 +282,10 @@ of data pertaining to an entry in the API for the given extension with the given name. */ function ideDocsFetchExtensionData pID, pEntryName - local tLibraryName + local tLibraryName, tAPI put revIDEExtensionProperty(pID, "title") into tLibraryName - return ideDocsFetchData(pEntryName, tLibraryName) + put revIDEExtensionProperty(pID, "api") into tAPI + return ideDocsFetchData(tAPI, tLibraryName, pEntryName) end ideDocsFetchExtensionData /* @@ -252,9 +298,10 @@ of data pertaining to the unique entry in the API for the given extension with t given name and type. */ function ideDocsFetchExtensionDataOfType pID, pEntryName, pType - local tLibraryName + local tLibraryName, tAPI put revIDEExtensionProperty(pID, "title") into tLibraryName - return ideDocsFetchDataOfType(pEntryName, tLibraryName, pType) + put revIDEExtensionProperty(pID, "api") into tAPI + return ideDocsFetchDataOfType(tAPI, tLibraryName, pEntryName, pType) end ideDocsFetchExtensionDataOfType /* @@ -267,25 +314,42 @@ of data describing the element of the array of data pertaining to the entry in the API for the given extension with the given name and type. */ function ideDocsFetchExtensionElementOfType pID, pEntryName, pType, pElement - local tLibraryName - put revIDEExtensionProperty(pID, "title") into tLibraryName - return ideDocsFetchElementOfType(pEntryName, tLibraryName, pType, pElement) + local tLibraryName, tAPI + put revIDEExtensionProperty(pID, "title") into tLibraryName + put revIDEExtensionProperty(pID, "api") into tAPI + return ideDocsFetchElementOfType(tAPI, tLibraryName, pEntryName, pType, pElement) end ideDocsFetchExtensionElementOfType +/* +Fetch all docs element of the given type in the LiveCode script dictionary. + +Returns: +A numerically keyed array of data, each element of which is an array of data +pertaining to a LiveCode script dictionary entry with the given type. +*/ +function ideDocsFetchExtensionElementsOfType pID, pType + local tLibraryName, tAPI + put revIDEExtensionProperty(pID, "title") into tLibraryName + put revIDEExtensionProperty(pID, "api") into tAPI + return __ideDocsFetchData(tAPI, tLibraryName, "", pType) +end ideDocsFetchExtensionElementsOfType + /* Returns a list of library names, one per line, which have API entries in the dictionary. */ function ideDocsFetchLibraryNames # Ensure we have a connection + local tConnection try ideDocsInitialize + put the result into tConnection catch tError return tError end try local tRecordSet, tData, tDataSet, tSQL - put "SELECT library_name FROM libraries" into tSQL - put revQueryDatabase(sConnection, tSQL) into tRecordSet + put "SELECT library_name FROM dictionary_data" into tSQL + put revQueryDatabase(tConnection, tSQL) into tRecordSet if the result is not a number then return "error fetching library names" & return & the result end if @@ -296,19 +360,27 @@ function ideDocsFetchLibraryNames repeat while tMoreRecords add 1 to tCount get revDatabaseColumnNamed(tRecordSet, "library_name", "tData") - put tData into tDataSet[tCount] + put true into tDataSet[tData] revMoveToNextRecord tRecordSet put the result into tMoreRecords end repeat - + # Close the record set revCloseCursor tRecordSet - - combine tDataSet with return + + combine tDataSet with return as set + sort tDataSet return tDataSet end ideDocsFetchLibraryNames -private function ideDocsFetchLibraryEntries pLibraryName +/* +Fetch the data for all entries in a given library + +Returns: +A numerically keyed array, each element of which is the array +of data pertaining to an entry in the given library API. +*/ +function ideDocsFetchLibraryEntries pLibraryName return __ideDocsFetchData("", pLibraryName, "") end ideDocsFetchLibraryEntries @@ -345,24 +417,31 @@ of data pertaining to an entry in the API for the given extension. */ function ideDocsFetchExtensionEntries pID - local tLibraryName - put revIDEExtensionProperty(pID, "title") into tLibraryName - return ideDocsFetchLibraryEntries(tLibraryName) + local tLibraryName, tAPI + put revIDEExtensionProperty(pID, "title") into tLibraryName + put revIDEExtensionProperty(pID, "api") into tAPI + return ideDocsFetchLibraryEntries(tAPI, tLibraryName) end ideDocsFetchExtensionEntries -on ideDocsUpdateDatabase pLibraryA - ideDocsInitialize +on ideDocsUpdateDatabase pAPI, pLibraryA, pDistributed + if pDistributed is true and revEnvironmentIsInstalled() then + exit ideDocsUpdateDatabase + end if + + local tConnection + ideDocsInitialize pDistributed + put the result into tConnection local tResult - revExecuteSQL sConnection,"BEGIN TRANSACTION" - dispatch "revDocsUpdateDatabase" to stack "revDocsParser" with sConnection, pLibraryA + revExecuteSQL tConnection,"BEGIN TRANSACTION" + dispatch "revDocsUpdateDatabase" to stack "revDocsParser" with tConnection, pAPI, pLibraryA put the result into tResult if tResult is not empty then - revExecuteSQL sConnection,"ROLLBACK" + revExecuteSQL tConnection,"ROLLBACK" return tResult end if - - revExecuteSQL sConnection, "COMMIT" + + revExecuteSQL tConnection, "COMMIT" return empty end ideDocsUpdateDatabase diff --git a/Toolset/libraries/revideextensionlibrary.livecodescript b/Toolset/libraries/revideextensionlibrary.livecodescript index 4fa2f4daa8..0fea535b15 100644 --- a/Toolset/libraries/revideextensionlibrary.livecodescript +++ b/Toolset/libraries/revideextensionlibrary.livecodescript @@ -1,111 +1,192 @@ script "revideextensionlibrary" -local sExtensions, sExtensionProperties +local sExtensions, sExtensionProperties, sModuleVersion -on revLoadLibrary - if the target is me then - insert script of me into back +constant kExtensionUtils = "com.livecode.library.extension-utils" +private function __PathToExtensionUtils + set the itemdelimiter to "." + return revIDESpecialFolderPath("extensions") & slash & \ + kExtensionUtils & slash & item -1 of kExtensionUtils & "." & \ + "livecodescript" +end __PathToExtensionUtils + +on extensionInitialize + if the target is not me then + pass extensionInitialize + end if + + insert script of me into back + + # Explicitly load extension utils first + revInternal__LoadLibrary "extension-utils", __PathToExtensionUtils() + + if the result is not empty then + throw the result end if -end revLoadLibrary -on revUnloadLibrary + # Load all the extensions ready for use + __extensionsLoad +end extensionInitialize + +on extensionFinalize if the target is me then remove script of me from back end if -end revUnloadLibrary +end extensionFinalize + +private function __ModuleVersion + if sModuleVersion is empty then + put extensionLCCompileVersion() into sModuleVersion + end if + return sModuleVersion +end __ModuleVersion + +function revIDEExtensionBytecodeFilename pUseVersion + if pUseVersion is empty then + put true into pUseVersion + end if + + if pUseVersion then + return "module." & __ModuleVersion() & ".lcm" + else + return "module.lcm" + end if +end revIDEExtensionBytecodeFilename # Called at startup. Loads all the extensions ready for use on revIDEInitialiseExtensions - # Install extensions that haven't yet been installed - repeat for each line tExtensionPackage in __extensionPackagePaths() - revIDEInstallExtension tExtensionPackage - end repeat - # Load all the extensions ready for use __extensionsLoad end revIDEInitialiseExtensions -# Intalls the extension -on revIDEInstallExtension pExtensionPath, pType, pCallbackObject, pCallbackMessage - if pExtensionPath begins with "http" or there is a file pExtensionPath then - - # Get the ID of the extension in the cache - local tCacheIndex - put __extensionCacheID("package_url",pExtensionPath) into tCacheIndex - - if tCacheIndex is empty then - put __extensionCacheID("download_package_path",pExtensionPath) into tCacheIndex - end if - - # If the extension cache ID couldn't be found, generate a new one - if tCacheIndex is empty then - put the number of elements of sExtensions + 1 into tCacheIndex +command revIDEExtensionDownloadAndInstall pExtensionPath, pType, pCallbackObject, pCallbackMessage + local tCacheIndex + __extensionDownloadBegin pExtensionPath, pType, pCallbackObject, pCallbackMessage + put it into tCacheIndex + + if the result is not empty then + answer error the result + exit revIDEExtensionDownloadAndInstall + end if + + # Download the package and install + __extensionPropertySet tCacheIndex, "package_url", pExtensionPath + try + __extensionDownload tCacheIndex + catch tError + answer error tError + end try + __extensionsChanged +end revIDEExtensionDownloadAndInstall + +private function __extensionDependencyExists pExt + return __extensionCacheID("name", pExt) is a number +end __extensionDependencyExists + +private command __extensionInstallPackage pPackageLocation + if there is not a file pPackageLocation then + throw "No package found at" && pPackageLocation + end if + + local tCacheIndex + put __extensionCacheID("download_package_path", pPackageLocation) \ + into tCacheIndex + if tCacheIndex is not a number then + put the number of elements of sExtensions + 1 into tCacheIndex + __extensionPropertySet tCacheIndex, "download_package_path", pPackageLocation + __extensionUpdateUIWithPackage tCacheIndex, pPackageLocation + end if + __extensionPropertySet tCacheIndex, "status", "installing" + + local tVerifyResult, tName + __extensionDownloadVerify tCacheIndex + put the result into tVerifyResult + if tVerifyResult is not empty then + __extensionCacheRemove tCacheIndex + throw "Error installing extension" && pPackageLocation & return & the result + end if + + put __extensionPropertyGet(tCacheIndex, "name") into tName + + # Fetch the dependency list (minus builtin modules) and ensure all + # are loaded + local tDeps + put revIDEExtensionsOrderByDependency(tName) into tDeps + repeat for each line tExtension in tDeps + # Skip the one we're installing + if tExtension is tName then + next repeat end if - - # Add callback data to cache - __extensionPropertySet tCacheIndex, "callback_target", pCallbackObject - __extensionPropertySet tCacheIndex, "callback_handler", pCallbackMessage - __extensionPropertySet tCacheIndex, "name", "New Extension Installing" - - # AL-2015-03-06: [[ Bug 14820 ]] Set the type so that the icon is correct while downloading - __extensionPropertySet tCacheIndex, "type", pType - - if pExtensionPath begins with "http" then - # Download the package and install - __extensionPropertySet tCacheIndex, "package_url", pExtensionPath - __extensionInstallDownload tCacheIndex - else - # Package already downloaded - begin installation - __extensionPropertySet tCacheIndex, "download_package_path", pExtensionPath - __extensionInstallVerify tCacheIndex + # Ensure dependency exists + if not __extensionDependencyExists(tExtension) then + throw "Dependency" && tExtension && "not available. Please install before proceeding" end if - else - # pExtensionPath is not a URL or file on disk - return __extensionError(tCacheIndex,"Could not install extension. The extension must be a URL to a valid package or a path to a extension package on disk:" && pExtensionPath) - end if -end revIDEInstallExtension + end repeat + __extensionInstall tCacheIndex, pPackageLocation +end __extensionInstallPackage + +command revIDEExtensionInstall pPackageLocation + try + __extensionInstallPackage pPackageLocation + catch tError + answer error tError + end try + __extensionsChanged +end revIDEExtensionInstall # Uninstalls the extension -on revIDEUninstallExtension pExtensionTypeID +command revIDEExtensionUninstall pName + local tCacheIndex, tName # Start the uninstall process - if pExtensionTypeID is not a number then - put __extensionCacheID("name", pExtensionTypeID) into pExtensionTypeID + if pName is a number then + put __extensionPropertyGet(pName, "name") into tName + put pName into tCacheIndex + else + put __extensionCacheID("name", pName) into tCacheIndex + put pName into tName end if - __extensionUninstallCheckInUse pExtensionTypeID -end revIDEUninstallExtension + # Get the path to the package file + local tExtensionPackageFile, tInstallPath + put __extensionPropertyGet(tCacheIndex, "download_package_path") into tExtensionPackageFile + put __extensionPropertyGet(tCacheIndex, "install_path") into tInstallPath + try + __extensionUninstallCheckInUse tCacheIndex, 10 + __extensionUninstallDeleteFiles tCacheIndex, tName, tInstallPath, 25 + __extensionUninstallDeletePreferences tCacheIndex, tName, 50 + __extensionUnload tCacheIndex, tName, 80 + __extensionUninstallComplete tCacheIndex + catch tError + answer error tError + end try + __extensionsChanged +end revIDEExtensionUninstall # Returns the extension data function revIDEExtensions pType, pStatus, pWithoutInvisible # No type passed so return all extensions # Repeat over the extension array looking for elements with matching type - local tExtensions - repeat for each key tExtensionKey in sExtensions - if sExtensions[tExtensionKey]["name"] is empty then - delete variable sExtensions[tExtensionKey] + local tExtensions, tExtension + repeat for each key tCacheId in sExtensions + put sExtensions[tCacheId] into tExtension + if tExtension["name"] is empty then + __extensionCacheRemove tCacheId next repeat end if - if pType is not empty and sExtensions[tExtensionKey]["type"] is not pType then next repeat - if pStatus is "installed" then - if sExtensions[tExtensionKey]["status"] is "uninstalled" then - next repeat - end if - else if pStatus is not empty then - if sExtensions[tExtensionKey]["status"] is not pStatus then + if pType is not empty and tExtension["type"] is not pType then + next repeat + end if + if pStatus is not empty then + if tExtension["status"] is not pStatus then next repeat end if end if - if pWithoutInvisible and not sExtensions[tExtensionKey]["uservisible"] then + if pWithoutInvisible and not tExtension["uservisible"] then next repeat end if - local tIconPath - if there is not a file sExtensions[tExtensionKey]["icon"] then - put revIDEDefaultExtensionIcon(pType) into sExtensions[tExtensionKey]["icon"] - end if - - put sExtensions[tExtensionKey] into tExtensions[sExtensions[tExtensionKey]["name"]] + put tExtension into tExtensions[tExtension["name"]] end repeat return tExtensions end revIDEExtensions @@ -115,49 +196,153 @@ function revIDEExtensionProperties pTypeID return sExtensionProperties[pTypeID] end revIDEExtensionProperties +# organise the property info into the structure that the inspectors +# expect, namely [<section>]["grouplist"][<group>]["proplist"][<prop>] +private function __OrganiseInspectorMetadata pDataA + local tExtensionPropsInfoA + repeat for each key tProp in pDataA + local tSection, tGroup, tOrder, tPropInfoA + put pDataA[tProp] into tPropInfoA + put pDataA[tProp]["order"] into tOrder + put pDataA[tProp]["label"] into tGroup + put pDataA[tProp]["section"] into tSection + put tPropInfoA into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["proplist"][tProp] + + put true into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["widget_prop"] + put tOrder into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["order"] + end repeat + return tExtensionPropsInfoA +end __OrganiseInspectorMetadata + function revIDEExtensionPropertiesInfo pTypeId, pOrganise local tPropsA, tExtensionPropsInfoA put revIDEExtensionProperties(pTypeId) into tPropsA if pOrganise then - # If pOrganise is true, organise the property info into the structure that the property - # inspector expects, namely [<section>]["grouplist"][<group>]["proplist"][<prop>] - repeat for each key tProp in tPropsA - local tSection, tGroup, tOrder, tPropInfoA - put tPropsA[tProp] into tPropInfoA - put tPropsA[tProp]["order"] into tOrder - put tPropsA[tProp]["label"] into tGroup - put tPropsA[tProp]["section"] into tSection - put tPropInfoA into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["proplist"][tProp] - - put true into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["widget_prop"] - put tOrder into tExtensionPropsInfoA[tSection]["grouplist"][tGroup]["order"] - end repeat + return __OrganiseInspectorMetadata(tPropsA) else - put tPropsA into tExtensionPropsInfoA + return tPropsA end if - return tExtensionPropsInfoA end revIDEExtensionPropertiesInfo function revIDEExtensionProperty pKind, pProperty local tExtensionID put __extensionCacheID("name", pKind) into tExtensionID + if pProperty is "api" then + return __TypeToAPI(__extensionPropertyGet(tExtensionID, "type")) + end if + return __extensionPropertyGet(tExtensionID, pProperty) end revIDEExtensionProperty +command revIDEExtensionToggleUserVisibility pKind + local tCacheId + put __extensionCacheID("name", pKind) into tCacheId + + local tUserVisible + put __extensionPropertyGet(tCacheId, "uservisible") \ + into tUserVisible + __extensionPropertySet tCacheId, "uservisible", not tUserVisible + revIDESetPreferenceOfSet pKind, "uservisible", not tUserVisible +end revIDEExtensionToggleUserVisibility + +command revIDEExtensionToggleLoadOnStartup pKind + local tLoadOnStartup + put revIDEGetPreferenceOfSet(pKind, "loadOnStartup") into tLoadOnStartup + if tLoadOnStartup is empty then + put true into tLoadOnStartup + end if + revIDEExtensionSetLoadOnStartup pKind, not tLoadOnStartup +end revIDEExtensionToggleLoadOnStartup + +command revIDEExtensionSetLoadOnStartup pKind, pValue + revIDESetPreferenceOfSet pKind, "loadOnStartup", pValue +end revIDEExtensionSetLoadOnStartup + +function revIDEExtensionGetLoadOnStartup pKind + return revIDEGetPreferenceOfSet(pKind, "loadOnStartup") is not false +end revIDEExtensionGetLoadOnStartup + +function revIDEExtensionStandaloneSettings pID + # Get the internal cache index + local tCacheIndex + put __extensionCacheID("name", pID) into tCacheIndex + + return __extensionPropertyGet(tCacheIndex, "standaloneSettings") +end revIDEExtensionStandaloneSettings + +function revIDEExtensionStandaloneSettingsInfo pTypeId, pOrganise + local tPropsA, tExtensionPropsInfoA + put revIDEExtensionStandaloneSettings(pTypeId) into tPropsA + + if pOrganise then + return __OrganiseInspectorMetadata(tPropsA) + else + return tPropsA + end if +end revIDEExtensionStandaloneSettingsInfo + ############################## # PRIVATE INSTALLATION PROCESS ############################## +private command __extensionDownloadBegin pExtensionUrl, pType, pCallbackObject, pCallbackMessage + if not (pExtensionUrl begins with "http") then + # pExtensionPath is not a URL or file on disk + return "Could not download extension. The extension must be a URL" && \ + "to a valid package:" && pExtensionUrl for error + end if + + # Get the ID of the extension in the cache + local tCacheIndex + put __extensionCacheID("package_url",pExtensionUrl) into tCacheIndex + + if tCacheIndex is empty then + put __extensionCacheID("download_package_path",pExtensionUrl) into tCacheIndex + end if + + # If the extension cache ID couldn't be found, generate a new one + if tCacheIndex is empty then + put the number of elements of sExtensions + 1 into tCacheIndex + end if + + # Add callback data to cache + __extensionPropertySet tCacheIndex, "callback_target", pCallbackObject + __extensionPropertySet tCacheIndex, "callback_handler", pCallbackMessage + __extensionPropertySet tCacheIndex, "name", "New Extension" + + # AL-2015-03-06: [[ Bug 14820 ]] Set the type so that the icon is correct while downloading + __extensionPropertySet tCacheIndex, "type", pType + return tCacheIndex for value +end __extensionDownloadBegin + +private command __extensionUpdateUIWithPackage pCacheIndex, pPath + # Get initial name from file + set the itemdel to "." + local tName + put pPath into tName + delete the last item of tName + repeat while the last item of tName is a number + delete the last item of tName + end repeat + __extensionPropertySet pCacheIndex, "name", tName + + # Send update to refresh UI with new package installation + doExtensionsChanged +end __extensionUpdateUIWithPackage + # Download the extension -on __extensionInstallDownload pCacheIndex +private command __extensionDownload pCacheIndex # Check the file extension is correct local tURL put __extensionPropertyGet(pCacheIndex,"package_url") into tURL set the itemdel to "." - if the last item of tURL is not "lce" then return __extensionError(pCacheIndex,"Could not download extension. The package must have the file extension 'lce':" && tURL) + if the last item of tURL is not "lce" then + return __extensionError(pCacheIndex, \ + "The package must have the file extension 'lce':" && tURL) + end if local tPackageFilePath set the itemdel to "/" @@ -168,43 +353,38 @@ on __extensionInstallDownload pCacheIndex __extensionPropertySet pCacheIndex, "progress_message", "Downloading" __extensionPropertySet pCacheIndex, "progress", 0 __extensionPropertySet pCacheIndex, "label", tPackageFilePath + __extensionPropertySet pCacheIndex, "downloaded_from_store", true - # Put is a first stab at the name - set the itemdel to "." - local tName - put tPackageFilePath into tName - delete the last item of tName - repeat while the last item of tName is a number - delete the last item of tName - end repeat - __extensionPropertySet pCacheIndex, "name", tName - - # Send update to refresh UI with new package installation - __extensionsChanged + __extensionUpdateUIWithPackage pCacheIndex, tPackageFilePath # Update progress __extensionSendProgressUpdate pCacheIndex, "Downloading", 0 # Download the extension to a file - libURLDownloadToFile tURL, __extensionPropertyGet(pCacheIndex,"download_package_path"), "__extensionInstallDownloadComplete" -end __extensionInstallDownload + libURLDownloadToFile tURL, __extensionPropertyGet(pCacheIndex,"download_package_path"), "extensionDownloaded" +end __extensionDownload + +on extensionDownloaded pURL, pDownloadStatus + __extensionDownloaded pURL, pDownloadStatus +end extensionDownloaded # Dowload complete -on __extensionInstallDownloadComplete pURL, pDownloadStatus +private command __extensionDownloaded pURL, pDownloadStatus # Get the index of the extension - local tExtensionID + local tCacheIndex - put __extensionCacheID("package_url", pURL) into tExtensionID + put __extensionCacheID("package_url", pURL) into tCacheIndex # Update progress - __extensionSendProgressUpdate tExtensionID, "Download Complete", 100 + __extensionSendProgressUpdate tCacheIndex, "Download Complete", 100 - # Start installing by verifying package - send "__extensionInstallVerify" && tExtensionID to me in 0 milliseconds -end __extensionInstallDownloadComplete + local tPath + put __extensionPropertyGet(tCacheIndex,"download_package_path") into tPath + revIDEExtensionInstall tPath +end __extensionDownloaded # Verify extension package is valid -on __extensionInstallVerify pCacheIndex +private command __extensionDownloadVerify pCacheIndex # Update progress __extensionSendProgressUpdate pCacheIndex, "Verifying extension", 0 @@ -213,86 +393,67 @@ on __extensionInstallVerify pCacheIndex put __extensionPropertyGet(pCacheIndex, "download_package_path") into tExtensionPath # Check the package exists - if there is not a file tExtensionPath then return __extensionError(pCacheIndex,"Could not install extension. Package does not exists: " && tExtensionPath) + if there is not a file tExtensionPath then + return __extensionError(pCacheIndex, \ + "Package does not exist: " && tExtensionPath) + end if # Check the file extension is valid set the itemdel to "." - if the last item of tExtensionPath is not "lce" then return __extensionError(pCacheIndex,"Could not install extension. The package extension '"&the last item of tExtensionPath&"' Is not valid. Must be 'lce'.") - - # Check the manifest contains a name - local tExtensionName - put __extensionManifestValue(pCacheIndex, "name") into tExtensionName - if tExtensionName is "error" then return __extensionError(pCacheIndex,"Could not install extension. The package manifest must contain a valid name (com.livecode.extensions.<developer_ID>.<extension_name>)") - __extensionPropertySet pCacheIndex, "name", tExtensionName - - # Check the manifest contains a version - local tExtensionVersion - put __extensionManifestValue(pCacheIndex, "version") into tExtensionVersion - if tExtensionVersion is "error" then return __extensionError(pCacheIndex,"Could not install extension. The package manifest must contain a valid version number (1.2.3 - major,minor,maintenance)") - __extensionPropertySet pCacheIndex, "version", tExtensionVersion - - # Check the manifest contains an author - local tExtensionAuthor - put __extensionManifestValue(pCacheIndex, "author") into tExtensionAuthor - if tExtensionAuthor is "error" then return __extensionError(pCacheIndex,"Could not install extension. The package manifest must contain an author") - __extensionPropertySet pCacheIndex, "author", tExtensionAuthor - - # Check the manifest contains an type - local tExtensionType - put __extensionManifestValue(pCacheIndex, "type") into tExtensionType - if tExtensionType is "error" then return __extensionError(pCacheIndex,"Could not install extension. The package manifest must contain a type") - __extensionPropertySet pCacheIndex, "type", tExtensionType - - # Check the manifest contains an title - local tExtensionTitle - put __extensionManifestValue(pCacheIndex, "title") into tExtensionTitle - if tExtensionTitle is "error" then return __extensionError(pCacheIndex,"Could not install extension. The package manifest must contain a title") - __extensionPropertySet pCacheIndex, "title", tExtensionTitle + if the last item of tExtensionPath is not "lce" then + return __extensionError(pCacheIndex, "The package extension '" & \ + the last item of tExtensionPath&"' is not valid." && \ + " Must be 'lce'.") + end if - # Build the type ID from the name and version - __extensionPropertySet pCacheIndex, "type_id", tExtensionName & "." & tExtensionVersion + # Ensure the zip contains the things we expect + local tManifestDataA + extensionValidateLCEPackage tExtensionPath, tManifestDataA + if the result is not empty then + return the result + end if - # Next step - send "__extensionInstallRemoveOlderVersions" && pCacheIndex to me in 0 milliseconds -end __extensionInstallVerify - -on __extensionInstallRemoveOlderVersions pCacheIndex - __extensionSendProgressUpdate pCacheIndex, "Removing older versions", 7 + repeat for each key tKey in tManifestDataA + __extensionPropertySet pCacheIndex, tKey, tManifestDataA[tKey] + end repeat - local tName + # Build the type ID from the name and version + __extensionPropertySet pCacheIndex, "type_id", \ + tManifestDataA["name"] & "." & tManifestDataA["version"] +end __extensionDownloadVerify + +private command __extensionInstall pCacheIndex, pPackage + local tName, tTypeId, tInstallPath put __extensionPropertyGet(pCacheIndex, "name") into tName + put __extensionPropertyGet(pCacheIndex, "type_id") into tTypeId + put revIDESpecialFolderPath("user extensions") & slash & tTypeId into tInstallPath + revIDEEnsurePath tInstallPath + + __extensionInstallRemoveOlderVersions pCacheIndex, tName, 15 + __extensionInstallExtract pCacheIndex, tInstallPath, tTypeID, pPackage, 30 + __extensionInstallCopyInterfaceFile pCacheIndex, tName, tInstallPath, 50 + __extensionInstallLoad pCacheIndex, tName, tInstallPath, 80 + __extensionInstallFinalise pCacheIndex, tTypeID +end __extensionInstall + +on __extensionInstallRemoveOlderVersions pCacheIndex, pName, pProgress + __extensionSendProgressUpdate pCacheIndex, "Removing older versions", pProgress repeat for each key tCacheIndex in sExtensions if tCacheIndex is pCacheIndex then next repeat - if sExtensions[tCacheIndex]["name"] is tName then - revIDEUninstallExtension tCacheIndex + if sExtensions[tCacheIndex]["name"] is pName then + revIDEExtensionUninstall tCacheIndex end if end repeat - - # Next step - send "__extensionInstallExtract" && pCacheIndex to me in 0 milliseconds end __extensionInstallRemoveOlderVersions -# Extract the extension files -on __extensionInstallExtract pCacheIndex - # Update progress - __extensionSendProgressUpdate pCacheIndex, "Extracting extension", 15 - - # Get the path to the package file - local tExtensionPackageFile - put __extensionPropertyGet(pCacheIndex, "download_package_path") into tExtensionPackageFile - - # Create directory to extract into - local tExtensionDirectory - put revIDESpecialFolderPath("temp extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") into tExtensionDirectory - revIDEEnsurePath(tExtensionDirectory) - +private command __extensionPackageExtract pPackage, pTargetFolder # Extract the icon,docs and executable module into the folder - revZipOpenArchive tExtensionPackageFile, "read" + revZipOpenArchive pPackage, "read" # Work out the root of the zip local tZipItems, tZipRoot - put revZipEnumerateItems(tExtensionPackageFile) into tZipItems + put revZipEnumerateItems(pPackage) into tZipItems if the last char of line 1 of tZipItems is "/" then put line 1 of tZipItems into tZipRoot else @@ -303,116 +464,60 @@ on __extensionInstallExtract pCacheIndex local tDirectory set the itemdel to slash repeat for each line tFile in tZipItems - put tExtensionDirectory & slash & item 1 to -2 of tFile into tDirectory + put pTargetFolder & slash & item 1 to -2 of tFile into tDirectory revIDEEnsurePath(tDirectory) - revZipExtractItemToFile tExtensionPackageFile, tFile, tExtensionDirectory & slash & tFile + revZipExtractItemToFile pPackage, tFile, pTargetFolder & slash & tFile end repeat - # add path to icon file to the data array - __extensionPropertySet pCacheIndex, "icon", revIDESpecialFolderPath("user extensions") & slash & __extensionPropertyGet(pCacheIndex,"type_id") & "/support/icon.png" - - revZipCloseArchive tExtensionPackageFile - - # Next step - send "__extensionInstallGuide" && pCacheIndex to me in 0 milliseconds -end __extensionInstallExtract + revZipCloseArchive pPackage +end __extensionPackageExtract -# Install the guide into the IDE -on __extensionInstallGuide pCacheIndex - # Update progress - __extensionSendProgressUpdate pCacheIndex, "Adding user guide to documentation", 30 - - # Path to user guide - local tUserGuideFolder - put revIDESpecialFolderPath("temp extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") & slash & "docs/guide" into tUserGuideFolder - - # Get the name and author required by user guide install function - local tExtensionName, tExtensionAuthor - put __extensionPropertyGet(pCacheIndex, "name") into tExtensionName - put __extensionPropertyGet(pCacheIndex, "author") into tExtensionAuthor - - # Install user guide into the IDE - revIDEInstallUserGuide tUserGuideFolder, tExtensionName, tExtensionAuthor - - send "__extensionInstallAPI" && pCacheIndex to me in 500 milliseconds -end __extensionInstallGuide - -# Install the extension API into the IDE -on __extensionInstallAPI pCacheIndex +# Extract the extension files +private command __extensionInstallExtract pCacheIndex, pFinalPath, pTypeId, pPackage, pProgress # Update progress - __extensionSendProgressUpdate pCacheIndex, "Adding API to documentation", 45 - - # Path to user guide - local tUserAPIFolder - put revIDESpecialFolderPath("temp extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") & slash & "docs/api" into tUserAPIFolder - - # Get the name and author required by API install function - local tExtensionName, tExtensionAuthor - put __extensionPropertyGet(pCacheIndex, "name") into tExtensionName - put __extensionPropertyGet(pCacheIndex, "author") into tExtensionAuthor + __extensionSendProgressUpdate pCacheIndex, "Extracting extension", pProgress - # Install API into the IDE - // revIDEInstallAPI tUserAPIFolder, tExtensionName, tExtensionAuthor - revIDEInstallAPI tUserAPIFolder, tExtensionName, tExtensionAuthor + __extensionPropertySet pCacheIndex, "install_path", pFinalPath - # Next step - send "__extensionInstallMakeLive" && pCacheIndex to me in 0 milliseconds -end __extensionInstallAPI + # Extract into final directory + __extensionPackageExtract pPackage, pFinalPath +end __extensionInstallExtract -# Moves to temp extracted files into their final live location -on __extensionInstallMakeLive pCacheIndex +private command __extensionInstallCopyInterfaceFile pCacheIndex, pName, pInstallFolder, pProgress # Update progress - __extensionSendProgressUpdate pCacheIndex, "Copying extension into install location", 60 - - # Get path the directories - local tTempInstallPath, tFinalPath - put revIDESpecialFolderPath("temp extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") into tTempInstallPath - put revIDESpecialFolderPath("user extensions") into tFinalPath - __extensionPropertySet pCacheIndex, "install_path", tFinalPath & slash & __extensionPropertyGet(pCacheIndex, "type_id") - - # Copy folder from temp directory into live directory - revCopyFolder tTempInstallPath,tFinalPath + __extensionSendProgressUpdate pCacheIndex, "Copying interface file", pProgress # AL-2015-03-15: [[ Bug 15008 ]] Move interface file to interface folder local tInterfaceFile, tInterfacePath - put __extensionPropertyGet(pCacheIndex, "name") & ".lci" into tInterfaceFile - put tFinalPath & slash &__extensionPropertyGet(pCacheIndex, "type_id") \ - & slash & tInterfaceFile into tInterfacePath + put pName & ".lci" into tInterfaceFile + put pInstallFolder & slash & tInterfaceFile into tInterfacePath if there is a file tInterfacePath then local tTargetFolder - put tFinalPath & slash & "interface" into tTargetFolder + put revIDESpecialFolderPath("user extensions") & slash & \ + "interface" into tTargetFolder revIDEEnsurePath tTargetFolder revCopyFile tInterfacePath, tTargetFolder & slash & tInterfaceFile end if - - # Next step - send "__extensionInstallLoad" && pCacheIndex to me in 0 milliseconds -end __extensionInstallMakeLive +end __extensionInstallCopyInterfaceFile -on __extensionInstallLoad pCacheIndex - # Update progress - __extensionSendProgressUpdate pCacheIndex, "Loading extension", 75 - - # Path to module file - local tModuleFile - put revIDESpecialFolderPath("temp extensions") \ - & slash & __extensionPropertyGet(pCacheIndex, "type_id") \ - & slash & "module.lcm" into tModuleFile - - # Store the extension's property metadata - local tTypeID - put __extensionPropertyGet(pCacheIndex, "name") into tTypeID - revIDEExtensionSetInfo(tTypeID) +private command __extensionInstallLoad pCacheIndex, pName, pInstallFolder, pProgress + local tFolderData + extensionFindInFolder pInstallFolder, true, false, tFolderData + if tFolderData is empty then + throw "extension missing from" && pInstallFolder + end if - # Load module file into the engine local tDataA - put sExtensions[pCacheIndex] into tDataA["copies"][1] + put tFolderData[pName][pInstallFolder] into tDataA["copies"][1] + + -- add any previously cached info + union tDataA["copies"][1] with sExtensions[pCacheIndex] recursively local tExisting repeat for each key tExtensionID in sExtensions if tExtensionID is pCacheIndex then next repeat - if sExtensions[tExtensionID]["name"] is tTypeID then + if sExtensions[tExtensionID]["name"] is pName then put sExtensions[tExtensionID]["copies"] into tExisting end if end repeat @@ -421,29 +526,21 @@ on __extensionInstallLoad pCacheIndex put tExisting[tKey] into tDataA["copies"][tKey + 1] end repeat - __extensionLoad tTypeID, tDataA - - # Next step - send "__extensionInstallFinalise" && pCacheIndex to me in 0 milliseconds + __extensionLoad pName, tDataA end __extensionInstallLoad # Delete installation files and original package -on __extensionInstallFinalise pCacheIndex - # Update progress - __extensionSendProgressUpdate pCacheIndex, "Removing temp files", 90 - - # Delete temp install folder - local tTempInstallPath - put revIDESpecialFolderPath("temp extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") into tTempInstallPath - if there is a folder tTempInstallPath then - revDeleteFolder tTempInstallPath - end if - +on __extensionInstallFinalise pCacheIndex, pTypeId # Delete temp package file - local tTempInstallPackage - put revIDESpecialFolderPath("downloading extensions") & slash & __extensionPropertyGet(pCacheIndex, "type_id") & ".lce" into tTempInstallPackage - if there is a file tTempInstallPackage then - revDeleteFolder tTempInstallPackage + if __extensionPropertyGet(pCacheIndex, "downloaded_from_store") then + # Update progress + __extensionSendProgressUpdate pCacheIndex, "Removing temp files", 90 + local tTempInstallPackage + put revIDESpecialFolderPath("downloading extensions") & slash & \ + pTypeId & ".lce" into tTempInstallPackage + if there is a file tTempInstallPackage then + revDeleteFile tTempInstallPackage + end if end if # Update the cache @@ -459,182 +556,201 @@ end __extensionInstallFinalise ############################## # Check if the widget to be uninstalled is in use -on __extensionUninstallCheckInUse pCacheIndex +private command __extensionUninstallCheckInUse pCacheIndex, pProgress # Update progress if pCacheIndex is not a number then return __extensionError(pCacheIndex, "Could not remove extension '" & pCacheIndex & "' because it is not a valid index") - __extensionSendProgressUpdate pCacheIndex, "Checking if extension is in use", 20 - - # Next step - __extensionUninstallDeleteFiles pCacheIndex + __extensionSendProgressUpdate pCacheIndex, "Checking if extension is in use", pProgress end __extensionUninstallCheckInUse -# Delete the files associated to the extension -on __extensionUninstallDeleteFiles pCacheIndex +# Unload the extension +private command __extensionUninstallUnload pCacheIndex, pName, pProgress # Update progress - __extensionSendProgressUpdate pCacheIndex, "Deleting extension files", 40 + __extensionSendProgressUpdate pCacheIndex, "Unloading extension", pProgress - # Get the extension isntall path - local tPath - put __extensionPropertyGet(pCacheIndex, "install_path") into tPath + revIDEExtensionUnload pName +end __extensionUninstallUnload + +# Delete the files associated to the extension +private command __extensionUninstallDeleteFiles pCacheIndex, pName, pInstallPath, pProgress + # Update progress + __extensionSendProgressUpdate pCacheIndex, "Deleting extension files", pProgress # Make sure the path contains the folder extension as a check before deleting a folder - if tPath contains "extension" then - revDeleteFolder tPath + if pInstallPath begins with revIDESpecialFolderPath("user extensions") then + revDeleteFolder pInstallPath end if # AL-2015-03-15: [[ Bug 15008 ]] Delete interface file from interface folder local tInterfaceFile - put __extensionPropertyGet(pCacheIndex, "name") & ".lci" into tInterfaceFile - if there is a file (specialFolderPath("user extensions") & slash & "interface" & slash & tInterfaceFile) then - revDeleteFile specialFolderPath("user extensions") & slash & "interface" & slash & tInterfaceFile + put pName & ".lci" into tInterfaceFile + if there is a file (revIDESpecialFolderPath("user extensions") & slash & "interface" & slash & tInterfaceFile) then + revDeleteFile revIDESpecialFolderPath("user extensions") & slash & "interface" & slash & tInterfaceFile end if - - # Next step - __extensionUninstallUnload pCacheIndex end __extensionUninstallDeleteFiles -# Unload the extension -on __extensionUninstallUnload pCacheIndex +private command __extensionUninstallDeletePreferences pCacheIndex, pName, pProgress # Update progress - __extensionSendProgressUpdate pCacheIndex, "Unloading extension", 60 + __extensionSendProgressUpdate pCacheIndex, "Deleting preferences", pProgress - # Unload the extension by name - local tName - put __extensionPropertyGet(pCacheIndex, "name") into tName - revIDEExtensionUnload tName - - # Next step - __extensionUninstallDocs pCacheIndex -end __extensionUninstallUnload + revIDEDeletePreferenceSet pName +end __extensionUninstallDeletePreferences -# Remove the guide from the IDE -on __extensionUninstallDocs pCacheIndex +private command __extensionUnload pCacheIndex, pName, pProgress # Update progress - __extensionSendProgressUpdate pCacheIndex, "Removing API and user guide from documentation", 80 + __extensionSendProgressUpdate pCacheIndex, "Unloading extension", pProgress - revIDERegenerateBuiltDictionaryData - - __extensionUninstallComplete pCacheIndex -end __extensionUninstallDocs + revIDEExtensionUnload pName +end __extensionUnload -on __extensionUninstallComplete pCacheIndex +private command __extensionUninstallComplete pCacheIndex # Notify IDE uninstallation complete __extensionSendProgressUpdate pCacheIndex, "Complete", 100 - - # Update the IDE - __extensionsChanged + delete variable sExtensions[pCacheIndex] end __extensionUninstallComplete ############################## # PRIVATE SHARED ############################## +private command __ProcessInspectorMetadata @xMetadataA + repeat for each key tKey in xMetadataA + local tLabel, tSection + if xMetadataA[tKey]["section"] is empty then + put "Basic" into xMetadataA[tKey]["section"] + end if + + if xMetadataA[tKey]["label"] is empty then + put tKey into xMetadataA[tKey]["label"] + end if + + # Process value options, default and delimiter + replace comma with return in xMetadataA[tKey]["options"] + replace "\n" with return in xMetadataA[tKey]["delimiter"] + if xMetadataA[tKey]["default"] is not empty then + replace "\n" with return in xMetadataA[tKey]["default"] + end if + + if xMetadataA[tKey]["user_visible"] is empty then + put true into xMetadataA[tKey]["user_visible"] + end if + + if xMetadataA[tKey]["properties"] is not empty then + -- If there is a 'properties' value, delete the key + -- and replace it with that value + local tInfo, tNewKey + put xMetadataA[tKey] into tInfo + put tInfo["properties"] into tNewKey + delete variable xMetadataA[tKey] + delete variable tInfo["properties"] + put tInfo into xMetadataA[tNewKey] + end if + end repeat +end __ProcessInspectorMetadata -function __extensionFetchPropertyMetadata pXMLTree, pProperty, pElement - local tNode - put revXMLMatchingNode(pXMLTree, "package", "metadata", "key", pProperty &"." & pElement, 1) into tNode - if tNode is not empty then - return revXMLNodeContents(pXMLTree, tNode) - end if - - return empty -end __extensionFetchPropertyMetadata - -function __extensionPropertyInfoFromManifest pManifestPath +private function __extensionPropertyInfoFromManifest pId, pManifestPath if not there is a file pManifestPath then return empty # Create the XML tree - local tXMLTree, tProperties, tExtensionData + local tXMLTree, tProperties, tExtensionData, tPropertyNodes put revXMLCreateTreeFromFile(pManifestPath,true,true,false) into tXMLTree - # Process the general property metadata into an array - local tMetadataNodes, tMetadataA, tKeys, tValue - put revXMLChildNames(tXMLTree, "package",return,"metadata",true) into tMetadataNodes - set the itemdelimiter to "." - repeat for each line tMetadata in tMetadataNodes - put revXMLAttribute(tXMLTree,"package" & "/" & tMetadata,"key") into tKeys - put revXMLNodeContents(tXMLTree,"package" & "/" & tMetadata) into tValue - repeat with x = the number of items in tKeys down to 1 - get tValue - put empty into tValue - put it into tValue[item x of tKeys] - end repeat - union tMetadataA with tValue recursively + put revXMLChildNames(tXMLTree,"package",return,"property",true) into tPropertyNodes + + local tCacheID + put __extensionCacheID("name", pID) into tCacheId + + local tPropertyNames, tPropertyXMLData, tPropNameList, tMaxOrder + repeat for each line tPropertyNode in tPropertyNodes + local tName + put revXMLAttribute(tXMLTree,"package" & "/" & tPropertyNode,"name") into tName + put __extensionPropertyGet(tCacheId, tName) into tPropertyXMLData[tName]["data"] + put revXMLAttribute(tXMLTree,"package" & "/" & tPropertyNode,"set") into \ + tPropertyXMLData[tName]["set"] + put revXMLAttribute(tXMLTree,"package" & "/" & tPropertyNode,"get") into \ + tPropertyXMLData[tName]["get"] + put tName into tPropNameList[tPropertyNode] + put max(tMaxOrder, tPropertyXMLData[tName]["data"]["order"]) into tMaxOrder end repeat - put revXMLChildNames(tXMLTree,"package",return,"property",true) into tProperties - local tOrder, tPropertyDataA - - local tMetadataKeys - put the keys of tMetadataA into tMetadataKeys - sort tMetadataKeys - sort tMetadataKeys by tMetadataA[each]["order"] - repeat for each line tKey in tMetadataKeys - local tPropertyInfo - put revIDEPropertyInfo(tKey) into tPropertyInfo - if tPropertyInfo is empty then - next repeat + -- Sort by ordered props, then by order of appearance + repeat for each line tPropertyNode in tPropertyNodes + if tPropertyXMLData[tPropNameList[tPropertyNode]]["data"]["order"] \ + is empty then + add 1 to tMaxOrder + put tMaxOrder into tPropertyXMLData[tPropNameList[tPropertyNode]]["data"]["order"] end if - add 1 to tOrder - union tMetadataA[tKey] with tPropertyInfo - put tMetadataA[tKey] into tPropertyDataA[tKey] - put tOrder into tPropertyDataA[tKey]["order"] end repeat - repeat for each line tProperty in tProperties - add 1 to tOrder - local tName - put revXMLAttribute(tXMLTree,"package" & "/" & tProperty,"name") into tName - - put tMetadataA[tName] into tPropertyDataA[tName] + put the keys of tPropertyXMLData into tPropertyNames + sort tPropertyNames by tPropertyXMLData[each]["data"]["order"] + + local tPropertyDataA + repeat for each line tProperty in tPropertyNames + local tIDEPropertyInfo, tPropertyInfoA + put tPropertyXMLData[tProperty]["data"] into tPropertyInfoA + put revIDEPropertyInfo(tProperty) into tIDEPropertyInfo + if tIDEPropertyInfo is not empty then + union tPropertyInfoA with tIDEPropertyInfo + put tPropertyInfoA into tPropertyDataA[tProperty] + else + put tPropertyInfoA into tPropertyDataA[tProperty] + end if - local tReadOnly - get revXMLAttribute(tXMLTree,"package" & "/" & tProperty,"set") - if it is empty or it begins with "xmlerr" then + local tReadOnly, tSetter + put tPropertyXMLData[tProperty]["set"] into tSetter + if tSetter is empty or tSetter begins with "xmlerr" then put true into tReadOnly else put false into tReadOnly end if - put tReadOnly into tPropertyDataA[tName]["read_only"] + put tReadOnly into tPropertyDataA[tProperty]["read_only"] - if tPropertyDataA[tName]["editor"] is empty then + if tPropertyDataA[tProperty]["editor"] is empty then local tType - put revXMLAttribute(tXMLTree,"package" & "/" & tProperty,"get") into tType + put tPropertyXMLData[tProperty]["get"] into tType if tType is "Integer" or tType is "Real" then - put "com.livecode.pi.number" into tPropertyDataA[tName]["editor"] + put "com.livecode.pi.number" into tPropertyDataA[tProperty]["editor"] else - put "com.livecode.pi." & tolower(tType) into tPropertyDataA[tName]["editor"] + put "com.livecode.pi." & tolower(tType) into tPropertyDataA[tProperty]["editor"] end if end if - put tOrder into tPropertyDataA[tName]["order"] + # Tag the property as a widget property, so we can order them + # correctly after the built-in props for the given section + put true into tPropertyDataA[tProperty]["widget_prop"] end repeat - repeat for each key tName in tPropertyDataA - local tLabel, tSection - - if tPropertyDataA[tName]["section"] is empty then - put "Basic" into tPropertyDataA[tName]["section"] - end if - - if tPropertyDataA[tName]["label"] is empty then - put tName into tPropertyDataA[tName]["label"] + # Fetch property override metadata + local tMetadataValue, tMetadataKey + local tMetadataNodes, tMetadataA, tDataA + put revXMLChildNames(tXMLTree, "package",return,"metadata",true) into tMetadataNodes + repeat for each line tMetadata in tMetadataNodes + put revXMLAttribute(tXMLTree,"package" & "/" & tMetadata,"key") into tMetadataKey + put revXMLNodeContents(tXMLTree,"package" & "/" & tMetadata) into tMetadataValue + if tMetadataValue is empty or tMetadataValue begins with "xmlerr" then + put empty into tMetadataValue end if - - # Process value options, default and delimiter - replace comma with return in tPropertyDataA[tName]["options"] - replace "\n" with return in tPropertyDataA[tName]["delimiter"] - if tPropertyDataA[tName]["default"] is not empty then - replace "\n" with return in tPropertyDataA[tName]["default"] + __SetMetadata tMetadataKey, tMetadataValue, tDataA + end repeat + + repeat for each key tProperty in tDataA + if tPropertyXMLData[tProperty] is not empty then + next repeat end if - - # Tag the property as a widget property, so we can order them - # correctly after the built-in props for the given section - put true into tPropertyDataA[tName]["widget_prop"] - - if tPropertyDataA[tName]["user_visible"] is empty then - put true into tPropertyDataA[tName]["user_visible"] + local tIDEPropInfoA + put revIDEPropertyInfo(tProperty) into tIDEPropInfoA + if tIDEPropInfoA is not empty then + # if this is a control property that we are overriding, + # tData might be non-empty for the property even though + # there was no property node in the XML + union tPropertyDataA[tProperty] with tDataA[tProperty] + + # Now take any default property info that was not specified + # in the manifest + union tPropertyDataA[tProperty] with tIDEPropInfoA end if end repeat + __ProcessInspectorMetadata tPropertyDataA + revXMLDeleteTree tXMLTree return tPropertyDataA end __extensionPropertyInfoFromManifest @@ -680,22 +796,29 @@ private command __extensionSetExtensionInfoFromManifest pCacheIndex, pManifestPa end repeat end __extensionSetExtensionInfoFromManifest -command __extensionSetPropertyInfoFromManifest pID, pManifest +private command __extensionSetPropertyInfoFromManifest pID, pManifest local tPropertyInfo - put __extensionPropertyInfoFromManifest(pManifest) into tPropertyInfo + put __extensionPropertyInfoFromManifest(pId, pManifest) into tPropertyInfo put tPropertyInfo into sExtensionProperties[pID] end __extensionSetPropertyInfoFromManifest -function __extensionError pCacheIndex, pErrorMessage +private function __extensionError pCacheIndex, pErrorMessage __extensionSendProgressUpdate pCacheIndex, "Error:" && pErrorMessage, 100 - --put "Error:" && pErrorMessage, 100 - --revIDEUninstallExtension pCacheIndex - return empty + return pErrorMessage end __extensionError # Send notication that widget has been added/removed -on __extensionsChanged +on doExtensionsChanged ideMessageSend "ideExtensionsChanged" +end doExtensionsChanged + +local sExtensionsChangedMsg +private command __extensionsChanged + if sExtensionsChangedMsg is not empty then + cancel sExtensionsChangedMsg + end if + send "doExtensionsChanged" to me in 10 millisecs + put the result into sExtensionsChangedMsg end __extensionsChanged # Sent progress update on installation of widget @@ -705,169 +828,73 @@ on __extensionSendProgressUpdate pCacheIndex, pMessage, pProgress __extensionPropertySet pCacheIndex, "progress", pProgress local tName - //revputarray sExtensions put __extensionPropertyGet(pCacheIndex, "name") into tName ideMessageSend "ideExtensionStatusChanged", (tName & comma & pMessage & comma & pProgress) - - //local tCallbackTarget, tCallBackHandler - //put __extensionPropertyGet(pCacheIndex, "callback_target") into tCallbackTarget - //put __extensionPropertyGet(pCacheIndex, "callback_handler") into tCallBackHandler - //if exists(tCallbackTarget) then - //dispatch tCallBackHandler to tCallbackTarget with pMessage,pProgress - //end if - // Send message to registered targets end __extensionSendProgressUpdate -private function __fetchModuleData pExtensionFile - local tDataA, tFolder - set the itemdelimiter to slash - put item 1 to -2 of pExtensionFile into tFolder - revIDEExtensionFetchMetadata tFolder & slash & "manifest.xml", tDataA +private function __fetchExtensionManifestData pFolder, pExtFile + local tDataA + revIDEExtensionFetchMetadata pFolder & slash & "manifest.xml", tDataA # If we couldn't fetch a type id, or there was no manifest then the result will not be empty if the result is not empty then put "Invalid manifest" into tDataA["error"] put "error" into tDataA["status"] end if return tDataA -end __fetchModuleData - -private function __extensionIsBuiltin pID - switch pID - case "com.livecode.widget" - case "com.livecode.engine" - case "com.livecode.canvas" - case "com.livecode.foreign" - case "com.livecode.arithmetic" - case "com.livecode.array" - case "com.livecode.binary" - case "com.livecode.bitwise" - case "com.livecode.byte" - case "com.livecode.char" - case "com.livecode.codeunit" - case "com.livecode.date" - case "com.livecode.file" - case "com.livecode.list" - case "com.livecode.logic" - case "com.livecode.mathfoundation" - case "com.livecode.math" - case "com.livecode.sort" - case "com.livecode.stream" - case "com.livecode.string" - case "com.livecode.system" - case "com.livecode.type" - case "com.livecode.typeconvert" - case "com.livecode.extensions.libbrowser" - return true - default - return false - end switch -end __extensionIsBuiltin +end __fetchExtensionManifestData -private on __addToDependencies pDependee, pDependent, @xDependencies - # AL-2015-04-13: [[ Bug 15216 ]] Use keys of array to remove duplicates - put true into xDependencies[pDependee][pDependent] -end __addToDependencies - -private on __addToList pNode, @xList - if xList is empty then - put pNode into xList - else - put return & pNode after xList - end if -end __addToList +private command __extensionAddDependenciesToRequiresArray \ + pExtension, @xRequiresA, @xExtensions -private on __removeFromList pNode, @xList - get lineOffset(pNode, xList) - if it is not 0 then - delete line it of xList - end if -end __removeFromList + local tDependentsA + put revIDEExtensionProperty(pExtension, "requires") into tDependentsA -private on __visitNode pDependencies, pNode, @xUnmarked, @xMarked, @xTemporaryMarked, @xOrder - if pNode is among the lines of xTemporaryMarked then - return "Error" - end if - if pNode is among the lines of xMarked then - # AL-2015-04-13: [[ Bug 15216 ]] Remove from unmarked if this was already marked - __removeFromList pNode, xUnmarked - return "" - end if - __addToList pNode, xTemporaryMarked - repeat for each key tNode in pDependencies[pNode] - __visitNode pDependencies, tNode, xUnmarked, xMarked, xTemporaryMarked, xOrder - if the result is not empty then - return "Error" - end if - end repeat - __addToList pNode, xMarked - __removeFromList pNode, xUnmarked - __removeFromList pNode, xTemporaryMarked - __addToList pNode, xOrder -end __visitNode - -private function __dependencyOrder pDependencies, pList - local tUnmarked, tTemporaryMarked, tMarked, tOrder, tToVisit - put pList into tUnmarked - repeat while tUnmarked is not empty - put any line of tUnmarked into tToVisit - __visitNode pDependencies, tToVisit, tUnmarked, tMarked, tTemporaryMarked, tOrder - if the result is not empty then - throw "Circularity in dependencies starting from" && tToVisit - return empty + repeat for each element tElement in tDependentsA + if tElement is not among the keys of xRequiresA then + __extensionAddDependenciesToRequiresArray \ + tElement, xRequiresA, xExtensions end if + addToList tElement, xRequiresA[pExtension] end repeat - return tOrder -end __dependencyOrder + + put empty into xExtensions[pExtension] +end __extensionAddDependenciesToRequiresArray function revIDEExtensionsOrderByDependency pExtensions # Accumulate an array of dependencies - local tDependencies, tRequirements + local tRequiresA, tExtensions repeat for each line tExtension in pExtensions - put revIDEExtensionProperty(tExtension, "requires") into tRequirements - repeat for each element tDependent in tRequirements - if __extensionIsBuiltin(tDependent) then - next repeat - end if - __addToDependencies tExtension, tDependent, tDependencies - end repeat + __extensionAddDependenciesToRequiresArray \ + tExtension, tRequiresA, tExtensions end repeat - # Order them - return __dependencyOrder(tDependencies, pExtensions) + return extensionOrderByDependency(the keys of tExtensions, tRequiresA) end revIDEExtensionsOrderByDependency +private function isUserExtension pData + if pData["ide"] then + return 1 + end if + return 0 +end isUserExtension + +private command addToList pElement, @xArray + put pElement into xArray[the number of elements in xArray + 1] +end addToList + on __extensionsLoad - local tDataA - revIDEPushDefaultFolder - + local tDataA # Fetch all the available data about extensions in the search paths - local tFoldersA, tExtensionFolder, tPath + local tFoldersA, tExtensionFolder put revIDEExtensionFolders() into tFoldersA - set the itemdel to "." repeat for each key tKey in tFoldersA put tFoldersA[tKey] into tExtensionFolder - set the defaultfolder to tExtensionFolder - repeat for each line tFolder in the folders + repeat for each line tFolder in folders(tExtensionFolder) if tFolder begins with "." then next repeat if tFolder is among the items of "downloading,temp,uninstalled" then next repeat - - local tExtensionModulePath, tArray - put tExtensionFolder & slash & tFolder & slash & "module.lcm" into tPath - if there is a file tPath then - put __fetchModuleData(tPath) into tArray - if tKey is "ide" then - put true into tArray["ide"] - else - put false into tArray["ide"] - end if - local tTypeID - if tArray["name"] is empty then - put tFolder into tTypeID - else - put tArray["name"] into tTypeID - end if - put tArray into tDataA[tTypeID][tExtensionFolder][tFolder] - end if + local tExtFolder + put tExtensionFolder & slash & tFolder into tExtFolder + extensionFindInFolder tExtFolder, tKey is "user", true, tDataA end repeat end repeat @@ -876,43 +903,44 @@ on __extensionsLoad put the keys of tDataA into tExtensionsList sort tExtensionsList - local tToLoadA, tDependencies + local tToLoadA, tDependentsA, tRequiresA set the itemdel to "," put 1 into tExtensionCount repeat for each line tTypeID in tExtensionsList put 1 into tExtensionCopyCount - repeat for each item tItem in "user,ide" - repeat for each key tFolder in tDataA[tTypeID][tFoldersA[tItem]] - put tDataA[tTypeID][tFoldersA[tItem]][tFolder] into tExtensionDataA["copies"][tExtensionCopyCount] - put tFoldersA[tItem] & slash & tFolder into tExtensionDataA["copies"][tExtensionCopyCount]["install_path"] - add 1 to tExtensionCopyCount - end repeat + local tCopyFolders + put the keys of tDataA[tTypeID] into tCopyFolders + -- give priority to user extensions. If there are multiple + -- then further resolve by alphabetical order of full filename + sort tCopyFolders + sort tCopyFolders ascending numeric by isUserExtension(tDataA[tTypeID][each]) + repeat for each key tFolder in tDataA[tTypeID] + put tDataA[tTypeID][tFolder] into tExtensionDataA["copies"][tExtensionCopyCount] + put tFolder into tExtensionDataA["copies"][tExtensionCopyCount]["install_path"] + add 1 to tExtensionCopyCount end repeat put tExtensionDataA into tToLoadA[tTypeID] - # Accumulate an array of dependencies - repeat for each element tDependent in tExtensionDataA["copies"][1]["requires"] - if __extensionIsBuiltin(tDependent) then - next repeat - end if - __addToDependencies tTypeID, tDependent, tDependencies + + put tExtensionDataA["copies"][1]["requires"] into tDependentsA + repeat for each element tElement in tDependentsA + addToList tElement, tRequiresA[tTypeId] end repeat put empty into tExtensionDataA end repeat - # Perform topological sort on list of dependencies so that they are loaded in the correct order - repeat for each line tLine in __dependencyOrder(tDependencies, the keys of tToLoadA) + local tLoadOrder + put extensionOrderByDependency(tExtensionsList, tRequiresA) into \ + tLoadOrder + + repeat for each line tLine in tLoadOrder + # Extension utils is explicitly loaded + if tLine is kExtensionUtils then + next repeat + end if __extensionLoad tLine, tToLoadA[tLine] end repeat - - revIDEPopDefaultFolder end __extensionsLoad -# Returns: List of the packages that are in the directory but not installed -function __extensionPackagePaths - local tPaths - return tPaths -end __extensionPackagePaths - # Calls Weservice and returns updates function __extensionUpdates end __extensionUpdates @@ -926,6 +954,10 @@ private function __extensionCacheID pPropertyToSearch, pValue end repeat end __extensionCacheID +private command __extensionCacheRemove pIndex + delete variable sExtensions[pIndex] +end __extensionCacheRemove + # Gets a property from the internal extension cache function __extensionPropertyGet pCacheIndex, pProperty return sExtensions[pCacheIndex][pProperty] @@ -942,60 +974,205 @@ private command __extensionLoad pID, pExtensionDataA # Only try to load the first copy in the load order put pExtensionDataA["copies"][1] into tToLoadA - local tFolder, tVersion, tStatus, tError, tIDEExtension + local tFolder, tVersion, tStatus, tError, tIDEExtension, tSourceFile, tSourceType put tToLoadA["install_path"] into tFolder put tToLoadA["version"] into tVersion put tToLoadA["status"] into tStatus put tToLoadA["error"] into tError put tToLoadA["ide"] into tIDEExtension - revIDEExtensionLoad pID, tFolder, tVersion, tStatus, tError, tIDEExtension + put tToLoadA["source_file"] into tSourceFile + put tToLoadA["source_type"] into tSourceType + revIDEExtensionLoad tSourceType, pID, tFolder, tVersion, tStatus, \ + tError, tIDEExtension, tSourceFile, tToLoadA, true end __extensionLoad -command revIDEExtensionLoad pID, pFolder, pVersion, pStatus, pError, pIDEExtension - local tStatus, tError - if pError is empty then - local tResources, tModule - put pFolder & slash & "resources" into tResources - put pFolder & slash & "module.lcm" into tModule - # If we have a resources folder then load with resource path - if there is a folder tResources then - load extension from file tModule with resource path tResources - else - load extension from file tModule +private command __MapCodeLibraryForIDE pFolder + local tLibraries + if revEnvironmentIsInstalled() and \ + pFolder begins with revEnvironmentToolsPath() and \ + the platform is "MacOS" then + -- special case bundled extensions must load code from within MacOS dir + -- the libs to load should be in Contents/MacOS/<extension>/ + local tExtension + set the itemDelimiter to slash + put item -2 of pFolder into tExtension + + put files(specialFolderPath("engine") & "/" & tExtension) & return & \ + folders(specialFolderPath("engine") & "/" & tExtension) into tLibraries + filter tLibraries without ".*" + + if tLibraries is not empty then + set the itemDelimiter to "." + repeat for each line tLibrary in tLibraries + -- remove extension + delete the last item of tLibrary + if tLibrary is not empty then + set the revLibraryMapping[tLibrary] to "./" & tExtension & "/" & tLibrary + return empty + end if + end repeat end if - if the result is not empty then - put toUpper(char 1 of the result) & char 2 to -1 of the result into tError - put "error" into tStatus + end if + + -- code folders should be platform ID triples however for the + -- time being as we have no way to access the data required to + -- determine the options section of the platform ID so we filter only + -- arch and platform and hope for the best. Ideally we would have + -- access to a build options string and give a complete match precedence. + local tCodeFolders + put folders(pFolder) into tCodeFolders + switch the platform + case "MacOS" + filter tCodeFolders with "*-mac*" + break + case "Win32" + filter tCodeFolders with "*-win32*" + break + default + filter tCodeFolders with "*-"& toLower(the platform) & "*" + break + end switch + + local tFilteredCodeFolders + filter tCodeFolders with the processor & "-*" into tFilteredCodeFolders + split tFilteredCodeFolders by return as set + if the platform is "MacOS" then + -- explicit processor should take precedence over universal builds but + -- in the event multiple libraries are included and some are universal + -- we must merge + local tUniveralFilteredCodeFolders + filter tCodeFolders with "universal-*" into tUniveralFilteredCodeFolders + split tUniveralFilteredCodeFolders by return as set + union tFilteredCodeFolders with tUniveralFilteredCodeFolders + end if + + repeat for each key tFolder in tFilteredCodeFolders + put files(pFolder & "/" & tFolder) & return & \ + folders(pFolder & "/" & tFolder) into tLibraries + filter tLibraries without ".*" + + if tLibraries is not empty then + set the itemDelimiter to "." + repeat for each line tLibrary in tLibraries + -- remove extension + delete the last item of tLibrary + if tLibrary is not empty then + set the revLibraryMapping[tLibrary] to pFolder & "/" & tFolder & "/" & tLibrary + end if + end repeat + end if + end repeat +end __MapCodeLibraryForIDE + +private command __LoadExtension pCacheIndex, pExtensionType, pSourceType, \ + pSourceFile, pFolder, pStatus, @xError + revInternal__Log "Message", the params + if xError is empty then + local tFileToLoad + if not __extensionNeedsLoad(pExtensionType) then + put "installed" into pStatus else - put "installed" into tStatus + if pSourceType is "lcb" then + local tResources, tModule, tCode + put revIDEExtensionBytecodeFilename(true) into tFileToLoad + put pFolder & slash & tFileToLoad into tModule + if there is no file tModule then + put revIDEExtensionBytecodeFilename(false) into tFileToLoad + put pFolder & slash & tFileToLoad into tModule + end if + put pFolder & slash & "resources" into tResources + put pFolder & slash & "code" into tCode + # map code before loading extension + if there is a folder tCode then + __MapCodeLibraryForIDE tCode + end if + # If we have a resources folder then load with resource path + if there is a folder tResources then + load extension from file tModule with resource path tResources + else + load extension from file tModule + end if + else + set the itemdelimiter to "." + revInternal__LoadLibrary item 1 of pSourceFile, pFolder & slash & pSourceFile + put pSourceFile into tFileToLoad + end if + if the result is not empty then + put toUpper(char 1 of the result) & \ + char 2 to -1 of the result into xError + put "error" into pStatus + else + put "installed" into pStatus + end if end if - else - put pStatus into tStatus - put pError into tError end if - + __extensionPropertySet pCacheIndex, "status", pStatus + __extensionPropertySet pCacheIndex, "error", xError + __extensionPropertySet pCacheIndex, "file", tFileToLoad + __extensionsChanged +end __LoadExtension + +private command __revIDELCBExtensionLoad pID, pFolder, pVersion, pStatus, \ + pError, pIsIDEExtension, pSourceFile, pAdditionalInfoA, pIsStartup # Find entry in the cache if it exists local tCacheIndex put __extensionCacheID("install_path", pFolder) into tCacheIndex - # If no extry is in the cache, create one + # If no entry is in the cache, create one if tCacheIndex is not a number then put the number of elements of sExtensions + 1 into tCacheIndex __extensionPropertySet tCacheIndex, "install_path", pFolder end if + local tSupportFiles + put pAdditionalInfoA["support_files"] into tSupportFiles + local tLoadOnStartup + if pError is empty then + put pAdditionalInfoA["_ide"] is true or \ + revIDEExtensionGetLoadOnStartup(pID) into tLoadOnStartup + end if + if not pIsStartup or tLoadOnStartup is not false then + __LoadExtension tCacheIndex, pAdditionalInfoA["type"], "lcb", pSourceFile, \ + pFolder, pStatus, pError + -- If we have an error loading, try to recompile the extension + if pError is not empty then + if not pIsIDEExtension and pSourceFile is not empty then + revIDEExtensionCompile pFolder, pSourceFile, tSupportFiles, pFolder, \ + revIDEExtensionBytecodeFilename(true) + if the result is empty then + local tNewError + __LoadExtension tCacheIndex, pAdditionalInfoA["type"], "lcb", \ + pSourceFile, pFolder, pStatus, tNewError + put tNewError into pError + end if + end if + end if + else + __extensionPropertySet tCacheIndex, "status", "unloaded" + end if + # Update name, status, error, and whether the extension comes with the IDE __extensionPropertySet tCacheIndex, "name", pID __extensionPropertySet tCacheIndex, "type_id", pID & "." & pVersion - __extensionPropertySet tCacheIndex, "status", tStatus - __extensionPropertySet tCacheIndex, "error", tError - __extensionPropertySet tCacheIndex, "ide", pIDEExtension + __extensionPropertySet tCacheIndex, "ide", pIsIDEExtension + __extensionPropertySet tCacheIndex, "source_file", pSourceFile + __extensionPropertySet tCacheIndex, "source_type", "lcb" + __extensionPropertySet tCacheIndex, "support_files", tSupportFiles - # Store the extension's property metadata + # Check for sample stacks + __extensionPropertySet tCacheIndex, "samples", __extensionSampleStacks(pID,pFolder) + + # Store the extension's metadata revIDEExtensionSetInfo pID + local tUserVisiblePref + put revIDEGetPreferenceOfSet(pID, "uservisible") into tUserVisiblePref + if tUserVisiblePref is not empty then + __extensionPropertySet tCacheIndex, "uservisible", tUserVisiblePref + end if + # Deal with the various icon possibilities - if sExtensionProperties[pID]["svgIconPath"] is empty then + if sExtensionProperties[pID]["svgicon"] is empty then local tIconPath put pFolder & "/support/icon.png" into tIconPath if there is a file tIconPath then @@ -1011,10 +1188,165 @@ command revIDEExtensionLoad pID, pFolder, pVersion, pStatus, pError, pIDEExtensi # Generate extension API from source if there is not one present in the folder # Don't do in an installed IDE as we might not be able to generate the files in the appropriate location if not revEnvironmentIsInstalled() and not there is a file (pFolder & slash & "api.lcdoc") then - revIDEExtensionUpdateAPI pFolder + revIDEExtensionUpdateAPI pFolder, pSourceFile + end if + + return pError +end __revIDELCBExtensionLoad + +private command addToStringList @xList, pValue, pDel + if pDel is empty then put return into pDel + if xList is empty then + put pValue into xList + else + put pDel & pValue after xList + end if +end addToStringList + +private function __UseTypeToKey pUseType + switch pUseType + case "android permission" + return "android.permissions" + case "android feature" + return "android.features" + end switch +end __UseTypeToKey + +private function __extensionHasID pType + switch pType + case "snippet" + return false + default + return true + end switch +end __extensionHasID + +private function __extensionNeedsLoad pType + switch pType + case "snippet" + case "sample" + return false + default + return true + end switch +end __extensionNeedsLoad + +private command __revIDELCSExtensionLoad pFullPath, pFolder, pVersion, pStatus, \ + pError, pIsIDEExtension, pSourceFile, pAdditionalInfoA, pIsStartup + + # Find entry in the cache if it exists + local tCacheIndex + put __extensionCacheID("install_path", pFolder) into tCacheIndex + + # If no entry is in the cache, create one + if tCacheIndex is not a number then + put the number of elements of sExtensions + 1 into tCacheIndex + __extensionPropertySet tCacheIndex, "install_path", pFolder + end if + + if pAdditionalInfoA is empty then + put __fetchExtensionManifestData(pFolder, pSourceFile) into pAdditionalInfoA + end if + + local tType + put pAdditionalInfoA["type"] into tType + + # Update name, status, error, and whether the extension comes with the IDE + local tId + if __extensionHasID(tType) then + try + put the short name of stack (pFolder & slash & pSourceFile) into tId + catch pError + end try + else + # The manifest should contain an id + put pAdditionalInfoA["name"] into tId + end if + + local tLoadOnStartup + if pError is empty and __extensionNeedsLoad(tType) then + put revIDEExtensionGetLoadOnStartup(tID) into tLoadOnStartup + end if + if not pIsStartup or (tLoadOnStartup is not false) then + __LoadExtension tCacheIndex, tType, "lcs", pSourceFile, pFolder, pStatus, pError + else + __extensionPropertySet tCacheIndex, "status", "unloaded" end if - return tError + __extensionPropertySet tCacheIndex, "name", tId + __extensionPropertySet tCacheIndex, "type_id", tId & "." & pVersion + + __extensionPropertySet tCacheIndex, "author", pAdditionalInfoA["author"] + __extensionPropertySet tCacheIndex, "title", pAdditionalInfoA["title"] + __extensionPropertySet tCacheIndex, "svgicon", pAdditionalInfoA["svgicon"] + __extensionPropertySet tCacheIndex, "version", pAdditionalInfoA["version"] + + repeat for each key tKey in pAdditionalInfoA["uses"] + local tSettingString + put empty into tSettingString + -- store info about settings (android permissions etc) + repeat for each element tSetting in pAdditionalInfoA["uses"][tKey] + addToStringList tSettingString, tSetting, "," + end repeat + __extensionPropertySet tCacheIndex, __UseTypeToKey(tKey), tSettingString + end repeat + + __extensionPropertySet tCacheIndex, "source_file", pSourceFile + __extensionPropertySet tCacheIndex, "ide", pIsIDEExtension + __extensionPropertySet tCacheIndex, "source_type", "lcs" + __extensionPropertySet tCacheIndex, "type", pAdditionalInfoA["type"] + __extensionPropertySet tCacheIndex, "uservisible", true + __extensionPropertySet tCacheIndex, "support_files", pAdditionalInfoA["support_files"] + + # Store the extension's property metadata + -- revIDEExtensionSetInfo pID + + # Deal with the various icon possibilities + if sExtensionProperties[tID]["svgicon"] is empty then + local tIconPath + put pFolder & "/support/icon.png" into tIconPath + if there is a file tIconPath then + __extensionPropertySet tCacheIndex, "icon", tIconPath + end if + end if + + # If this is not startup, then auto-launch snippet or sample stack + if not pIsStartup then + if tType is "snippet" then + revIDEExtensionShowSnippet pFolder & slash & pSourceFile + else if tType is "sample" then + revIDEExtensionOpenSample pFolder & slash & pSourceFile + end if + end if + return pError +end __revIDELCSExtensionLoad + +command revIDEExtensionReload pTypeId + local tCacheIndex + put __extensionCacheID("name", pTypeID) into tCacheIndex + if tCacheIndex is not a number then + answer error "Can't reload" && pTypeID & ": restart required" + exit revIDEExtensionReload + end if + local tError, tDataA + put sExtensions[tCacheIndex] into tDataA + __LoadExtension tCacheIndex, tDataA["type"], tDataA["source_type"], \ + tDataA["source_file"], tDataA["install_path"], \ + "", tError + if tError is not empty then + answer error tError + end if +end revIDEExtensionReload + +command revIDEExtensionLoad pType, pID, pFolder, pVersion, pStatus, pError, \ + pIDEExtension, pSourceFile, pAdditionalInfoA, pIsStartup + if pType is "lcb" then + __revIDELCBExtensionLoad pID, pFolder, pVersion, pStatus, pError, \ + pIDEExtension, pSourceFile, pAdditionalInfoA, pIsStartup + else if pType is "lcs" then + __revIDELCSExtensionLoad pID, pFolder, pVersion, pStatus, pError, \ + pIDEExtension, pSourceFile, pAdditionalInfoA, pIsStartup + end if end revIDEExtensionLoad function revIDEExtensionFetchDefaultScript pFolder, pCacheIndex, pValidate @@ -1052,70 +1384,21 @@ function revIDEExtensionFetchDefaultScript pFolder, pCacheIndex, pValidate return tScript end revIDEExtensionFetchDefaultScript -function __extensionManifestValue pCacheIndex, pProperty - # Get the path to the package file - local tExtensionPackageFile - put __extensionPropertyGet(pCacheIndex, "download_package_path") into tExtensionPackageFile - - if not there is a file tExtensionPackageFile then return __extensionError(pCacheIndex,"Could not extract manifest because package was not found in downloads folder") - - # A zip can come compressed with a base folder or without. So work out what the - # root folder is before trying to extract files - revZipOpenArchive tExtensionPackageFile, "read" +function __extensionSampleStacks pID, pFolder + local tSampleFolder, tSamples, tSampleArray - local tZipItems, tZipRoot - put revZipEnumerateItems(tExtensionPackageFile) into tZipItems - - if the last char of line 1 of tZipItems is "/" then - put line 1 of tZipItems into tZipRoot - else - put empty into tZipRoot - end if - - # Extract the package manfiest to a variable to read key data - local tManifestData, tManifestXMLTree, tValue - revZipExtractItemToVariable tExtensionPackageFile, (tZipRoot & "manifest.xml"), "tManifestData" - - revZipCloseArchive tExtensionPackageFile - - put revXMLCreateTree(tManifestData,true,true,false) into tManifestXMLTree - put revXMLNodeContents(tManifestXMLTree,"/package/" & pProperty) into tValue - if tValue begins with "xmlerr" then - return empty - else - return tValue - end if -end __extensionManifestValue - -function __extensionManifestValueFromFile pCacheIndex, pProperty - # Get the path to the manifest file - local tExtensionInstallPath, tManifestFilepath - put __extensionPropertyGet(pCacheIndex, "install_path") into tExtensionInstallPath - put tExtensionInstallPath & slash & "manifest.xml" into tManifestFilepath - - if not there is a file tManifestFilepath then - local tError - put "Could not get extension manifest information: " into tError - put "extension folder does not contain a manifest file" after tError - return __extensionError(pCacheIndex,tError) + # Get the paths to sample satcks in the bundle + put pFolder & slash & "samples" into tSampleFolder + if there is a folder tSampleFolder then + put files(tSampleFolder) into tSamples + filter tSamples without ".*" + repeat for each line tStack in tSamples + put pFolder & slash & "samples/" & tStack into tSampleArray[tStack] + end repeat end if - # Extract the package manfiest to a variable to read key data - local tManifestXMLTree, tValue - - put revXMLCreateTreeFromFile(tManifestFilepath,true,true,false) into tManifestXMLTree - put revXMLNodeContents(tManifestXMLTree,"/package/" & pProperty) into tValue - if tValue begins with "xmlerr" then - return empty - else - return tValue - end if -end __extensionManifestValueFromFile - -# Returns a value from the manifest -//private on __extensionManifestValue pCacheIndex, pManifestKey -//end __extensionManifestValue - + return tSampleArray +end __extensionSampleStacks ############################## # CALLBACKS @@ -1124,15 +1407,40 @@ end __extensionManifestValueFromFile on extensionUpdateDataReceived end extensionUpdateDataReceived -function revIDEExtensionDocsData +-- At the moment, if the extension is of type module then assume +-- it provides an LCB API, and otherwise it provides an LCS API. +private function __TypeToAPI pType + switch pType + case "module" + return "livecode_builder" + break + case "plugin" + return "livecode_ide" + break + case "library" + case "widget" + default + return "livecode_script" + break + end switch +end __TypeToAPI + +function revIDEExtensionDocsData pForAPI local tExtensionsA put revIDEExtensions("", "installed", true) into tExtensionsA local tDataA, tCount repeat for each element tExtension in tExtensionsA + if pForAPI is not empty and \ + __TypeToAPI(tExtension["type"]) is not pForAPI then + next repeat + end if add 1 to tCount put tExtension["install_path"] into tDataA[tCount]["folder"] put tExtension["title"] into tDataA[tCount]["title"] put tExtension["author"] into tDataA[tCount]["author"] + put tExtension["source_file"] into tDataA[tCount]["source_file"] + put tExtension["source_type"] into tDataA[tCount]["source_type"] + put tExtension["name"] into tDataA[tCount]["name"] end repeat return tDataA end revIDEExtensionDocsData @@ -1140,158 +1448,126 @@ end revIDEExtensionDocsData on revIDEExtensionUpdateAPI pFolder, pExtensionSource if pExtensionSource is empty then local tFiles - revIDEPushDefaultFolder pFolder - put the files into tFiles + put files(pFolder) into tFiles filter tFiles with "*.lcb" if tFiles is empty then exit revIDEExtensionUpdateAPI put line 1 of tFiles into pExtensionSource - revIDEPopDefaultFolder end if # Check timestamps to see if API is out of date. - local tNeedUpdate, tError - put revIDEIsFilesetStale(pFolder & slash & pExtensionSource, \ - pFolder & slash & "api.lcdoc", false, tError) into tNeedUpdate + local tNeedUpdate, tError, tSource + put pFolder & slash & pExtensionSource into tSource + put revIDEIsFilesetStale(tSource, \ + pFolder & slash & "api.lcdoc", false, tError) into tNeedUpdate if tNeedUpdate is empty then put true into tNeedUpdate if tNeedUpdate then + local tText + if there is a stack tSource then + put the long id of stack tSource into tSource + put the script of stack tSource into tText + else + put textDecode(url("binfile:" & tSource), "utf-8") into tText + end if + local tAPI - dispatch function "revDocsGenerateDocsFileFromModularFile" to stack "revDocsParser" with (pFolder & slash & pExtensionSource) + dispatch function "revDocsGenerateDocsFileFromText" to stack "revDocsParser" with tText, tSource put the result into tAPI put textEncode(tAPI, "utf-8") into url ("binfile:" & pFolder & slash & "api.lcdoc") return "updated" end if end revIDEExtensionUpdateAPI -private on revIDEExtensionFetchMetadata pManifestPath, @rDataA - local tDataA - - local tManifestContents, tTreeID - put url ("file:" & pManifestPath) into tManifestContents - put revXMLCreateTree(tManifestContents,true,true,false) into tTreeID - - if tTreeID begins with "xmlerr" then - return "Error: invalid xml in manifest" - end if - - local tTargetType - put textDecode(revXMLNodeContents(tTreeID, "/package/type"), "utf-8") into tTargetType - - if tTargetType begins with "xmlerr" then - return "Error: no type found in manifest" - end if - put tTargetType into tDataA["type"] - - local tTargetName - put textDecode(revXMLNodeContents(tTreeID, "/package/name"), "utf-8") into tTargetName - if tTargetName begins with "xmlerr" then - return "Error: couldn't retrieve extension name from manifest" - end if - put tTargetName into tDataA["name"] - - local tTargetTitle - put textDecode(revXMLNodeContents(tTreeID, "/package/title"), "utf-8") into tTargetTitle - - if tTargetTitle is empty or tTargetTitle begins with "xmlerr" then - put empty into tTargetTitle - end if - put tTargetTitle into tDataA["title"] - - local tTargetVersion - put textDecode(revXMLNodeContents(tTreeID, "/package/version"), "utf-8") into tTargetVersion - - if tTargetVersion is empty or tTargetVersion begins with "xmlerr" then - put empty into tTargetVersion - end if - put tTargetVersion into tDataA["version"] - - local tTargetAuthor - put textDecode(revXMLNodeContents(tTreeID, "/package/author"), "utf-8") into tTargetAuthor - if tTargetAuthor is empty or tTargetAuthor begins with "xmlerr" then - put empty into tTargetAuthor - end if - put tTargetAuthor into tDataA["author"] - - # Fetch property metadata - local tMetadataValue, tMetadataKey - local tMetadataNodes, tMetadataA, tKeys, tValue - put revXMLChildNames(tTreeID, "package",return,"metadata",true) into tMetadataNodes - repeat for each line tMetadata in tMetadataNodes - put revXMLAttribute(tTreeID,"package" & "/" & tMetadata,"key") into tMetadataKey - put revXMLNodeContents(tTreeID,"package" & "/" & tMetadata) into tMetadataValue - if tMetadataValue is empty or tMetadataValue begins with "xmlerr" then - put empty into tMetadataValue - end if - put tMetadataValue into tDataA[tMetadataKey] +command revIDEExtensionCompile pFolder, pFile, pSupportFiles, pTargetFolder, pOutputFilename + // Make file paths full paths + repeat with tLine = 1 to the number of lines in pSupportFiles + put pFolder & slash before line tLine of pSupportFiles end repeat + put pFolder & slash before pFile - # Fetch extension dependencies - local tRequires, tCount - put 0 into tCount - put revXMLChildNames(tTreeID,"package",return,"requires",true) into tRequires - repeat for each line tDependency in tRequires - add 1 to tCount - local tName - put revXMLAttribute(tTreeID,"package" & "/" & tDependency,"name") into tName - put tName into tDataA["requires"][tCount] - end repeat + extensionCompile "", pFile, pSupportFiles, "", \ + revIDESpecialFolderPath("user extensions") & slash & \ + "interface", pTargetFolder, pOutputFilename - # Fetch library handlers - if tTargetType is "library" then - local tHandlerList, tHandlerNodes - put revXMLChildNames(tTreeID, "package",return,"handler",true) into tHandlerNodes - repeat for each line tHandler in tHandlerNodes - local tHandlerName - put revXMLAttribute(tTreeID,"package" & "/" & tHandler,"name") into tHandlerName - - if tHandlerName is empty or tHandlerName begins with "xmlerr" then - next repeat - end if - - if tHandlerList is empty then - put tHandlerName into tHandlerList - else - put return & tHandlerName after tHandlerList - end if - end repeat - put tHandlerList into tDataA["handlers"] + if the result is not empty then + return the result for error end if + return it for value +end revIDEExtensionCompile + +command revIDEExtensionMetadata pFolder, pFile, pType, @rDataA + local tDataA, tResult + revIDEExtensionFetchMetadata pFolder & slash & "manifest.xml", tDataA + put the result into tResult - # User visible should default to true - if tDataA["uservisible"] is empty then - put true into tDataA["uservisible"] + put tDataA into rDataA + return tResult +end revIDEExtensionMetadata + +private command __SetMetadata pKey, pValue, @xArray + split pKey by "." + put pValue into xArray[pKey] +end __SetMetadata + +private command revIDEExtensionFetchMetadata pManifestPath, @rDataA + local tDataA + put extensionFetchMetadata(pManifestPath) into tDataA + if the result is not empty then + return the result end if + # Make sure 'inspector' style metadata is processed + __ProcessInspectorMetadata tDataA["standaloneSettings"] + put tDataA into rDataA return empty end revIDEExtensionFetchMetadata -function revIDEExtensionModuleFile pKind +function revIDEExtensionFileData pID # Get the internal cache index local tCacheIndex - put __extensionCacheID("name", pKind) into tCacheIndex + put __extensionCacheID("name", pID) into tCacheIndex - return __extensionPropertyGet(tCacheIndex, "install_path") & slash & "module.lcm" -end revIDEExtensionModuleFile - -command revIDEExtensionUnload pKind - local tCacheIndex - put __extensionCacheID("name", pKind) into tCacheIndex + local tSourceType, tFolder, tFile + put __extensionPropertyGet(tCacheIndex, "install_path") into tFolder + put __extensionPropertyGet(tCacheIndex, "source_type") into tSourceType + put __extensionPropertyGet(tCacheIndex, "file") into tFile - local tCopies - put __extensionPropertyGet(tCacheIndex, "copies") into tCopies - if the number of elements in tCopies <= 1 then - delete variable sExtensions[tCacheIndex] + local tDataA + put tSourceType into tDataA["type"] + put tFolder & slash & tFile into tDataA["file"] + return tDataA +end revIDEExtensionFileData + +private command __UnloadExtension pCacheIndex, pSourceType, pSourceFile, pTypeId + local tError, tStatus + if pSourceType is "lcb" then + unload extension pTypeId else - __extensionPropertySet tCacheIndex, "status", "uninstalled" + set the itemdelimiter to "." + revInternal__UnloadLibrary item 1 of pSourceFile end if - - # Check if it's loaded - if pKind is among the lines of the loadedExtensions then - unload extension pKind + if the result is not empty then + put toUpper(char 1 of the result) & \ + char 2 to -1 of the result into tError + put "error" into tStatus + else + put "unloaded" into tStatus end if - return the result + __extensionPropertySet pCacheIndex, "status", tStatus + __extensionPropertySet pCacheIndex, "error", tError + __extensionsChanged +end __UnloadExtension + +command revIDEExtensionUnload pKind + local tCacheIndex + put __extensionCacheID("name", pKind) into tCacheIndex + + local tDataA + put sExtensions[tCacheIndex] into tDataA + __UnloadExtension tCacheIndex, tDataA["source_type"], \ + tDataA["source_file"], pKind end revIDEExtensionUnload function revIDEExtensionLibraryHandlers pLibraryID @@ -1300,3 +1576,74 @@ function revIDEExtensionLibraryHandlers pLibraryID return __extensionPropertyGet(tCacheIndex, "handlers") end revIDEExtensionLibraryHandlers + +command revIDEExtensionIconFromType pType, pID, @rIconName, @rIconPath + put revIDEExtensionProperty(pID, "svgIcon") into rIconPath + switch pType + case "widget" + put "wrench" into rIconName + break + case "library" + put "book" into rIconName + break + case "external" + put "external link" into rIconName + break + case "inclusion" + case "resource" + put "puzzle piece" into rIconName + break + case "database driver" + put "database" into rIconName + break + case "script library" + put "file text alt" into rIconName + break + default + put "circle" into rIconName + break + end switch +end revIDEExtensionIconFromType + +command revIDEExtensionShowSnippet pSourceFile + local tSnippet + put revIDEUTF8FileContents(pSourceFile) into tSnippet + lock screen + revIDEOpenPalette("snippet viewer") + dispatch "revIDESnippetViewerSetSnippet" to stack \ + revIDEPaletteToStackName("snippet viewer") with tSnippet + unlock screen +end revIDEExtensionShowSnippet + +local sSampleFileName +local sOpenedStacksA +on ideOpenStack pCard + local tStack + put the long id of the owner of pCard into tStack + if tStack is the long id of stack sSampleFileName then + ## Clear the filename to force the user to choose save location if saving the stack + put the short name of tStack into sOpenedStacksA[sSampleFileName] + set the filename of tStack to empty + put empty into sSampleFileName + revIDEUnsubscribe "ideOpenStack" + end if +end ideOpenStack + +command revIDEExtensionLaunchSampleStack pSampleStack + // Check if the sample stack has already been opened, + // i.e. if its name is mapped in the array. If so, just + // open it. + if there is a stack (sOpenedStacksA[pSampleStack]) then + open stack sOpenedStacksA[pSampleStack] + exit revIDEExtensionLaunchSampleStack + end if + + // Otherwise open the stack from the file. Wait until we + // get the openStack message before emptying the filename + // otherwise we will get a long id clash + revIDESubscribe "ideOpenStack" + put pSampleStack into sSampleFileName + + ## Open the sample stack + open stack pSampleStack +end revIDEExtensionLaunchSampleStack diff --git a/Toolset/libraries/revidelibrary.8.livecodescript b/Toolset/libraries/revidelibrary.8.livecodescript index 29e8109d1a..aaa787601d 100644 --- a/Toolset/libraries/revidelibrary.8.livecodescript +++ b/Toolset/libraries/revidelibrary.8.livecodescript @@ -20,214 +20,27 @@ References: revIDESubscribe (command) /** Called when loading the IDE library **/ -on revLoadLibrary - if the target is me then - insert the script of me into back +on extensionInitialize + if the target is not me then + pass extensionInitialize end if + + insert the script of me into back revIDEInitialiseIDELibrary -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary - if the target is me then - remove the script of me from back +on extensionFinalize + if the target is not me then + pass extensionFinalize end if -end revUnloadLibrary + + remove the script of me from back + revIDEFinaliseIDELibrary +end extensionFinalize ############# # Internal functions ############# -# Reads all the of the extension files into an internal array which is then used by all revIDEExtension and revIDEWidget -# type functions - -local sExtensionData -local sExtensionDataForDisplay - -private on __loadExtensions - local tInactiveExtensionFolder, tExtensionData - - put empty into sExtensionData - put empty into sExtensionDataForDisplay - - ## Load installed extensions - revIDEPushDefaultFolder revIDESpecialFolderPath("extensions") - repeat for each line tFile in the files - if char 1 of tFile is "." then next repeat - __loadExtension tFile - end repeat - - revIDEPopDefaultFolder - dispatch "ideExtensionsChanged" -end __loadExtensions - -private command __loadExtension pExtensionFile - local tExtensionID, tExtensionPackageData, tIndex, tKeys - local tExtractedExtensionFolder - - put char 1 to -5 of pExtensionFile into tExtensionID - put revIDESpecialFolderPath("extensions") into tExtractedExtensionFolder - - ## Check if already extracted - if there is not a folder (tExtractedExtensionFolder & "/" & pExtensionFile) then - __extractExtension(revIDESpecialFolderPath("extensions") & "/" & pExtensionFile) - end if - - # Try to load the extension - local tExecutableModuleFile - put revIDESpecialFolderPath("extensions") & slash & tExtensionID & slash & "module.lcm" into tExecutableModuleFile - if there is a file tExecutableModuleFile then - load extension from file tExecutableModuleFile - if the result is not empty then - __revIDEError("loading extension failed: " && the result) - return empty - end if - end if - - ## Check if already loaded - if tExtensionID is not among the keys of sExtensionData then - put the keys of sExtensionDataForDisplay into tKeys - replace return with comma in tKeys - put max(tKeys) + 1 into tIndex - - ## Extract the extension - --put __extractExtension(revIDESpecialFolderPath("extensions") & "/" & pExtensionFile) into tExtensionPackageData - put __extensionData(tExtensionID) into tExtensionPackageData - - local tExtenstionTypeID - put tExtensionPackageData["name"] into tExtenstionTypeID - put tExtensionPackageData into sExtensionData[tExtenstionTypeID] - put tExtensionPackageData into sExtensionDataForDisplay[tIndex] - put "active" into sExtensionData[tExtenstionTypeID]["status"] - put "active" into sExtensionDataForDisplay[tIndex]["status"] - end if -end __loadExtension - -private function __extensionData pExtensionID - local tExtractedExtensionFolder, tExtensionFolder, tManifest, tXMLTree, tExtensionData - local tIsWidget, tIsLibrary, tRequiredNodes - - put revIDESpecialFolderPath("extensions") into tExtractedExtensionFolder - put tExtractedExtensionFolder & "/" & pExtensionID into tExtensionFolder - - if there is not a folder tExtensionFolder then return empty - - ## Manifest - put url ("file:" & tExtensionFolder & "/manifest.xml") into tManifest - if tManifest is empty then return empty - - put revXMLCreateTree(tManifest,true,true,false) into tXMLTree - put revXMLNodeContents(tXMLTree,"/package/name") into tExtensionData["name"] - put revXMLNodeContents(tXMLTree,"/package/title") into tExtensionData["label"] - put revXMLNodeContents(tXMLTree,"/package/description") into tExtensionData["description"] - put revXMLNodeContents(tXMLTree,"/package/author") into tExtensionData["author"] - put revXMLNodeContents(tXMLTree,"/package/version") into tExtensionData["version"] - put revXMLNodeContents(tXMLTree,"/package/license") into tExtensionData["license"] - - if item 1 of tExtensionData["author"] is "xmlerr" then - put empty into tExtensionData["author"] - end if - - ## Type - put revXMLChildNames(tXMLTree,"package",return,"widget",false) into tIsWidget - put revXMLChildNames(tXMLTree,"package",return,"library",false) into tIsLibrary - - if tIsWidget is "widget" then put "widget" into tExtensionData["type"] - else if tIsLibrary is "library" then put "library" into tExtensionData["type"] - else put "widget" into tExtensionData["type"] - - ## Requirements - put revXMLChildNames(tXMLTree,"package",return,"requires",true) into tRequiredNodes - repeat with x = 1 to the number of lines in tRequiredNodes - put revXMLAttribute(tXMLTree,"package" & "/" & line x of tRequiredNodes,"name") into tExtensionData["requires"][x]["name"] - put revXMLAttribute(tXMLTree,"package" & "/" & line x of tRequiredNodes,"version") into tExtensionData["requires"][x]["version"] - end repeat - - revXMLDeleteTree tXMLTree - - put (tExtensionFolder & "/manifest.xml") into tExtensionData["manifest_path"] - - ## Icons - if there is a file (tExtensionFolder & "/icon.png") then put (tExtensionFolder & "/icon.png") into tExtensionData["icon"] - - ## Guide - if there is a file (tExtensionFolder & "/guide.md") then put (tExtensionFolder & "/guide.md") into tExtensionData["guide"] - - ## API - if there is a file (tExtensionFolder & "/api.lcdoc") then put (tExtensionFolder & "/api.lcdoc") into tExtensionData["api"] - return tExtensionData -end __extensionData - -private command __extractExtension pFilename - local tManifest, tExtensionData, tIcon, tFileRoot, tIdentifier, tXMLTree, tRequiredNodes, tType - local tIsWidget, tIsLibrary, tItems - - if char -3 to -1 of pFilename is not "lce" then return __revIDEError("The file" && pFilename && "is not a valid LiveCode Extension file.") - - local tNewFolderName - set the itemDel to "/" - put char 1 to -5 of item -1 of pFilename into tNewFolderName - revZipOpenArchive pFilename, "read" - - local tZipItems - put revZipEnumerateItems(pFilename) into tZipItems - if the last char of line 1 of tZipItems is "/" then - put line 1 of tZipItems into tFileRoot - else - put empty into tFileRoot - end if - - ## Extract Extension files - local tExtensionsFolder, tUnzippedExtensionFolder, tIconFile, tLargeIconFile - put revIDESpecialFolderPath("extensions") into tExtensionsFolder - put tExtensionsFolder & "/" & tNewFolderName into tUnzippedExtensionFolder - - if there is not a folder tUnzippedExtensionFolder then - revIDEEnsurePath tUnzippedExtensionFolder - end if - - ## Manifest - local tManifestPath - put tUnzippedExtensionFolder & "/manifest.xml" into tManifestPath - revZipExtractItemToFile pFilename, (tFileRoot & "manifest.xml"), tManifestPath - - ## Icon files - put tUnzippedExtensionFolder & "/icon.png" into tIconFile - revZipExtractItemToFile pFilename, (tFileRoot & "support/icon.png"), tIconFile - - ## Extract any other icon files - local tUnzippedIconFile - put revZipEnumerateItems(pFilename) into tItems - filter tItems with "*icon*" - repeat for each line tIcon in tItems - put tUnzippedExtensionFolder & "/" & item -1 tIcon into tUnzippedIconFile - revZipExtractItemToFile pFilename, tIcon, tUnzippedIconFile - end repeat - - ## Documentaion - - ## Guide - local tGuidePath - put tUnzippedExtensionFolder & "/guide.md" into tGuidePath - revZipExtractItemToFile pFilename, (tFileRoot & "docs/guide/guide.md"), tGuidePath - ##-- Rebuild user guide JSON - - ## API - local tAPIPath - put tUnzippedExtensionFolder & "/api.lcdoc" into tAPIPath - revZipExtractItemToFile pFilename, (tFileRoot & "docs/api/api.lcdoc"), tAPIPath - -- put tAPIPath into tExtensionData["api"] - - ## Executable Module File - revZipExtractItemToFile pFilename, (tFileRoot & "module.lcm"), tUnzippedExtensionFolder & "/module.lcm" - - revZipCloseArchive pFilename -end __extractExtension - -private function __trimZippedData pString - if codepointToNum(the last char of pString) < 32 then - delete the last char of pString - end if - return pString -end __trimZippedData # Reads in all the tool data local sToolDefinition @@ -461,7 +274,7 @@ private function __classicObjectPropertiesFromType pType switch the last item of pType case "Card" case "Stack" - case "DataGrid" + case "Substack" return sClassicObjectProperties[pType] default if not (pType begins with "com.livecode.interface.classic") then @@ -550,6 +363,11 @@ private on __setPropertyDataOfObjectFromFile pObjectType, pFile, pPropInfoA add 1 to tCountsA[tSection][tGroupLabel]["count"] put tCountsA[tSection][tGroupLabel]["count"] into pPropInfoA[tPropertyName]["order"] + -- Put 'control properties' last + -- TODO: there should be a more transparent way of ordering these + if pObjectType is "com.livecode.interface.Control" then + add 1000 to pPropInfoA[tPropertyName]["group_order"] + end if put pPropInfoA[tPropertyName] into sClassicObjectProperties[pObjectType]["properties"][tPropertyName] put pPropInfoA[tPropertyName] into tObjectPropertiesA[tPropertyName] @@ -559,11 +377,11 @@ private on __setPropertyDataOfObjectFromFile pObjectType, pFile, pPropInfoA end __setPropertyDataOfObjectFromFile private function __propertyInfoFilename - return "propertyInfo.txt" + return "propertyInfo.tsv" end __propertyInfoFilename private function __classicToolsOrderFilename - return "classicToolsOrder.txt" + return "classicToolsOrder.tsv" end __classicToolsOrderFilename private on __orderClassicTools @@ -601,7 +419,7 @@ private on __objectPropertiesRead put tFile into tObjectType # Get the name of the object set the itemdel to "." - if the last item of tObjectType is "txt" then delete the last item of tObjectType + if the last item of tObjectType is "tsv" then delete the last item of tObjectType if tObjectType is empty then next repeat __setPropertyDataOfObjectFromFile tObjectType, tObjectDefinitionsPath & slash & tFile, tPropertiesInfo @@ -721,9 +539,7 @@ private function __objectPropertiesShared pObjectTypeList, pOrganiseInSections, put pObjectTypeList is not empty into tAllControls repeat for each line tObjectType in pObjectTypeList - set the itemdelimiter to "." - get item -1 of tObjectType - if it is "Card" or it is "Stack" then + if not __objectTypeIsControl(tObjectType) then put false into tAllControls end if if tPropertiesArray is empty then @@ -891,128 +707,132 @@ Description: >*Note:* The type returned by <ideObjectTypeFromObject> can depend on the values of the object's properties. **/ - function ideObjectTypeFromObject pObjectID - switch word 1 of the name of pObjectID - case "stack" +function ideObjectTypeFromObject pObjectID + switch word 1 of the name of pObjectID + case "stack" + if word 4 of pObjectID is "stack" then + return "com.livecode.interface.classic.Substack" + else return "com.livecode.interface.classic.Stack" - case "card" - return "com.livecode.interface.classic.Card" - case "group" - if the dgProps["control type"] of pObjectID is "Data Grid" then - if the dgProps["style"] of pObjectID is "Table" then - return "com.livecode.interface.classic.DataGrid" - else - return "com.livecode.interface.classic.DataGridForm" - end if - else - return "com.livecode.interface.classic.Group" - end if - break - case "field" - if revIDEGetTableProperty(pObjectID, "basicTableObject") then - return "com.livecode.interface.classic.TableField" - else if the listbehavior of pObjectID is true then - return "com.livecode.interface.classic.ListField" - else if the vscrollbar of pObjectID is true then - return "com.livecode.interface.classic.TextArea" + end if + case "card" + return "com.livecode.interface.classic.Card" + case "group" + if the dgProps["control type"] of pObjectID is "Data Grid" then + if the dgProps["style"] of pObjectID is "Table" then + return "com.livecode.interface.classic.DataGrid" else - return "com.livecode.interface.classic.Field" + return "com.livecode.interface.classic.DataGridForm" end if - break - case "button" - if the menumode of pObjectID is "combobox" then return "com.livecode.interface.classic.ComboBox" - - switch the style of pObjectID - case "radiobutton" - return "com.livecode.interface.classic.RadioButton" - break - case "checkbox" - return "com.livecode.interface.classic.Checkbox" - break - case "menu" - switch the menumode of pObjectID - case "combobox" - return "com.livecode.interface.classic.ComboBox" - break - case "option" - return "com.livecode.interface.classic.OptionMenu" - break - case "pulldown" - return "com.livecode.interface.classic.PulldownMenu" - break - case "tabbed" - return "com.livecode.interface.classic.TabPanel" - break - case "popup" - case "cascade" - default - return "com.livecode.interface.classic.PopupMenu" - break - end switch - case "rectangle" - return "com.livecode.interface.classic.RectangleButton" - break - default - if the default of pObjectID is true then - return "com.livecode.interface.classic.DefaultButton" - else - return "com.livecode.interface.classic.Button" - end if - break - end switch - case "scrollbar" - switch the style of pObjectID - case "scale" - return "com.livecode.interface.classic.Slider" - break - case "progress" - return "com.livecode.interface.classic.ProgressBar" - break - case "scrollbar" - if the height of pObjectID > the width of pObjectID and the height of pObjectID < 54 then - return "com.livecode.interface.classic.LittleArrows" - else - return "com.livecode.interface.classic.Scrollbar" - end if - break - end switch - break - case "image" - return "com.livecode.interface.classic.Image" - break - case "player" - return "com.livecode.interface.classic.Player" - case "widget" - return the kind of pObjectID - break - case "graphic" - switch the style of pObjectID - case "text" - case "rectangle" - return "com.livecode.interface.classic.RectangleGraphic" - break - case "roundrect" - return "com.livecode.interface.classic.RoundRectGraphic" - break - case "line" - return "com.livecode.interface.classic.LineGraphic" - break - case "arc" - case "oval" - return "com.livecode.interface.classic.OvalGraphic" - break - case "curve" - return "com.livecode.interface.classic.CurveGraphic" - break - case "polygon" - return "com.livecode.interface.classic.PolygonGraphic" - break - case "regular" - return "com.livecode.interface.classic.RegularGraphic" - break - end switch - break - end switch + else + return "com.livecode.interface.classic.Group" + end if + break + case "field" + if revIDEGetTableProperty(pObjectID, "basicTableObject") then + return "com.livecode.interface.classic.TableField" + else if the listbehavior of pObjectID is true then + return "com.livecode.interface.classic.ListField" + else if the vscrollbar of pObjectID is true then + return "com.livecode.interface.classic.TextArea" + else + return "com.livecode.interface.classic.Field" + end if + break + case "button" + if the menumode of pObjectID is "combobox" then return "com.livecode.interface.classic.ComboBox" + + switch the style of pObjectID + case "radiobutton" + return "com.livecode.interface.classic.RadioButton" + break + case "checkbox" + return "com.livecode.interface.classic.Checkbox" + break + case "menu" + switch the menumode of pObjectID + case "combobox" + return "com.livecode.interface.classic.ComboBox" + break + case "option" + return "com.livecode.interface.classic.OptionMenu" + break + case "pulldown" + return "com.livecode.interface.classic.PulldownMenu" + break + case "tabbed" + return "com.livecode.interface.classic.TabPanel" + break + case "popup" + case "cascade" + default + return "com.livecode.interface.classic.PopupMenu" + break + end switch + case "rectangle" + return "com.livecode.interface.classic.RectangleButton" + break + default + if the default of pObjectID is true then + return "com.livecode.interface.classic.DefaultButton" + else + return "com.livecode.interface.classic.Button" + end if + break + end switch + case "scrollbar" + switch the style of pObjectID + case "scale" + return "com.livecode.interface.classic.Slider" + break + case "progress" + return "com.livecode.interface.classic.ProgressBar" + break + case "scrollbar" + if the height of pObjectID > the width of pObjectID and the height of pObjectID < 54 then + return "com.livecode.interface.classic.LittleArrows" + else + return "com.livecode.interface.classic.Scrollbar" + end if + break + end switch + break + case "image" + return "com.livecode.interface.classic.Image" + break + case "player" + return "com.livecode.interface.classic.Player" + case "widget" + return the kind of pObjectID + break + case "graphic" + switch the style of pObjectID + case "text" + case "rectangle" + return "com.livecode.interface.classic.RectangleGraphic" + break + case "roundrect" + return "com.livecode.interface.classic.RoundRectGraphic" + break + case "line" + return "com.livecode.interface.classic.LineGraphic" + break + case "arc" + case "oval" + return "com.livecode.interface.classic.OvalGraphic" + break + case "curve" + return "com.livecode.interface.classic.CurveGraphic" + break + case "polygon" + return "com.livecode.interface.classic.PolygonGraphic" + break + case "regular" + return "com.livecode.interface.classic.RegularGraphic" + break + end switch + break + end switch end ideObjectTypeFromObject private function __dumpArrayRecurse pArray, pLevel, @pCounter, @pList @@ -1306,8 +1126,15 @@ on __readGroupedPropertiesOfControl pGroupsA, @pDataA end repeat local tDataA + set the itemdelimiter to ";" repeat for each key tKey in tPropMappingA - __fetchPropertyOfControl tKey, tDataA + if the number of items in tKey > 1 then + repeat for each item tRealProp in tKey + __fetchPropertyOfControl tRealProp, tDataA[tKey] + end repeat + else + __fetchPropertyOfControl tKey, tDataA + end if end repeat local tValue, tEffective @@ -1329,7 +1156,19 @@ on __readGroupedPropertiesOfControl pGroupsA, @pDataA end repeat end __readGroupedPropertiesOfControl -private on __fetchPropertyOfControl pProp, @pData +private command __fetchPropertyCustomGetter pGetter, pObject, pProperty, @xPropArray + local tEffective, tValue + dispatch function pGetter with pObject, pProperty, tEffective + put the result into tValue + if tEffective then + put tValue into xPropArray["effective" && pProperty] + put empty into xPropArray[pProperty] + else + put tValue into xPropArray[pProperty] + end if +end __fetchPropertyCustomGetter + +private on __fetchPropertyOfControl pProp, @xData local tError put empty into tError @@ -1340,59 +1179,59 @@ private on __fetchPropertyOfControl pProp, @pData put __classicObjectProperties(tObjID) into tProperties if tProperties["properties"][pProp]["getter"] is not empty then - dispatch function tProperties["properties"][pProp]["getter"] with tObjID, pProp - put the result into pData[pProp] + __fetchPropertyCustomGetter tProperties["properties"][pProp]["getter"], \ + tObjId, pProp, xData exit __fetchPropertyOfControl end if try switch pProp case "short name" - put the short name of the target into pData[pProp] + put the short name of the target into xData[pProp] break case "scriptlines" - put the number of lines of the script of the target into pData[pProp] + put the number of lines of the script of the target into xData[pProp] break case "scriptstatus" - put the scriptStatus of the target into pData[pProp] + put the scriptStatus of the target into xData[pProp] break case "behavior scriptlines" - put the number of lines of the script of the behavior of the target into pData[pProp] + put the number of lines of the script of the behavior of the target into xData[pProp] break case "long id" - put the long id of the target into pData[pProp] + put the long id of the target into xData[pProp] break case "owner" - put the long id of the owner of the target into pData[pProp] + put the long id of the owner of the target into xData[pProp] break case "type" - put word 1 of the name of the target into pData["type"] + put word 1 of the name of the target into xData["type"] break case "custom control" if the the cIDEProperties["cCustomControl"] of the Target is "true" then - put "true" into pData["custom control"] + put "true" into xData["custom control"] else if the dgProp["control type"] of the target is "Data Grid" then - put "true" into pData["custom control"] + put "true" into xData["custom control"] else - put "false" into pData["custom control"] + put "false" into xData["custom control"] end if break default - put the pProp of the Target into pData[pProp] + put the pProp of the Target into xData[pProp] break end switch - put the short name of the target into pData["name"] + put the short name of the target into xData["name"] catch tError end try # AL-2015-07-15: Remove 'do' construction, as evaluating the target as a string # causes incorrect object references when obejcts have the same name - if pData[pProp] is empty then + if xData[pProp] is empty then try local tEffective put the effective pProp of the target into tEffective if tEffective is not empty then - put tEffective into pData["effective" && pProp] + put tEffective into xData["effective" && pProp] end if catch tError end try @@ -1404,8 +1243,17 @@ end __fetchPropertyOfControl # for each of the properties function __readPropertiesOfControl pList, @pData local tError + set the itemdelimiter to ";" repeat for each line tProp in pList - __fetchPropertyOfControl tProp, pData + -- If this pseudo-property is actually multiple properties, + -- the value is an array with keys the real property names + if the number of items in tProp > 1 then + repeat for each item tRealProp in tProp + __fetchPropertyOfControl tRealProp, pData[tRealProp] + end repeat + else + __fetchPropertyOfControl tProp, pData + end if end repeat end __readPropertiesOfControl @@ -1472,10 +1320,18 @@ function __unescapeString pString return pString end __unescapeString +on revIDEFinaliseIDELibrary + revIDEUnsubscribeAll +end revIDEFinaliseIDELibrary + on revIDEInitialiseIDELibrary # Load fonts - start using font file (revIDESpecialFolderPath("fonts") & slash & "lcideicons.ttf") - start using font file (revIDESpecialFolderPath("fonts") & slash & "fontawesome.ttf") + local tFonts + put files(revIDESpecialFolderPath("fonts")) into tFonts + filter lines of tFonts with "*.ttf" + repeat for each line tFont in tFonts + start using font file (revIDESpecialFolderPath("fonts") & slash & tFont) + end repeat # Setup the default lists of properties to read from objects when reading the structure of a stack put "name" & return & "visible" & return & "cantselect" & return & "layer" & return & "long id" & return & "label" & return & "behavior" & return & "scriptlines" & return & "scriptstatus" & return & "short name" & return & "owner" & return & "behavior" & return & "behavior scriptlines" & return & "type" & return & "custom control" into sControlPropertiesToRead @@ -1483,16 +1339,23 @@ on revIDEInitialiseIDELibrary put "scriptlines" & return & "scriptstatus" & return & "short name" & return & "behavior" & return & "behavior scriptlines" & return & "long id" into sStackPropertiesToRead ## Load Extensions - revIDEInitialiseExtensions + revInternal__LoadLibrary "revideextensionlibrary" ## Regenerate dictionary data + revInternal__LoadLibrary "revDatabaseLibrary" revIDERegenerateBuiltDictionaryData ## Initialise property library revIDEPropertyLibraryInitialise + ideSubscribe "ideExtensionsChanged" + ideSubscribe "ideDesktopChanged" end revIDEInitialiseIDELibrary +on ideExtensionsChanged + revIDERegenerateBuiltDictionaryData +end ideExtensionsChanged + ############# # Subscription ############# @@ -1673,7 +1536,7 @@ function revIDEMessages "ideAnswerDialogClosed,ideControlDeleted,ideCardDeleted,ideEditScript,ideExtensionLog,ideExtensionsChanged,ideExtensionStatusChanged,ideFindMoreWidgets," \ & "ideInspectedObjectsChanged,ideLibraryStack,ideNewCard,ideNewStack,ideNewControl,revIDENameChanged,ideObjectSelectionStarted,ideOpenStack," \ & "idePluginsChanged,idePreferenceChanged,idePropertyChanged,ideReleaseStack,ideResumeStack,ideSelectedObjectChanged,ideStackDeleted,ideToolChanged," \ - & "ideTutorialProgressChanged,ideWindowsChanged,ideMouseMove" \ + & "ideTutorialProgressChanged,ideWindowsChanged,ideMouseMove,ideDesktopChanged" \ ) end revIDEMessages @@ -2087,7 +1950,8 @@ returns (String): A return delimited list of stack names function revIDEEditableStacks local tEditableStacks repeat for each line tStack in the openstacks - if the mode of stack tStack < 2 then + if the mode of stack tStack is 1 and \ + the visible of stack tStack is true then if tEditableStacks is empty then put tStack into tEditableStacks else @@ -2155,29 +2019,11 @@ function revIDEGlobalPropertyContinuousRange pProperty end revIDEGlobalPropertyContinuousRange /** -A list of the stacks that can be set at the main stack of the given stack - -Returns: A list of the names of stacks, one per line - -Description: -Use the <revIDEMainstackPropertyOptions> function to retrieve a list of the names of the -stacks that can be set as the main stack of the current stack, taking into account the -Show IDE Stacks preference. +Used by the PI to make a substack into a mainstack **/ -function revIDEMainstackPropertyOptions - local tStackList, tCurrentStack - put ideMainStacks() into tStackList - put revIDESelectedObjects() into tCurrentStack - - ## Allow the stack to be set as its own mainstack - if word 1 of tCurrentStack is "stack" then - if the short name of tCurrentStack is not among the lines of tStackList then - put return & the short name of tCurrentStack after tStackList - end if - end if - sort lines of tStackList - return tStackList -end revIDEMainstackPropertyOptions +command revIDEMakeSubstackMainstack pObj + set the mainstack of pObj to the short name of pObj +end revIDEMakeSubstackMainstack /** A list of the current mainstacks @@ -2403,6 +2249,15 @@ function revIDEStacksInUse return tData end revIDEStacksInUse +function revIDEStackIsIDEWindow pStackName + if pStackName begins with revIDEScriptEditorPrefix() or pStackName is "revDictionary" \ + or pStackName is "revResourceCenter" or pStackName is "revOnline" then + return true + end if + + return false +end revIDEStackIsIDEWindow + function revIDEAPIFilters end revIDEAPIFilters @@ -2425,11 +2280,37 @@ Example: set revIDEGetPreference("text size") to 12 Returns (Any): The value of the preference */ on revIDESetPreference pPreferenceName, pValue - set the pPreferenceName of stack "revpreferences" to pValue - revInternal__SavePreferences - ideMessageSend "idePreferenceChanged:" & pPreferenceName,pValue + if the pPreferenceName of stack "revpreferences" is not pValue then + set the pPreferenceName of stack "revpreferences" to pValue + revInternal__SavePreferences + ideMessageSend "idePreferenceChanged:" & pPreferenceName,pValue + end if end revIDESetPreference +command revIDESetPreferenceOfSet pSetName, pPreferenceName, pValue + local tProps + put the customproperties[pSetName] of stack "revpreferences" into tProps + put pValue into tProps[pPreferenceName] + set the customproperties[pSetName] of stack "revpreferences" to tProps + revInternal__SavePreferences + local tParams + put pSetName into tParams[1] + put pPreferenceName into tParams[2] + put pValue into tParams[3] + ideMessageSendWithParameters "idePreferenceOfSetChanged", "", tParams +end revIDESetPreferenceOfSet + +command revIDEDeletePreferenceSet pSetName + local tSets, tLineOffset + put the custompropertysets of stack "revpreferences" into tSets + put lineOffset(pSetName, tSets) into tLineOffset + if tLineOffset is not 0 then + delete line tLineOffset of tSets + set the customPropertySets of stack "revpreferences" to tSets + revInternal__SavePreferences + end if +end revIDEDeletePreferenceSet + /* Gets a preference. @@ -2447,13 +2328,23 @@ function revIDEGetPreference pPreferenceName put the pPreferenceName of stack "revPreferences" into tValue end if + if pPreferenceName is "cScriptEditor,editor,font" and \ + tValue is empty and \ + "Source Code Pro" is among the lines of the fontNames then + return "Source Code Pro" + end if + return tValue end revIDEGetPreference +function revIDEGetPreferenceOfSet pSetName, pPreferenceName + local tProps + put the customproperties[pSetName] of stack "revpreferences" into tProps + return tProps[pPreferenceName] +end revIDEGetPreferenceOfSet + command __DevPreference pPreferenceName, @rValue - global gREVDevelopment - - if gREVDevelopment then + if not revEnvironmentIsInstalled() then switch pPreferenceName case "cScriptEditor,explicitVariables" case "cScriptEditor,preserveVariables" @@ -2596,7 +2487,9 @@ function revIDEPlatformVersion end revIDEPlatformVersion function revIDEColor pTag - if pTag is "edition_color" then return ideCoreEditionColour() + if pTag is "edition_color" then + return revEnvironmentEditionProperty("color") + end if switch pTag case "text_1" @@ -2761,9 +2654,9 @@ command revIDEUpdatePBPreferences revIDESetPBSortPreferences "pb_stackSort", tSortType, tSortOrder end if - -- Number should be default for cards and controls + -- Layer should be default for cards and controls if tOldSortType is empty then - put "Number" into tSortType + put "Layer" into tSortType end if if revIDEGetPreference("pb_cardSort") is empty then @@ -2817,36 +2710,19 @@ function revIDEStackProperties pStackID, pLevel end revIDEStackProperties function revIDECardPropertiesOfStack pStackID, pLevel - local tCardList, tCardID, tCardArray, tIndex - local tSubStackIDs, tSubstack + local tCardID, tCardArray, tIndex,tCardIDs + local tSubStackIDs, tSubstack, tSortedChildControlListIndexA local tSortType, tSortOrder revIDEGetPBSortPreferences "pb_cardSort", tSortType, tSortOrder - set the itemDel to tab - repeat with x = 1 to the number of cards of stack pStackID - put x & tab & the short name of card x of stack pStackID & tab & the id of card x of stack pStackID & return after tCardList - end repeat - delete the last character of tCardList + put the cardIDs of stack pStackID into tCardIDs - ## Sort the cards as per preferences - if tSortType is "name" then - if tSortOrder is "ascending" then - sort lines of tCardList ascending by item 2 of each - else - sort lines of tCardList descending by item 2 of each - end if - else - if tSortOrder is "ascending" then - sort lines of tCardList ascending numeric by item 1 of each - else - sort lines of tCardList descending numeric by item 1 of each - end if - end if + put __createSortedControlsArray (pStackID, tCardIDs, tSortType, tSortOrder) into tSortedChildControlListIndexA - repeat for each line tCard in tCardList + repeat with x = 1 to the number of elements of tSortedChildControlListIndexA + put tSortedChildControlListIndexA[x]["controlID"] into tCardID add 1 to tIndex - put item 3 of tCard into tCardID dispatch function "__readPropertiesOfControl" to card id tCardID of pStackID with sCardPropertiesToRead, tCardArray[tIndex] put "card" into tCardArray[tIndex]["type"] put "container" into tCardArray[tIndex]["style"] @@ -2875,9 +2751,9 @@ function revIDECardPropertiesOfStack pStackID, pLevel end if else if tSortOrder is "ascending" then - sort lines of tSubStacksList ascending by item 1 of each + sort lines of tSubStacksList ascending numeric by item 1 of each else - sort lines of tSubStacksList descending by item 1 of each + sort lines of tSubStacksList descending numeric by item 1 of each end if end if @@ -2896,9 +2772,57 @@ function revIDECardPropertiesOfStack pStackID, pLevel return tCardArray end revIDECardPropertiesOfStack +function __createSortedControlsArray pParentObject, pChildControls, pSortType, pSortOrder + local tChildCount, tChildControlListA, tChildControlListIndexA, tNextIndex, tSortedChildControlListIndexA + -- create the array + put 1 into tChildCount + + if pParentObject begins with "stack" then + repeat with x = 1 to the number of cards of stack pParentObject + put x into tChildControlListA["layer"] + put the short name of card x of stack pParentObject into tChildControlListA["short name"] + put the id of card x of stack pParentObject into tChildControlListA["controlID"] + put tChildControlListA into tChildControlListIndexA[tChildCount] + add 1 to tChildCount + end repeat + else -- parent is a card or a group + repeat for each line tControlID in pChildControls + put the layer of control id tControlID of pParentObject into tChildControlListA["layer"] + put the short name of control id tControlID of pParentObject into tChildControlListA["short name"] + put tControlID into tChildControlListA["controlID"] + put tChildControlListA into tChildControlListIndexA[tChildCount] + add 1 to tChildCount + end repeat + end if + + -- sort the array + get the keys of tChildControlListIndexA + if pSortType is "name" then + if pSortOrder is "ascending" then + sort lines of it ascending by tChildControlListIndexA[each]["short name"] + else + sort lines of it descending by tChildControlListIndexA[each]["short name"] + end if + else --tSortType is "layer" + if pSortOrder is "ascending" then + sort lines of it ascending numeric by tChildControlListIndexA[each]["layer"] + else + sort lines of it descending numeric by tChildControlListIndexA[each]["layer"] + end if + end if + split it by return + put 1 into tNextIndex + repeat for each element tIndex in it + put tChildControlListIndexA[tIndex] into tSortedChildControlListIndexA[tNextIndex] + add 1 to tNextIndex + end repeat + + return tSortedChildControlListIndexA +end __createSortedControlsArray + function revIDEControlPropertiesOfCard pCardID, pLevel - local tChildControls, tControlArray, tIndex, tFullArray, tChildCount - local tChildControlList, tControlID + local tChildControls, tControlArray, tIndex, tFullArray + local tSortedChildControlListIndexA, tControlID local tSortType,tSortOrder ## Sort controls as per preferences @@ -2911,29 +2835,10 @@ function revIDEControlPropertiesOfCard pCardID, pLevel put the childcontrolIDs of pCardID into tChildControls end if - set the itemDel to tab - repeat for each line tControlID in tChildControls - put the layer of control id tControlID of pCardID & tab & the short name of control id tControlID of pCardID & tab & tControlID & return after tChildControlList - add 1 to tChildCount - end repeat - delete the last character of tChildControlList + put __createSortedControlsArray (pCardID, tChildControls, tSortType, tSortOrder) into tSortedChildControlListIndexA - if tSortType is "name" then - if tSortOrder is "ascending" then - sort lines of tChildControlList ascending by item 2 of each - else - sort lines of tChildControlList descending by item 2 of each - end if - else - if tSortOrder is "ascending" then - sort lines of tChildControlList ascending by item 1 of each - else - sort lines of tChildControlList descending by item 1 of each - end if - end if - - repeat with x = 1 to the number of lines in tChildControlList - put item 3 of line x of tChildControlList into tControlID + repeat with x = 1 to the number of elements of tSortedChildControlListIndexA + put tSortedChildControlListIndexA[x]["controlID"] into tControlID add 1 to tIndex put empty into tControlArray @@ -2965,39 +2870,20 @@ function revIDEControlPropertiesOfCard pCardID, pLevel end revIDEControlPropertiesOfCard function revIDEControlPropertiesOfGroup pGroupID, pLevel - local tControlArray, tIndex - local tChildControls, tChildCount, tChildControlList + local tControlArray, tIndex, tControlID + local tChildControls, tSortedChildControlListIndexA local tSortType,tSortOrder - put the childcontrolIDs of pGroupID into tChildControls - put the number of lines in tChildControls into tChildCount - - set the itemDel to tab - repeat for each line tControlID in tChildControls - put the layer of control id tControlID of pGroupID & tab & the short name of control id tControlID of pGroupID & tab & tControlID & return after tChildControlList - end repeat - delete the last character of tChildControlList - - ## Sort controls as per preferences + ## Sort controls as per preferences revIDEGetPBSortPreferences "pb_controlSort", tSortType, tSortOrder - if tSortType is "name" then - if tSortOrder is "ascending" then - sort lines of tChildControlList ascending by item 2 of each - else - sort lines of tChildControlList descending by item 2 of each - end if - else - if tSortOrder is "ascending" then - sort lines of tChildControlList ascending by item 1 of each - else - sort lines of tChildControlList descending by item 1 of each - end if - end if + put the childcontrolIDs of pGroupID into tChildControls - repeat for each line tControl in tChildControlList + put __createSortedControlsArray (pGroupID, tChildControls, tSortType, tSortOrder) into tSortedChildControlListIndexA + + repeat with x = 1 to the number of elements of tSortedChildControlListIndexA + put tSortedChildControlListIndexA[x]["controlID"] into tControlID add 1 to tIndex - put item 3 of tControl into tControlID dispatch function "__readPropertiesOfControl" to control id tControlID of pGroupID with sControlPropertiesToRead, tControlArray[tIndex] if tControlArray[tIndex]["type"] is "group" then @@ -3369,20 +3255,33 @@ private command __setSizeToPreference pObjectID, pObjectType end if end __setSizeToPreference +private function __objectTypeIsControl pObjectTypeID + switch pObjectTypeID + case "com.livecode.interface.classic.Stack" + case "com.livecode.interface.classic.Substack" + case "com.livecode.interface.classic.Card" + return false + default + return true + end switch +end __objectTypeIsControl on revIDECreateObject pObjectTypeID, pTarget, pLoc - if pObjectTypeID is "com.livecode.interface.classic.card" or \ - pObjectTypeID is "com.livecode.interface.classic.stack" then + if not __objectTypeIsControl(pObjectTypeID) then return __revIDEError("Object must be a control") end if - + if not exists(pTarget) then return __revIDEError("Cannot create object. Target does not exist: " && pTarget) if not pObjectTypeID begins with "com.livecode" then return __revIDEError("No such object type ID: " && pTarget) - + if sClassicObjectProperties is empty then __objectPropertiesRead # Set the default stack to the target we're creating the object on set the defaultstack to revIDEStackOfObject(pTarget) - + + if pLoc is empty then + put the loc of this card of the defaultStack into pLoc + end if + # Create the object lock screen lock messages @@ -3398,10 +3297,10 @@ on revIDECreateObject pObjectTypeID, pTarget, pLoc put round(the cTabButtonWidth of stack "revPreferences" / 2), round(the cTabButtonHeight of stack "revPreferences" / 2) into tCreateRect put item 1 of tCreateRect + the cTabButtonWidth of stack "revPreferences" into item 3 of tCreateRect put item 2 of tCreateRect + the cTabButtonHeight of stack "revPreferences" into item 4 of tCreateRect - + local lDataGrid put true into lDataGrid -- select data grid at end not single control - + unlock messages # tObjectId is passed by reference and will have the data grid group id placed into it addDataGridToStack the short name of this stack, tCreateRect, empty, empty, tCreatedControlID @@ -3429,6 +3328,17 @@ on revIDECreateObject pObjectTypeID, pTarget, pLoc else # Not a classic control try + if pObjectTypeID is "com.livecode.widget.native.map" and the platform is "MacOS" and (revIDEPlatformVersion() begins with "10.9" or revIDEPlatformVersion() begins with "10.10") then + local tMessage + put "The Mac MapKit API is supported from OS X 10.9 onwards, but Apple restricts use of the API on 10.9 and 10.10 to apps which are distributed from the Mac AppStore with an appropriate entitlement. " & \ + "Due to this, general use of the Map widget only supports OS X 10.11 onwards. " & CR & CR & \ + "However, you can still create a standalone with the Map widget on OSX 10.9 or 10.10 (of course you will see an empty grid rather than the actual map), " & \ + " BUT this standalone will run as expected on OSX 10.11 and above." into tMessage + + answer warning revIDELocalise(tMessage) with "Cancel" and "Continue" + if it is "Cancel" then exit revIDECreateObject + end if + create widget as pObjectTypeID put the long id of the last control into tCreatedControlID @@ -3452,46 +3362,37 @@ on revIDECreateObject pObjectTypeID, pTarget, pLoc __setSizeToPreference tCreatedControlID, pObjectTypeID set the loc of tCreatedControlID to pLoc - + unlock messages unlock screen - + ## Prevent passing of ideNewControl message for objects created on IDE stacks if revIDEObjectIsOnIDEStack(tCreatedControlID) is false then - global gRevStackStatus // AL-2015-04-08: [[ Bug 14822 ]] Ensure 'edited' status of stack is set - put "edited" into gREVStackStatus[the short name of this stack] + revIDESetEdited the short name of this stack ideMessageSend "ideNewControl", tCreatedControlID end if - + return tCreatedControlID end revIDECreateObject on revIDECloneObject pLongID - local tTarget, tLoc, tControlType - local tCreatedControlID - - put the loc of pLongID into tLoc - add 20 to item 1 of tLoc - add 20 to item 2 of tLoc - - put revIDECardOfObject(pLongID) into tTarget - if not exists(tTarget) then return __revIDEError("Cannot create object. Target does not exist:" && tTarget) - - -- # Set the default stack to the target we're creating the object on - -- set the defaultstack to the owner of tTarget - - -- # Create the object - -- lock screen - -- lock messages - --do "clone" && pLongID - clone pLongID - put the long ID of the last control into tCreatedControlID - set the loc of tCreatedControlID to tLoc - - -- unlock messages - -- unlock screen - -- return tCreatedControlID + if not exists(pLongID) then return __revIDEError("Cannot create object. Target does not exist:" && pLongID) + + if word 1 of pLongID is "card" or word 1 of pLongID is "stack" then + clone pLongID + else + local tTarget, tLoc, tControlType + local tCreatedControlID + + put the loc of pLongID into tLoc + add 20 to item 1 of tLoc + add 20 to item 2 of tLoc + + clone pLongID + put it into tCreatedControlID + set the loc of tCreatedControlID to tLoc + end if end revIDECloneObject on revIDECloneObjectWithDefaults pLongID @@ -3820,18 +3721,6 @@ on revIDERelayerControl pControl, pLayerNumber, pCard return the long id of tName end revIDERelayerControl -on revIDEMoveControl pControl, pNewCard, pLayerNumber - local tNewControl - lock messages - copy pControl to pNewCard - put the long id of it into tNewControl - - delete pControl - - revIDESetPropertyOfObject tNewControl, "layer", pLayerNumber - unlock messages -end revIDEMoveControl - on revIDEMoveCard pCard, pNewStack local tNewCard lock messages @@ -4114,7 +4003,7 @@ Example: local tIDEFolder put revIDESpecialFolderPath("IDE") into tIDEFolder */ -function revIDESpecialFolderPath pKey +function revIDESpecialFolderPath pKey, pParam local tPath set the itemdel to "/" switch pKey @@ -4125,11 +4014,18 @@ function revIDESpecialFolderPath pKey return item 1 to -3 of the filename of stack "home" & "/Toolset" break case "Toolchain" - return item 1 to -3 of the filename of stack "home" & "/Toolchain" + if revEnvironmentIsInstalled() then + return item 1 to -3 of the filename of stack "home" & "/Toolchain" + else + return revEnvironmentBinariesPath() + end if break case "Object Property Definitions" return item 1 to -3 of the filename of stack "home" & "/Toolset/resources/supporting_files/property_definitions" break + case "Object Default Scripts" + return item 1 to -3 of the filename of stack "home" & "/Toolset/resources/supporting_files/default_scripts" + break case "Standalone Settings Definitions" return item 1 to -3 of the filename of stack "home" & "/Toolset/resources/supporting_files/standalone_settings" break @@ -4181,6 +4077,9 @@ function revIDESpecialFolderPath pKey break case "api" case "guide" + if pParam is not empty then + put "_" & pParam after pKey + end if put item 1 to -3 of the filename of stack "home" & "/Documentation/html_viewer/resources/data/" & tolower(pKey) into tPath if not revEnvironmentIsInstalled() then revIDEEnsurePath tPath @@ -4455,7 +4354,7 @@ Returns a list of all the display names of stacks recognised by the IDE as a pal */ function revIDEAvailablePalettes return "Menubar,Tools,Inspector,Message Box,Project Browser,Extension Manager,Extension Builder,Start Center,Welcome,Menu Builder,Message Watcher,Plugin Preferences," \ - & "Standalone Settings,About,Dictionary,Guide,Resource Center,Preferences,Search" + & "Standalone Settings,About,Dictionary,Guide,Resource Center,Preferences,Search,Snippet Viewer" end revIDEAvailablePalettes function revIDEPaletteToStackName pPalette @@ -4504,6 +4403,8 @@ function revIDEPaletteToStackName pPalette return "revDictionary" case "resource center" return "revResourceCenter" + case "snippet viewer" + return "revIDESnippetViewer" end switch end revIDEPaletteToStackName @@ -4689,7 +4590,7 @@ private function revIDEPaletteBarHeight pStackID end revIDEPaletteBarHeight function revIDEBrowserWidgetUnavailable - return the platform is "Linux" and the processor is not "x86_64" + return (the platform is "Linux") and ($LIVECODE_USE_CEF is 0) end revIDEBrowserWidgetUnavailable /* @@ -4731,6 +4632,7 @@ command revIDEOpenPalette pPaletteName case "standalone settings" case "message watcher" case "tools" + case "snippet viewer" palette stack tStackName break case "search" @@ -4975,9 +4877,9 @@ end arrayRecurse private function __escapeStringAndConvertLineEndings pString replace "\" with "\\" in pString replace quote with ("\" & quote) in pString - replace (numToChar(13) & CR) with (CR & numToChar(13)) in pString - replace (CR & numToChar(13)) with CR in pString - replace CR with "\n" in pString + replace CRLF with "\n" in pString + replace numToCodepoint(13) with "\n" in pString + replace LF with "\n" in pString return (quote & pString & quote) end __escapeStringAndConvertLineEndings @@ -5004,7 +4906,7 @@ on revIDEInstallUserGuide pGuideFolder, pExtensionName, pAuthor revIDESetUTF8FileContents pGuideFolder & slash & "guide.js", tGuideJSON # Now regenerate the built guides - revIDEAddGuideAndRegenerate tGuideJSON + revIDERegenerateBuiltGuides end revIDEInstallUserGuide /* @@ -5026,7 +4928,7 @@ on revIDEInstallAPI pAPIFolder, pExtensionName, pAuthor revIDESetUTF8FileContents pAPIFolder & slash & "api.js", tAPIJSON # Now regenerate the built APIs - revIDEAddAPIAndRegenerate tAPIJSON + revIDERegenerateBuiltAPIs end revIDEInstallAPI on revIDEGoToLCSDictionaryEntry pTag, pType @@ -5043,11 +4945,21 @@ on revIDEGoToDictionaryEntry pLibrary, pTag, pType revIDEMessageSend "ideOpenPalette", "dictionary" end revIDEGoToDictionaryEntry -on revIDEGoToWidgetAPI pKind - local tLibraryName, tEntry - put revIDEExtensionProperty(pKind, "title") into tLibraryName - put tolower(pKind) into tEntry - revIDEGoToDictionaryEntry tLibraryName, tEntry, "widget" +command revIDEGoToExtensionAPI pKind + local tType + put revIDEExtensionProperty(pKind, "type") into tType + __GoToExtensionAPI pKind, tType +end revIDEGoToExtensionAPI + +private command __GoToExtensionAPI pKind, pType + local tName, tLibrary + put revIDEExtensionProperty(pKind, "title") into tName + put tolower(pKind) into tLibrary + revIDEGoToDictionaryEntry tLibrary, tName, pType +end __GoToExtensionAPI + +command revIDEGoToWidgetAPI pKind + __GoToExtensionAPI pKind, "widget" end revIDEGoToWidgetAPI on revIDEGoToObjectAPI pObjectID @@ -5064,9 +4976,21 @@ end revIDEGoToObjectAPI # Properties API ############# -local sLockUpdates -on revIDEPropertyLibraryInitialise +local sLockUpdates, sThrottleTime +private command __LockPropertyUpdates pThrottleTime + if pThrottleTime is empty then + put 10 into pThrottleTime + end if + put true into sLockUpdates + put pThrottleTime into sThrottleTime +end __LockPropertyUpdates + +private command __UnlockPropertyUpdates put false into sLockUpdates +end __UnlockPropertyUpdates + +on revIDEPropertyLibraryInitialise + __UnlockPropertyUpdates end revIDEPropertyLibraryInitialise ## Register new listeners for objects @@ -5092,12 +5016,39 @@ on revIDEPropertyCancelAllListeners end repeat end revIDEPropertyCancelAllListeners -on revIDEPropertyChanged pObject +local sObjListA +on revIDEUnlockPropertyUpdates + __UnlockPropertyUpdates + revIDESendPropertyChanged the keys of sObjListA + put empty into sObjListA +end revIDEUnlockPropertyUpdates + +on revIDESendPropertyChanged pObjectList + repeat for each line tObject in pObjectList + ideMessageSendWithTrigger "idePropertyChanged", tObject, tObject + end repeat +end revIDESendPropertyChanged + +local sPropertyChangedMsgID +on revIDEPropertyChanged pObjectList if sLockUpdates is true then + -- Accumulate a list of objects whose property changes were locked + -- from triggering an ide message. + repeat for each line tObj in pObjectList + put true into sObjListA[tObj] + end repeat + + if "revIDEUnlockPropertyUpdates" is in the pendingMessages then + cancel sPropertyChangedMsgID + end if + + -- Postpone update until sThrottleTime millisecs has passed + send "revIDEUnlockPropertyUpdates" to me in sThrottleTime millisecs + put the result into sPropertyChangedMsgID exit revIDEPropertyChanged end if - ideMessageSendWithTrigger "idePropertyChanged", pObject, pObject + revIDESendPropertyChanged pObjectList end revIDEPropertyChanged on revIDEHideProperty pProperty @@ -5164,6 +5115,27 @@ private on __setPropertyOfObject pObject, pProperty, pValue end __setPropertyOfObject +function ideCheckStackName pName + if char 1 to 3 of pName is "rev" then + answer warning revIDELocalise("Using rev in the first three characters of a stack name is reserved for use by the LiveCode development environment and advanced users creating Plug-ins. If you use these characters, your stack may not behave as expected.") with revIDELocalise("OK") and revIDELocalise("Cancel") + if it is revIDELocalise("Cancel") then + return false + end if + end if + if pName is a number then + beep + answer error revIDELocalise("You cannot set the name of a stack to a number.") + return false + end if + if pName contains quote then + beep + answer error revIDELocalise("The name of the stack cannot contain quotes") + return false + end if + + return true +end ideCheckStackName + on revIDEPropertySet pObjectList, pProperty, pValue, pLockUpdates local tThrottlePropertyChanged put false into tThrottlePropertyChanged @@ -5172,9 +5144,39 @@ on revIDEPropertySet pObjectList, pProperty, pValue, pLockUpdates end if if tThrottlePropertyChanged or pLockUpdates then - put true into sLockUpdates + __LockPropertyUpdates 10 end if + lock screen + # Set stack edited before property change + local tStacksListA, tStackShortNamesListA, tStack, tStackName + repeat for each line tObject in pObjectList + put revIDEStackOfObject(tObject) into tStack + if not tStacksListA[tStack] then + put true into tStacksListA[tStack] + + # If stack name is changed, use new name when setting edited + if tStack is tObject and pProperty is "name" then + + if not ideCheckStackName(pValue) then + local tOldName + put the short name of tStack into tOldName + set the name of tStack to tOldName + exit revIDEPropertySet + end if + + put pValue into tStackName + else + put the short name of tStack into tStackName + end if + put true into tStackShortNamesListA[tStackName] + end if + end repeat + + repeat for each key tStackName in tStackShortNamesListA + revIDESetEdited tStackName + end repeat + # Multi-object properties require the object list to be passed local tMultiObjectSetter put sClassicObjectProperties["com.livecode.interface.MultipleObjects"]["properties"][pProperty]["setter"] into tMultiObjectSetter @@ -5186,11 +5188,7 @@ on revIDEPropertySet pObjectList, pProperty, pValue, pLockUpdates end repeat end if - if sLockUpdates then - ideMessageSendWithParameters "idePropertyChanged", pObjectList - put false into sLockUpdates - end if - + unlock screen end revIDEPropertySet local sStoredPropsA @@ -5362,10 +5360,6 @@ function revIDEPaletteResourcePath pFilename, pTarget return tPalettePath & slash & pFilename end revIDEPaletteResourcePath -on logChanged pLog - ideMessageSend "ideExtensionLog", pLog -end logChanged - function revIDELastModifiedTimeOfFile pFolder, pFile local tDetailedFiles revIDEPushDefaultFolder pFolder @@ -5394,7 +5388,12 @@ end revIDELastModifiedTimeOfFilesInFolder function revIDEExtensionFolders local tFoldersA put revIDESpecialFolderPath("user extensions") into tFoldersA["user"] - put revIDESpecialFolderPath("extensions") into tFoldersA["ide"] + + local tCount = 0 + repeat for each line tFolder in revEnvironmentExtensionsPaths() + add 1 to tCount + put tFolder into tFoldersA["ide" && tCount] + end repeat return tFoldersA end revIDEExtensionFolders @@ -5416,6 +5415,52 @@ function revIDEDefaultExtensionIcon pType, pRetina end switch end revIDEDefaultExtensionIcon +function revIDEDefaultScript pObject, pHandler + local tDefaultScript, tType + put ideObjectTypeFromObject(pObject) into tType + if word 1 of the name of pObject is "widget" then + put revIDEWidgetDefaultScript(tType) into tDefaultScript + else + put revIDEClassicObjectDefaultScript(tType) into tDefaultScript + end if + + lock screen + lock messages + create invisible stack "revDefaultScriptHolder" + try + set the script of it to tDefaultScript + catch tError + end try + local tHandlers + put the revAvailableHandlers of it into tHandlers + delete stack "revDefaultScriptHolder" + local tHandlerStart, tHandlerEnd, tHandlerInfo, tHandlerInfoLine + set the wholematches to false + -- Ensure we don't accidentally match a substring by putting + -- spaces around the handler name + put lineOffset(" " & pHandler & " ", tHandlers) into tHandlerInfoLine + put line tHandlerInfoLine of tHandlers into tHandlerInfo + -- We want to include any comments before the handler declaration + -- so find the previous handler + put word 3 of tHandlerInfo into tHandlerStart + put word 4 of tHandlerInfo into tHandlerEnd + repeat while word 1 of line tHandlerStart of tDefaultScript is not empty + subtract 1 from tHandlerStart + end repeat + unlock messages + unlock screen + return line tHandlerStart to tHandlerEnd of tDefaultScript +end revIDEDefaultScript + +function revIDEClassicObjectDefaultScript pType + local tFolder + put revIDESpecialFolderPath("Object Default Scripts") into tFolder + if there is a stack (tFolder & slash & pType & ".livecodescript") then + return the script of stack (tFolder & slash & pType & ".livecodescript") + end if + return empty +end revIDEClassicObjectDefaultScript + function revIDEWidgetDefaultScript pKind return revIDEExtensionProperty(pKind, "defaultScript") end revIDEWidgetDefaultScript @@ -5424,6 +5469,8 @@ function revIDEScriptEditorBehavior pWhich local tPathToBehaviors put revIDESpecialFolderPath("Toolset") & slash & "palettes" & slash & "script editor" & slash & "behaviors" into tPathToBehaviors switch pWhich + case "common editor" + return tPathToBehaviors & slash & "revsecommoneditorbehavior.livecodescript" case "editor" return tPathToBehaviors & slash & "revseeditorbehavior.livecodescript" case "handlerlist" @@ -5442,6 +5489,8 @@ function revIDEScriptEditorBehavior pWhich return tPathToBehaviors & slash & "revsedocumentationpanebehavior.livecodescript" case "breakpointpane" return tPathToBehaviors & slash & "revsebreakpointpanebehavior.livecodescript" + case "errorspane" + return tPathToBehaviors & slash & "revseerrorspanebehavior.livecodescript" case "filterfield" return tPathToBehaviors & slash & "revsefilterfieldbehavior.livecodescript" case "variablescheckbox" @@ -5458,6 +5507,10 @@ function revIDEScriptEditorBehavior pWhich return tPathToBehaviors & slash & "revsevariablevisualizerstackbehavior.livecodescript" case "edit breakpoint" return tPathToBehaviors & slash & "revseeditbreakpointstackbehavior.livecodescript" + case "error template" + return tPathToBehaviors & slash & "revseerrortemplatebehavior.livecodescript" + case "find main card" + return tPathToBehaviors & slash & "revsefindmaincardbehavior.livecodescript" default return empty end switch @@ -5602,6 +5655,7 @@ command ConfirmPresenceOfTemplateStack pStack put kTemplateStack && tUnique into tStackName set the topleft of the templatestack to -1000,-1000 create stack tStackName + reset the templatestack close stack tStackName set the mainstack of stack tStackName to the mainstack of stack pStack @@ -5749,7 +5803,32 @@ on revIDESetDataGridProperty pObj, pProperty, pValue end switch end revIDESetDataGridProperty -function revIDEGetDataGridProperty pObject, pProperty +private function __DataGridTextProperty pObject, pProperty, @rEffective + local tRealProperty + switch pProperty + case "text font" + case "header text font" + put "textFont" into tRealProperty + break + case "text size" + case "header text size" + put "textSize" into tRealProperty + break + case "text style" + case "header text style" + put "textStyle" into tRealProperty + break + end switch + local tValue + put the dgProps[pProperty] of pObject into tValue + if tValue is empty then + put the effective tRealProperty of pObject into tValue + put true into rEffective + end if + return tValue +end __DataGridTextProperty + +function revIDEGetDataGridProperty pObject, pProperty, @rEffective switch pProperty case "row behavior" local tTemplate @@ -5761,12 +5840,29 @@ function revIDEGetDataGridProperty pObject, pProperty if sFirstRowHeaders[pObject] then return the dgText[true] of pObject else - return the dgText of pObject + return the dgText of pObject end if break case "first row header" return sFirstRowHeaders[pObject] is true break + case "text font" + case "text size" + case "text style" + case "header text font" + case "header text size" + case "header text style" + return __DataGridTextProperty(pObject, pProperty, rEffective) + case "header background color" + case "header background hilite color" + -- Special case these as their default values are two-color gradients + local tColor + put the dgProps[pProperty] of pObject into tColor + if the number of lines in tColor is 2 then + put true into rEffective + return line 1 of tColor + end if + return tColor default return the dgProps[pProperty] of pObject break @@ -6076,32 +6172,95 @@ on revIDESetGradientProperty pObject, pProperty, pValue end revIDESetGradientProperty private function __resolveStackFilePath pBasePath, pOtherPath - -- First absolutize other path (if possible) - local tOldFolder - put the folder into tOldFolder - set the itemDelimiter to slash - - local tFolderResult - set the folder to item 1 to -2 of pOtherPath - put the result into tFolderResult - if tFolderResult is not empty then - set the folder to tOldFolder - return pOtherPath - end if - put the folder & slash & item -1 of pOtherPath into pOtherPath - set the folder to tOldFolder + set the itemdelimiter to "/" + put __resolveRelativeFilenameReference(pOtherPath, item 1 to -2 of pBasePath) into pOtherPath - -- At this point tOtherPath should be absolute, so if its + -- At this point pOtherPath should be absolute, so if its -- (component-wise) prefix is pBasePath we relativize again. local tBasePathFolder - put item 1 to -2 of pBasePath & slash into tBasePathFolder - if pOtherPath begins with tBasePathFolder then - delete char 1 to (the number of chars in tBasePathFolder) of pOtherPath - end if + put item 1 to -2 of pBasePath into tBasePathFolder + put __makePathRelative(pOtherPath, tBasePathFolder) into pOtherPath return pOtherPath end __resolveStackFilePath +private function __resolveRelativeFilenameReference pFilename, pRootFolder + local tNewFilename + + set the itemdelimiter to "/" + + if not (pFilename begins with "../") then + if pFilename begins with "/" or item 1 of pFilename contains ":" then + return pFilename + else + return pRootFolder & "/" & pFilename + end if + end if + + put pFilename into tNewFilename + + repeat while tNewFilename begins with "../" + if pRootFolder is empty then + return "out of bounds" for error + else + delete the last item of pRootFolder + delete char 1 to 3 of tNewFilename + end if + end repeat + + if tNewFilename is empty then + return pRootFolder for value + else + return pRootFolder & "/" & tNewFilename for value + end if +end __resolveRelativeFilenameReference + +private function __makePathRelative pFilename, pRootFolder + local tIndex + local tMatchCount = 0 + local tNonMatchCount =0 + + # Normalize + if char 1 of pFilename is slash then delete char 1 of pFilename + if char 1 of pRootFolder is slash then delete char 1 of pRootFolder + if the last char of pFilename is slash then delete the last char of pFilename + if the last char of pRootFolder is slash then delete the last char of pRootFolder + set the itemdelimiter to slash + + if pFilename is empty then return empty + if pRootFolder is empty then return pFilename + + # Is pFilename a child directory of pRootFolder? + if pRootFolder is item 1 to (the number of items of pRootFolder) of pFilename then + delete char 1 to length(pRootFolder) + 1 of pFilename + else if pFilename is char 1 to length(pFilename) of pRootFolder then + delete char 1 to length(pFilename) + 1 of pRootFolder + put empty into pFilename + repeat with tIndex = 1 to the number of items of pRootFolder + put "../" after pFilename + end repeat + else + # determine where paths diverge + repeat with tIndex = 1 to the number of items of pFilename + if item tIndex of pFilename is not item tIndex of pRootFolder then + put tIndex - 1 into tMatchCount + put the number of items of pRootFolder - tIndex + 1 into tNonMatchCount + exit repeat + end if + end repeat + + if tMatchCount > 0 then + delete item 1 to tMatchCount of pFilename + end if + + repeat with tIndex = 1 to tNonMatchCount + put "../" before pFilename + end repeat + end if + + return pFilename +end __makePathRelative + command revIDESetStackFilesProperty pObject, pProperty, pValue local tProcessedValue put empty into tProcessedValue @@ -6132,6 +6291,79 @@ command revIDESetStackFilesProperty pObject, pProperty, pValue set the stackFiles of pObject to tProcessedValue end revIDESetStackFilesProperty +local sResizeA +command revIDESetRectProperty pObject, pProperty, pValue + switch pProperty + case "width" + if pValue is "fit" then + set the width of pObject to the formattedwidth of pObject + else if pValue is a number then + set the width of pObject to pValue + end if + break + case "height" + if pValue is "fit" then + set the height of pObject to the formattedheight of pObject + else if pValue is a number then + set the height of pObject to pValue + end if + break + case "resize" + put pValue into sResizeA[pObject] + break + case "left" + if sResizeA[pObject] then + set the width of pObject to (the width of pObject + the left of pObject - pValue) + end if + set the left of pObject to pValue + break + case "right" + if sResizeA[pObject] then + set the width of pObject to (the width of pObject + pValue - the right of pObject) + end if + set the right of pObject to pValue + break + case "top" + if sResizeA[pObject] then + set the height of pObject to (the height of pObject + the top of pObject - pValue) + end if + set the top of pObject to pValue + break + case "bottom" + if sResizeA[pObject] then + set the height of pObject to (the height of pObject + pValue - the bottom of pObject) + end if + set the bottom of pObject to pValue + break + end switch +end revIDESetRectProperty + +function revIDEGetRectProperty pObject, pProperty + switch pProperty + case "resize" + return sResizeA[pObject] + end switch +end revIDEGetRectProperty + +command revIDESetImageFilename pObjectID, pProperty, pFilename + if revIDEGetPreference("cImageFileRelative") is not false then + local tStackPath, tFilePath + set the itemDelimiter to "/" + put item 1 to -2 of the filename of stack revTargetStack(pObjectID) into tStackPath + if tStackPath is not empty then + put revCalculateRelativePath(tStackPath, pFilename) into tFilePath + if tFilePath begins with "./" then delete char 1 to 2 of tFilePath + if tFilePath ends with pFilename then + --full path contained in relative path, likely a different volume + --in any case, need to return absolute path + else if there is a file (tStackPath & slash & tFilePath) then + put tFilePath into pFilename + end if + end if + end if + set the filename of pObjectID to pFilename +end revIDESetImageFilename + ############# # Standalone Settings ############# @@ -6141,37 +6373,75 @@ on revIDEStandaloneSettingsForStack pStackID end revIDEStandaloneSettingsForStack private function __standaloneSettingsInfoFilename - return "standaloneSettings.txt" + return "standaloneSettings.tsv" end __standaloneSettingsInfoFilename function revIDEStandaloneSettings pStack, pSection local tInfo put revIDEStandaloneSettingsInfoOfSection(pSection) into tInfo - - local tPropsA, tPropName - repeat for each element tGroup in tInfo - repeat for each element tProp in tGroup["proplist"] - put tProp["property_name"] into tPropName - put tProp into tPropsA[tGroup["label"]][tPropName] - put the cRevStandaloneSettings[tPropName] of pStack into tPropsA[tGroup["label"]][tPropName]["value"] - end repeat - end repeat - return tPropsA + + return __revIDEStandaloneSettingsOfStackForExtension(pStack, tInfo) end revIDEStandaloneSettings function revIDEStandaloneSettingsInfoOfSection pSection local tStandaloneDefinitionsPath put revIDESpecialFolderPath("Standalone Settings Definitions") into tStandaloneDefinitionsPath - + local tInfoA put __propertyDataFromInfoFile(tStandaloneDefinitionsPath & slash & __standaloneSettingsInfoFilename()) into tInfoA - + local tOrganisedA put __organisePropertyInfo(tInfoA) into tOrganisedA - + return __orderPropSubArray(tOrganisedA[pSection], true) end revIDEStandaloneSettingsInfoOfSection +function revIDEStandaloneSettingsInfoOfExtension pKind + local tInfoA + put revIDEExtensionStandaloneSettingsInfo(pKind, true) into tInfoA + + local tSectionList + -- At the moment all per-extension standalone settings are in + -- the 'basic' section + put __orderPropArray(tInfoA, "Basic") into tSectionList + return tSectionList[1]["grouplist"] +end revIDEStandaloneSettingsInfoOfExtension + +function revIDEStandaloneSettingsOfExtension pStack, pKind + local tInfoA + put revIDEStandaloneSettingsInfoOfExtension(pKind) into tInfoA + + return __revIDEStandaloneSettingsOfStackForExtension(pStack, tInfoA, pKind) +end revIDEStandaloneSettingsOfExtension + +private function __revIDEStandaloneSettingsOfStackForExtension pStack, pInfoA, pExtension + local tSettings + if pExtension is not empty then + put the cRevStandaloneSettings[pExtension] of pStack into tSettings + else + put the customProperties["cRevStandaloneSettings"] of pStack into tSettings + end if + + local tPropsA, tPropName + set the itemdelimiter to ";" + repeat for each element tGroup in pInfoA + repeat for each element tProp in tGroup["proplist"] + put tProp["property_name"] into tPropName + put tProp into tPropsA[tGroup["label"]][tPropName] + if the number of items in tPropName > 1 then + repeat for each item tRealProp in tPropName + put tSettings[tRealProp] into \ + tPropsA[tGroup["label"]][tPropName]["value"][pStack][tRealProp] + end repeat + else + put tSettings[tPropName] into \ + tPropsA[tGroup["label"]][tPropName]["value"][pStack] + end if + end repeat + end repeat + return tPropsA +end __revIDEStandaloneSettingsOfStackForExtension + function revIDEStandaloneSettingsInfo local tStandaloneDefinitionsPath put revIDESpecialFolderPath("Standalone Settings Definitions") into tStandaloneDefinitionsPath @@ -6260,14 +6530,7 @@ on revIDETogglePaletteView unlock screen end revIDETogglePaletteView -on revIDEPopupContextualMenu pTargets - dispatch "revMenubarPopupContextualMenu" to stack revIDEPaletteToStackName("menubar") with pTargets -end revIDEPopupContextualMenu - -local sPluginsA -on revIDEUpdatePlugins - global gREVStartupList, gREVShutdownlist, gREVDontLoadMenus - +function revIDEGetAllPlugins local tUserPlugins put revAbsoluteFolderListing(revEnvironmentUserPluginsPath()) into tUserPlugins @@ -6283,6 +6546,19 @@ on revIDEUpdatePlugins if tDevelopmentPlugins is not empty then put revCombineFilePaths(tFinal,tDevelopmentPlugins) into tFinal end if + return tFinal +end revIDEGetAllPlugins + +on revIDEPopupContextualMenu pTargets + dispatch "revMenubarPopupContextualMenu" to stack revIDEPaletteToStackName("menubar") with pTargets +end revIDEPopupContextualMenu + +local sPluginsA +on revIDEUpdatePlugins + global gREVStartupList, gREVShutdownlist, gREVDontLoadMenus + + local tFinal + put revIDEGetAllPlugins() into tFinal put empty into gREVStartupList put empty into gREVShutdownList @@ -6472,11 +6748,17 @@ pWorking (boolean): If true return the loc relative to OS screen furniture rathe Returns: The screenRect of the screen the stack is on */ function revIDEStackScreenRect pStackName, pWorking + local tRect if pWorking then - return line (the screen of stack pStackName) of the working screenRects + put line (the screen of stack pStackName) of the working screenRects into tRect else - return line (the screen of stack pStackName) of the screenRects + put line (the screen of stack pStackName) of the screenRects into tRect + end if + if tRect is empty then + return 0,0,0,0 end if + + return tRect end revIDEStackScreenRect on revIDEActionNewMainstack pStackType @@ -6504,7 +6786,6 @@ on revIDEActionNewMainstack pStackType end revIDEActionNewMainstack on revIDEActionNewCard - global gRevStackStatus local tFilterStack put the short name of the topStack into tFilterStack if revFilterStacksList(tFilterStack) is empty then @@ -6514,7 +6795,7 @@ on revIDEActionNewCard local tCardID create card put the long id of it into tCardID - put "edited" into gREVStackStatus[the short name of this stack] + revIDESetEdited the short name of this stack ideMessageSend "ideNewCard tCardID" # Return the card id @@ -6526,14 +6807,11 @@ on revIDEActionDeleteCard end revIDEActionDeleteCard on revIDEDeleteCard pLongID - global gRevStackStatus answer error "Are you sure you want to delete" && the long name of pLongID & "?" with "Yes" or "No" if it is not "yes" then exit revIDEDeleteCard delete pLongID - local tStackName - put the short name of ideStackOfObject(pLongID) into tStackName - put "edited" into gREVStackStatus[tStackName] + revIDESetEdited the short name of ideStackOfObject(pLongID) end revIDEDeleteCard /* @@ -6599,7 +6877,7 @@ on revIDEActionNewScriptOnlyStack # Create script only revIDENewScriptOnlyStack it - # If an error occured, tell the use + # If an error occurred, tell the user if the result is not empty then answer the result end if @@ -6806,7 +7084,7 @@ function revIDEAcceptedTypes pType local tTypes switch pType case "image" - return "jpg,jpeg,jfif,gif,png,bitmap,bmp,dib,vga,pict,pict2,pic" + return "jpg,jpeg,jfif,gif,png,bitmap,bmp,dib,vga,pict,pict2,pic,svg" case "video" put "mp4,mpg,mpeg,mov" into tTypes if the platform is "win32" then @@ -6902,7 +7180,12 @@ on revIDEImportControl pType, pFileName, pReferenced set the defaultStack to tTargetStack switch pType case "image" - if pReferenced is true then + if pFileName ends with ".svg" then + -- SVG files can't be referenced + revIDECreateObject "com.livecode.interface.classic.image", tTargetStack, tCreatedControlLocation + put the long id of the last control into tCreatedControlID + set the text of tCreatedControlID to drawingSvgCompileFile(pFileName) + else if pReferenced is true then ## Create a classic image control with default properties ## Set the filename of the new image control to the referenced image revIDECreateObject "com.livecode.interface.classic.image", tTargetStack, tCreatedControlLocation @@ -6936,7 +7219,7 @@ on revIDEImportControl pType, pFileName, pReferenced revIDECreateObject "com.livecode.interface.classic.field", tTargetStack, tCreatedControlLocation put the result into tCreatedControlID put revIDEUTF8FileContents(pFileName) into tFileContents - put tFileContents into tCreatedControlID + set the text of tCreatedControlID to tFileContents select tCreatedControlID break case "graph" @@ -7262,6 +7545,41 @@ private function ideDispatchSaveStackRequest pStackName return tDispatchStatus end ideDispatchSaveStackRequest +local sStackEdited +command revIDESetEdited pStackName + # Don't set edited on a transient IDE stack (i.e. SE or PI generated) + if there is a stack pStackName and \ + the cIDETransient of stack pStackName then + exit revIDESetEdited + end if + + # Don't set edited on a stack if it is currently saving + if pStackName is "revSaving" or the mode of stack "revSaving" is 0 then + put true into sStackEdited[pStackName] + end if +end revIDESetEdited + +command revIDESetUnedited pStackName + put false into sStackEdited[pStackName] +end revIDESetUnedited + +function revIDEStackIsEdited pStackName + if revIDEStackNameIsIDEStack(pStackName) then + global gRevDevelopment + # Ignore status of IDE stacks if gRevDevelopment is false + if not gRevDevelopment then + return false + end if + + # Ignore status of IDE stacks that are not toplevel + if the mode of stack pStackName is not 1 then + return false + end if + end if + + return sStackEdited[pStackName] is true +end revIDEStackIsEdited + on revIDESaveStack pStackID local tDefaultStack put the defaultStack into tDefaultStack @@ -7322,7 +7640,6 @@ on revIDESaveStack pStackID put the effective filename of stack tStackName into tStackFilename local tStackFileVersion - global gRevStackStatus if revIDEGetPreference("cPreserveStackVersion") is true and the scriptOnly of stack tMainStack is false then put revIDEStackFileVersion(tStackFilename) into tStackFileVersion @@ -7336,7 +7653,7 @@ on revIDESaveStack pStackID "The minimum stack file version for this stack is %2.", tFileVersions) \ with revIDELocalise("Save as %1", tFileVersions) and revIDELocalise("Save as %2", tFileVersions) and revIDELocalise("Cancel") if it is revIDELocalise("Cancel") then - put "edited" into gREVStackStatus[tStackName] + revIDESetEdited tStackName close stack "revSaving" return "Cancelled" else if it is revIDELocalise("Save as %2", tFileVersions) then @@ -7352,7 +7669,7 @@ on revIDESaveStack pStackID answer revIDELocalise("Saving in script only format will result in loss of data as only the script will be saved." && \ "Are you sure you wish to continue?") with revIDELocalise("No") and revIDELocalise("Yes") if it is not revIDELocalise("Yes") then - put "edited" into gREVStackStatus[tStackName] + revIDESetEdited tStackName close stack "revSaving" return "Cancelled" end if @@ -7419,14 +7736,14 @@ on revIDESaveStack pStackID -- Dispatch the post-save hook, straight after the save, but only if it succeeded. dispatch "revHookPostSaveStack" to me with pStackID - put empty into gREVStackStatus[tStackName] + revIDESetUnedited tStackName local tMainStackList put the mainStack of stack tStackName into tMainStackList put return & the substacks of stack tStackName after tMainStackList repeat for each line tStack in tMainStackList if tStack is empty then next repeat - put empty into gREVStackStatus[tStack] + revIDESetUnedited tStack end repeat revUpdateRecentFiles tStackName end if @@ -7493,15 +7810,14 @@ on revIDESaveStackAs pStackID, pFileName, pVersion answer revIDELocalise("Can't save stack %1 with error:", tLocaliseSubstitutions) & return & tResult close stack "revSaving" else - global gRevStackStatus - put empty into gREVStackStatus[tShortName] + revIDESetUnedited tShortName local tMainStackList put the mainStack of pStackID into tMainStackList put return & the substacks of pStackID after tMainStackList repeat for each line tStack in tMainStackList if tStack is empty then next repeat - put empty into gREVStackStatus[tStack] + revIDESetUnedited tStack end repeat revUpdateRecentFiles the short name of pStackID end if @@ -7602,10 +7918,9 @@ on revIDEActionSaveStackAs pStackID, pSubstackOnly break end switch - global gRevStackStatus # User cancelled the the ask dialog if it is empty then - put "edited" into gREVStackStatus[tShortName] + revIDESetEdited tShortName return "Cancelled" end if @@ -7627,7 +7942,7 @@ on revIDEActionSaveStackAs pStackID, pSubstackOnly "The minimum stack file version for this stack is %2.", tFileVersions) \ with revIDELocalise("Save as %1", tFileVersions) and revIDELocalise("Save as %2", tFileVersions) and revIDELocalise("Cancel") if it is revIDELocalise("Cancel") then - put "edited" into gREVStackStatus[tShortName] + revIDESetEdited tShortName return "Cancelled" else if it is revIDELocalise("Save as %2", tFileVersions) then put tFileVersions[2] into tVersion @@ -7639,7 +7954,7 @@ on revIDEActionSaveStackAs pStackID, pSubstackOnly answer revIDELocalise("Saving in script only format will result in loss of data as only" & \ " the script will be saved. Are you sure you wish to continue?") with revIDELocalise("No") and revIDELocalise("Yes") if it is not revIDELocalise("Yes") then - put "edited" into gREVStackStatus[tShortName] + revIDESetEdited tShortName return "Cancelled" end if end if @@ -7794,13 +8109,18 @@ on revIDECut end if lock screen - lock messages + if the selectedImage is not empty then # If the there is a selection in an image using the image selection tool # Then make sure no text is selected before doing the cut - if the selectedText is not empty then select empty + if the selectedText is not empty then + lock messages + select empty + unlock messages + end if set the defaultStack to revTargetStack(the long id of the selectedImage) cut + unlock screen exit revIDECut end if @@ -7808,7 +8128,7 @@ on revIDECut if revCheckGroupDelete() then cut end if - unlock messages + unlock screen ideMessageSend "ideSelectedObjectChanged" @@ -8225,7 +8545,9 @@ on ideStyleText pSelectedChunk, pSelectedObject, pIsField, pWhich, pValue if pWhich is "superscript" then put -4 into tTextShiftAmount else put 4 into tTextShiftAmount - if the textShift of tTarget is a number then put 0 into tTextShiftAmount + if the textShift of tTarget is a number AND the textShift of tTarget is not 0 then + put 0 into tTextShiftAmount + end if set the textShift of tTarget to tTextShiftAmount break @@ -8370,30 +8692,34 @@ on revIDEToggle pProperty case "Suppress Messages" global gRevSuppressMessages put "suppressMessages" into tToggleMessage + + local tLine if not gREVSuppressMessages then put true into gREVSuppressMessages # Send the suppress messages toggle message before actually suppressing messages ideMessageSend "ideToggleChanged:" & tToggleMessage set the lockCursor to false - repeat for each line l in the pendingMessages - if char 1 to 3 of item 2 of l is not "rev" then cancel (item 1 of l) + repeat for each line tLine in the pendingMessages + if not revIDEObjectIsOnIDEStack(item 4 to -1 of tLine) then + cancel (item 1 of tLine) + end if end repeat - repeat for each line l in the frontScripts - if char 1 to 3 of the short name of l is not "rev" then - put l & cr after sRestoreState["front"] - remove script of l from front + repeat for each line tLine in the frontScripts + if not revIDEObjectIsOnIDEStack(tLine) then + put tLine & cr after sRestoreState["front"] + remove script of tLine from front end if end repeat - repeat for each line l in the backScripts - if char 1 to 3 of the short name of l is not "rev" then - put l & cr after sRestoreState["back"] - remove script of l from back + repeat for each line tLine in the backScripts + if not revIDEObjectIsOnIDEStack(tLine) then + put tLine & cr after sRestoreState["back"] + remove script of tLine from back end if end repeat - repeat for each line l in the stacksInUse - if char 1 to 3 of l is not "rev" then - put l & cr after sRestoreState["inUse"] - stop using stack l + repeat for each line tLine in the stacksInUse + if not revIDEObjectIsOnIDEStack(tLine) then + put tLine & cr after sRestoreState["inUse"] + stop using stack tLine end if end repeat revInternal__LoadLibrary "revNoMessagesLibrary" @@ -8401,14 +8727,14 @@ on revIDEToggle pProperty else revInternal__UnloadLibrary "revNoMessagesLibrary" put false into gREVSuppressMessages - repeat for each line l in sRestoreState["front"] - insert script of l into front + repeat for each line tLine in sRestoreState["front"] + insert script of tLine into front end repeat - repeat for each line l in sRestoreState["back"] - insert script of l into back + repeat for each line tLine in sRestoreState["back"] + insert script of tLine into back end repeat - repeat for each line l in sRestoreState["inUse"] - start using stack l + repeat for each line tLine in sRestoreState["inUse"] + start using stack tLine end repeat delete variable sRestoreState end if @@ -8453,7 +8779,7 @@ on revIDEToggle pProperty case "Rulers" put "rulers" into tToggleMessage if the mode of stack "revRulersH" is not 0 then - revInternal__UnloadLibrary "revRulersScript" + revInternal__UnloadLibrary "revRulersScriptLibrary" lock messages close stack "revRulersH" close stack "revRulersV" @@ -8470,9 +8796,6 @@ on revIDEToggle pProperty break case "Backdrop" if the backDrop is "none" then - if revIDEGetPreference("cBackDropColor") is empty then - revIDESetPreference "cBackDropColor", "black" - end if set the backDrop to revIDEGetPreference("cBackDropColor") revIDESetPreference "cBackDrop", the backDrop else @@ -8864,6 +9187,15 @@ on revIDEActionPasteTextIntoField pField unlock screen end revIDEActionPasteTextIntoField +on revIDEToggleLockTextOfField pField + # Make sure we have an field + if word 1 of pField is not "field" then + exit revIDEToggleLockTextOfField + end if + + set the lockText of pField to not (the lockText of pField) +end revIDEToggleLockTextOfField + on revIDEToggleTraversalOnOfField pField # Make sure we have an field if word 1 of pField is not "field" then @@ -8989,7 +9321,8 @@ on revIDEToggleReshapeGraphic revInternal__LoadLibrary "revReshapeLibrary" revSetMarkers else - revSetMarkers true + revSetMarkers "true" + revInternal__UnloadLibrary "revReshapeLibrary" end if end revIDEToggleReshapeGraphic @@ -9049,13 +9382,13 @@ on revIDERelayerControls pObjectList, pMode case "send to back" sort lines of tLayers numeric descending repeat for each line tLayer in tLayers - set the layer of tObjectArray[tLayer] to bottom + relayer tObjectArray[tLayer] to back of owner end repeat break case "bring to front" sort lines of tLayers numeric ascending repeat for each line tLayer in tLayers - set the layer of tObjectArray[tLayer] to top + relayer tObjectArray[tLayer] to front of owner end repeat break case "move forward" @@ -9330,36 +9663,36 @@ command revIDESuspendDevelopmentTools -- Remove front and back scripts that pertain to the IDE -- If the shift-key is down, we remove *all* 'rev' front and back scripts, including -- the library scripts. - local tScriptsList, tRemoveFrontList, tRemoveBackList + local tScriptsList, tRemoveFrontList, tRemoveBackList, tLine select empty if the shiftKey is down then put the frontScripts into tScriptsList - repeat for each line l in tScriptsList - if char 1 to 3 of the short name of l is "rev" then - put l & cr after tRemoveFrontList - remove script of l from front + repeat for each line tLine in tScriptsList + if revIDEObjectIsOnIDEStack(tLine) then + put tLine & cr after tRemoveFrontList + remove script of tLine from front end if end repeat put the backScripts into tScriptsList - repeat for each line l in tScriptsList - if char 1 to 3 of the short name of l is "rev" then - put l & cr after tRemoveBackList - remove script of l from back + repeat for each line tLine in tScriptsList + if revIDEObjectIsOnIDEStack(tLine) then + put tLine & cr after tRemoveBackList + remove script of tLine from back end if end repeat else put the frontScripts into tScriptsList - repeat for each line l in tScriptsList - if the short name of l is among the items of "revFrontScriptLibrary,revDebugger,revShortCutsLibrary" then - put l & cr after tRemoveFrontList - remove script of l from front + repeat for each line tLine in tScriptsList + if the short name of tLine is among the items of "revFrontScriptLibrary,revDebuggerLibrary,revShortCutsLibrary" then + put tLine & cr after tRemoveFrontList + remove script of tLine from front end if end repeat put the backScripts into tScriptsList - repeat for each line l in tScriptsList - if the short name of l is "revBackScriptLibrary,revShortCutsLibrary" then - put l & cr after tRemoveBackList - remove script of l from back + repeat for each line tLine in tScriptsList + if the short name of tLine is "revBackScriptLibrary,revShortCutsLibrary" then + put tLine & cr after tRemoveBackList + remove script of tLine from back end if end repeat end if @@ -9371,7 +9704,7 @@ command revIDESuspendDevelopmentTools put the openStacks into tList lock messages repeat for each line tStack in tList - if char 1 to 3 of the short name of stack tStack is "rev" or the short name of stack tStack is among the items of "Message Box,Home,answer dialog,ask dialog" then + if revIDEStackNameIsIDEStack(tStack) then # OK-2008-05-23 : Compare the stack's mode to its style. If they are equal then we don't need to store the mode, as opening the # stack will result in the default mode being that which matches its style. local tModeName @@ -9396,8 +9729,9 @@ command revIDESuspendDevelopmentTools put tClosedStacksList into gREVRestore["stacks"] -- Reset the windowBoundingRect - put the windowBoundingRect into gREVRestore["windowBoundingRect"] - set the windowBoundingRect to 0,0,item 3 to 4 of the windowBoundingRect + local tWindowRect + put revIDEStackScreenRect(the short name of the topStack, true) into tWindowRect + set the windowBoundingRect to tWindowRect -- Show the restore dialog lock recent @@ -9464,7 +9798,7 @@ command revIDERestoreDevelopmentTools set the defaultMenuBar to the long id of group "revMenuBar" of stack revIDEPaletteToStackName("menubar") set the width of stack "revMenuBar" to the width of stack "revMenuBar" + 1 -- bug 1806 set the width of stack "revMenuBar" to the width of stack "revMenuBar" - 1 - set the windowBoundingRect to gREVRestore["windowBoundingRect"] + ideSetWindowBoundingRect choose gREVRestore["tool"] -- Restore the script debug mode @@ -9492,9 +9826,9 @@ command revIDECheckForUpdates case "Linux" -- MDW-2015-12-19 [[fix_installer]] LC8-style setup filename if the processor is "x86_64" then - put item 1 to -3 of the filename me & "/setup.x86_64" into tCommand + put item 1 to -4 of the filename of me & "/setup.x86_64" into tCommand else - put item 1 to -3 of the filename me & "/setup.x86" into tCommand + put item 1 to -4 of the filename of me & "/setup.x86" into tCommand end if put tCommand && "install -foregroundupdate" into tCommand break @@ -9532,7 +9866,7 @@ User stacks, script editors, the dictionary and resource center are considered w from the point of view of the menubar */ function revIDEStackIsWindow pStackName - if pStackName begins with revIDEScriptEditorPrefix() or pStackName is "revDictionary" or pStackName is "revResourceCenter" then + if revIDEStackIsIDEWindow(pStackName) then return true end if @@ -10111,6 +10445,10 @@ private function __fetchAndRemoveControlTags pCard return tTags end __fetchAndRemoveControlTags +command revIDETutorialUpdateAndRemoveTags pStackName, @xTags + union xTags with __fetchAndRemoveTags(pStackName) +end revIDETutorialUpdateAndRemoveTags + on revIDETutorialLoad pCourse, pTutorial, pLesson local tLocation put __findTutorialLocation(pCourse, pTutorial, pLesson) into tLocation @@ -10137,7 +10475,7 @@ on revIDETutorialLoad pCourse, pTutorial, pLesson put return & tStackName after tStackList end if - union tTags with __fetchAndRemoveTags(tStackName) + revIDETutorialUpdateAndRemoveTags tStackName, tTags end repeat dispatch "revTutorialResume" to stack "revTutorial" with tStackList, tTags, tLessonDataA["step"] @@ -10369,10 +10707,11 @@ private function escape pString, pConvertLineEndings replace quote with ("\" & quote) in pString if pConvertLineEndings is true then - replace (numToChar(13) & CR) with (CR & numToChar(13)) in pString - replace (CR & numToChar(13)) with CR in pString + replace CRLF with "\n" in pString + replace numToCodepoint(13) with "\n" in pString end if - replace CR with "\n" in pString + replace LF with "\n" in pString + replace numToCodepoint(13) with "\r" in pString //replace "<" with "<" in pString //replace ">" with ">" in pString replace tab with "\t" in pString @@ -10389,53 +10728,106 @@ private function __getLCBSourceFile pFolder return tSource end __getLCBSourceFile -private function revIDEGetDocsAPIData +private function revIDEGetBaseDocsData pWhich local tData - local tAPIPath - put revIDESpecialFolderPath("API") into tAPIPath - put revIDEUTF8FileContents(tAPIPath & slash & "distributed_api.js") into tData + local tAPIPath, tLibs + put revIDESpecialFolderPath("api", pWhich) into tAPIPath + put files(tAPIPath) into tLibs + filter tLibs with "*.js" + local tDoc + repeat for each line tLibraryJS in tLibs + put revIDEUTF8FileContents(tAPIPath & slash & tLibraryJS) into tDoc + if tData is empty then + put tDoc into tData + else + put comma & tDoc after tData + end if + end repeat + return tData +end revIDEGetBaseDocsData + +private function revIDEGetExtensionDocsData pAPI local tExtensionDocsDataA - put revIDEExtensionDocsData() into tExtensionDocsDataA + put revIDEExtensionDocsData(pAPI) into tExtensionDocsDataA local tFolder, tCachedDataFolder set the itemdelimiter to slash + + local tData repeat for each element tExtensionData in tExtensionDocsDataA local tExtensionAPI put tExtensionData["folder"] into tFolder local tSource - put __getLCBSourceFile(tFolder) into tSource + put tExtensionData["source_file"] into tSource # Check if the lcdoc file is out of date - put revEnvironmentUserDocsPath() & slash & the last item of tFolder into tCachedDataFolder + put revEnvironmentUserDocsPath() & slash & tExtensionData["name"] into tCachedDataFolder revIDEEnsurePath tCachedDataFolder - + local tInputs - put tFolder & slash & tSource into tInputs[1] + put empty into tInputs + if tSource is not empty then + put tFolder & slash & tSource into tInputs[1] + end if # If we are running from source, also add the docs parser as an input # dependency of the docs files if not revEnvironmentIsInstalled() then - put the effective filename of stack "revDocsParser" into tInputs[2] + put the effective filename of stack "revDocsParser" into \ + tInputs[the number of elements in tInputs + 1] end if local tNeedUpdate, tError, tAPIDoc put tCachedDataFolder & slash & "api.lcdoc" into tAPIDoc - put revIDEIsFilesetStale(tInputs, \ - tAPIDoc, false, tError) \ + put revIDEIsFilesetStale(tInputs, tAPIDoc, false, tError) \ into tNeedUpdate + # If there is an up-to-date api.lcdoc in the source folder, just copy that across + local tSourceAPI + put tFolder & slash & "api.lcdoc" into tSourceAPI + if there is a file tSourceAPI then + if tSource is empty then + put false into tNeedUpdate + if there is no file tAPIDoc then + revIDESetUTF8FileContents tAPIDoc, revIDEUTF8FileContents(tSourceAPI) + end if + else if tNeedUpdate then + if revIDEIsFilesetStale(tInputs, tSourceAPI, false, tError) \ + is false then + + revIDESetUTF8FileContents tAPIDoc, revIDEUTF8FileContents(tSourceAPI) + put false into tNeedUpdate + end if + end if + end if # Regenerate the lcdoc file if required if tNeedUpdate is true then # Generate the docs text in lcdoc format local tDoc - dispatch function "revDocsGenerateDocsFileFromModularFile" to stack "revDocsParser" with tFolder & slash & tSource - put the result into tDoc - - # Output the lcdoc file - revIDESetUTF8FileContents tAPIDoc, tDoc + if tExtensionData["source_type"] is "lcb" then + dispatch function "revDocsGenerateDocsFileFromModularFile" to stack "revDocsParser" with \ + tFolder & slash & tSource + put the result into tDoc + else if tExtensionData["source_type"] is "lcs" then + local tStack, tPassword + try + put the long id of stack (tFolder & slash & tSource) into tStack + put the password of tStack into tPassword + end try + if tStack is not empty and tPassword is empty then + dispatch function "revDocsGenerateDocsFileFromText" \ + to stack "revDocsParser" with \ + the script of tStack, tStack + put the result into tDoc + end if + end if + if tDoc is not empty then + # Output the lcdoc file + revIDESetUTF8FileContents tAPIDoc, tDoc + end if end if local tAPIJS @@ -10456,23 +10848,36 @@ private function revIDEGetDocsAPIData tExtensionData["author"] put the result into tLibraryArray - dispatch function "revDocsFormatLibraryArrayAsJSON" to stack "revDocsParser" \ + dispatch function "revDocsFormatLibraryDocArrayAsJSON" to stack "revDocsParser" \ with tLibraryArray put the result into tExtensionAPI # Update the dictionary database - ideDocsUpdateDatabase tLibraryArray + ideDocsUpdateDatabase pAPI, tLibraryArray, false revIDESetUTF8FileContents tAPIJS, tExtensionAPI end if if tExtensionAPI is not empty then - put comma & tExtensionAPI after tData + if tData is not empty then + put comma & tExtensionAPI after tData + else + put tExtensionAPI into tData + end if end if end repeat - return tData -end revIDEGetDocsAPIData +end revIDEGetExtensionDocsData + +private function revIDEGetDocsAPIData pWhich + local tData, tExtensions + put revIDEGetBaseDocsData(pWhich) into tData + put revIDEGetExtensionDocsData(pWhich) into tExtensions + if tExtensions is not empty then + put comma & tExtensions after tData + end if + return tData +end revIDEGetDocsAPIData private function revIDEGetDocsGuideData local tData @@ -10491,8 +10896,13 @@ private function revIDEGetDocsGuideData put empty into tExtensionGuide put tExtensionData["folder"] into tFolder put revEnvironmentUserDocsPath() & slash & \ - the last item of tFolder into tCachedDataFolder + tExtensionData["name"] into tCachedDataFolder put tFolder & slash & "guide.md" into tGuideFile + if there is not a file tGuideFile then + -- User widgets have the guide.md in docs/guide/ + put "/docs/guide" after tFolder + put tFolder & slash & "guide.md" into tGuideFile + end if if there is not a file tGuideFile then next repeat revIDEEnsurePath tCachedDataFolder @@ -10510,8 +10920,10 @@ private function revIDEGetDocsGuideData if tGuide is not empty then put "{" & CR after tExtensionGuide - put tab & quote & "name" & quote & ":" && quote & tFolder & quote & comma & CR after tExtensionGuide - put tab & quote & "display name" & quote & ":" && quote & tFolder & quote & comma & CR after tExtensionGuide + put tab & quote & "name" & quote & ":" && quote & tExtensionData["name"] & quote & comma & CR after tExtensionGuide + put tab & quote & "display name" & quote & ":" && quote & tExtensionData["title"] & quote & comma & CR after tExtensionGuide + put tab & quote & "group" & quote & ":" && quote & "Extensions" & quote & comma & CR after tExtensionGuide + put tab & quote & "location" & quote & ":" && quote & tFolder & quote & comma & CR after tExtensionGuide put quote & "data" & quote & ":" & escape(tGuide, true) & CR after tExtensionGuide put "}" after tExtensionGuide @@ -10530,7 +10942,7 @@ private function revIDEGetDocsGuideData return tData end revIDEGetDocsGuideData -on revIDEAddGuideAndRegenerate pGuide +on revIDERegenerateBuiltGuides local tData # Get the location of the distributed guide @@ -10541,47 +10953,44 @@ on revIDEAddGuideAndRegenerate pGuide put revIDEGetDocsGuideData() after tData - if pGuide is not empty then - put comma & pGuide after tData - end if - put CR & tab & "]" & CR & "}" after tData local tDocsCache put revIDESpecialFolderPath("documentation cache") into tDocsCache revIDESetUTF8FileContents tDocsCache & slash & "built_guide.js", tData -end revIDEAddGuideAndRegenerate +end revIDERegenerateBuiltGuides -on revIDEAddAPIAndRegenerate pAPI - local tData - - # Get the location of the distributed API - local tAPIPath - put revIDESpecialFolderPath("API") into tAPIPath - - put "var dictionary_data =" & CR & "{" & CR & tab & quote & "docs" & quote & ":[" after tData - - put revIDEGetDocsAPIData() after tData - - if pAPI is not empty then - put comma & pAPI after tData - end if +constant kAPIs = "LiveCode Script,livecode_script|LiveCode Builder,livecode_builder|LiveCode IDE,livecode_ide" +on revIDERegenerateBuiltAPIs + local tData, tAPIData + set the lineDelimiter to "|" + repeat for each line tAPI in kAPIs + -- For now, the IDE API is BFS only + if item 2 of tAPI is "livecode_ide" and revEnvironmentIsInstalled() then + next repeat + end if + + put revIDEGetDocsAPIData(item 2 of tAPI) into tAPIData + dispatch function "revDocsCreateAPIJSON" to stack "revDocsParser" \ + with item 1 of tAPI, item 2 of tAPI, "", tAPIData + if tData is empty then + put the result into tData + else + put comma & the result after tData + end if + end repeat - put CR & tab & "]" & CR & "}" after tData + local tDictionaryData + put "var dictionary_data =" & return & "{" & return & \ + tab & quote & "docs" & quote & ":[" & \ + tData & return & tab & "]" & return & "}" \ + into tDictionaryData local tDocsCache put revIDESpecialFolderPath("documentation cache") into tDocsCache - revIDESetUTF8FileContents tDocsCache & slash & "built_api.js", tData -end revIDEAddAPIAndRegenerate - -on revIDERegenerateBuiltAPIs - revIDEAddAPIAndRegenerate + revIDESetUTF8FileContents tDocsCache & slash & "built_api.js", tDictionaryData end revIDERegenerateBuiltAPIs -on revIDERegenerateBuiltGuides - revIDEAddGuideAndRegenerate -end revIDERegenerateBuiltGuides - on revIDERegenerateBuiltDictionaryData revIDERegenerateBuiltAPIs revIDERegenerateBuiltGuides @@ -10653,7 +11062,7 @@ private command revIDEGenerateDistributedAPI put the effective filename of stack "revDocsParser" into tInputs[0] put tDocsFolder & slash & "dictionary" into tInputs[1] put tDocsFolder & slash & "glossary" into tInputs[2] - put revIDESpecialFolderPath("api") & slash & "script.js" into tOutput + put revIDESpecialFolderPath("api", "livecode_script") & slash & "script.js" into tOutput put revIDEIsFilesetStale(tInputs, tOutput, true, tError) into tNeedUpdate @@ -10668,11 +11077,11 @@ private command revIDEGenerateDistributedAPI put revDocsParseDictionaryToLibraryArray(tDocsFolder) into tScriptA["doc"] # Update the database - ideDocsUpdateDatabase tScriptA + ideDocsUpdateDatabase "livecode_script", tScriptA, true local tJSON - put revDocsFormatLibraryArrayAsJSON(tScriptA) into tJSON - revIDESetUTF8FileContents revIDESpecialFolderPath("api") & slash & "script.js", \ + put revDocsFormatLibraryDocArrayAsJSON(tScriptA) into tJSON + revIDESetUTF8FileContents revIDESpecialFolderPath("api", "livecode_script") & slash & "script.js", \ tJSON end if @@ -10682,7 +11091,7 @@ private command revIDEGenerateDistributedAPI set the itemdelimiter to slash put empty into tInputs - put revIDESpecialFolderPath("api") & slash & "builder.js" into tOutput + put revIDESpecialFolderPath("api", "livecode_builder") & slash & "builder.js" into tOutput put the effective filename of stack "revDocsParser" into tInputs[0] local tCount put 1 into tCount @@ -10726,42 +11135,115 @@ private command revIDEGenerateDistributedAPI put "dictionary" into tBuilderA["type"] # Update the database - ideDocsUpdateDatabase tBuilderA + ideDocsUpdateDatabase "livecode_builder", tBuilderA, true - put revDocsFormatLibraryArrayAsJSON(tBuilderA) into tJSON - revIDESetUTF8FileContents revIDESpecialFolderPath("api") & slash & "builder.js", \ + put revDocsFormatLibraryDocArrayAsJSON(tBuilderA) into tJSON + revIDESetUTF8FileContents revIDESpecialFolderPath("api", "livecode_builder") & slash & "builder.js", \ tJSON end if # Check to see if we need to regenerate the datagrid docs put empty into tInputs - put revIDESpecialFolderPath("api") & slash & "dg.js" into tOutput + put revIDESpecialFolderPath("api", "livecode_script") & slash & "dg.js" into tOutput put the effective filename of stack "revDocsParser" into tInputs[0] local tDatagridDoc, tFolder put revIDESpecialFolderPath("Documentation") &"/dictionary" into tFolder put tFolder & slash & "datagrid.lcdoc" into tInputs[1] put revIDEIsFilesetStale(tInputs, tOutput, false, tError) into tNeedUpdate - # Regenerate if necessary + # Regenerate if necessary if tNeedUpdate then local tLibA - put revDocsParseDocFileToLibraryArray(tFolder & slash & tDatagridDoc, "Data Grid", "LiveCode") into tLibA + put revDocsParseDocFileToLibraryArray(tFolder & slash & "datagrid.lcdoc", "DataGrid", "LiveCode") into tLibA + # Update the database - ideDocsUpdateDatabase tLibA - put revDocsFormatLibraryArrayAsJSON(tLibA) into tJSON - revIDESetUTF8FileContents revIDESpecialFolderPath("api") & slash & "dg.js", \ + ideDocsUpdateDatabase "livecode_script", tLibA, true + put revDocsFormatLibraryDocArrayAsJSON(tLibA) into tJSON + revIDESetUTF8FileContents revIDESpecialFolderPath("api", "livecode_script") & slash & "dg.js", \ tJSON end if - local tDictionaryData - put revIDEUTF8FileContents(revIDESpecialFolderPath("api") \ - & slash & "script.js") into tDictionaryData - put comma & revIDEUTF8FileContents(revIDESpecialFolderPath("api") \ - & slash & "builder.js") after tDictionaryData - put comma & revIDEUTF8FileContents(revIDESpecialFolderPath("api") \ - & slash & "dg.js") after tDictionaryData - - revIDESetUTF8FileContents revIDESpecialFolderPath("api") \ - & slash & "distributed_api.js", tDictionaryData + local tIDELibsFolder, tIdeSupportFolder + put tRepoPath & "/ide-support" into tIdeSupportFolder + put tRepoPath & "/ide/Toolset/libraries" into tIDELibsFolder + + # Check to see if we need to regenerate the ide dictionary + put empty into tInputs + put the effective filename of stack "revDocsParser" into tInputs[0] + put tIdeSupportFolder into tInputs[1] + put tIDELibsFolder into tInputs[2] + put revIDESpecialFolderPath("api", "livecode_ide") & slash & "ide.js" into tOutput + + put revIDEIsFilesetStale(tInputs, tOutput, true, tError) into tNeedUpdate + # Regenerate dictionary if necessary + if tNeedUpdate then + local tIDELibs, tIDEA, tIDECount, tIDEParsedA + put 1 into tIDECount + put the stackfiles of stack "home" into tIDELibs + split tIDELibs by return and comma + repeat for each key tStackName in tIDELibs + local tStack, tPassword, tDoc + try + put the long id of stack tStackName into tStack + put the password of tStack into tPassword + end try + if tStack is not empty and tPassword is empty then + put revDocsGenerateDocsFileFromText(the script of tStack, \ + tStack) into tDoc + end if + if tDoc is not empty then + put tDoc into tIDEA[tIDECount] + add 1 to tIDECount + end if + end repeat + + local tIDELibraryA + put 1 into tIDECount + repeat for each element tElement in tIDEA + put revDocsParseDocText(tElement) into tIDEParsedA + repeat for each key tEntry in tIDEParsedA["doc"] + put tIDEParsedA["doc"][tEntry] into tIDELibraryA["doc"][tIDECount] + add 1 to tIDECount + end repeat + put empty into tIDEParsedA + end repeat + put "LiveCode IDE" into tIDELibraryA["display name"] + put revDocsModifyForUrl(tIDELibraryA["display name"]) into tIDELibraryA["name"] + put "LiveCode" into tIDELibraryA["author"] + put "dictionary" into tIDELibraryA["type"] + + # Update the database + ideDocsUpdateDatabase "livecode_ide", tIDELibraryA, true + + put revDocsFormatLibraryDocArrayAsJSON(tIDELibraryA) into tJSON + revIDESetUTF8FileContents revIDESpecialFolderPath("api", "livecode_ide") & slash & "ide.js", \ + tJSON + end if + + local tExtractedDocsFolder + put revEnvironmentBinariesPath() & slash & "extracted_docs" into tExtractedDocsFolder + + local tFiles + put files(tExtractedDocsFolder) into tFiles + filter tFiles with "*.lcdoc" + + set the itemDelimiter to "." + local tFile + repeat for each line tFile in tFiles + # Check to see if we need to regenerate the docs + put empty into tInputs + put revIDESpecialFolderPath("api", "livecode_script") & slash & toLower(item 1 to -2 of tFile) & ".js" into tOutput + put the effective filename of stack "revDocsParser" into tInputs[0] + put tExtractedDocsFolder & slash & tFile into tInputs[1] + put revIDEIsFilesetStale(tInputs, tOutput, false, tError) into tNeedUpdate + # Regenerate if necessary + if tNeedUpdate then + put revDocsParseDocFileToLibraryArray(tExtractedDocsFolder & slash & tFile, item -2 of tFile, "LiveCode") into tLibA + # Update the database + ideDocsUpdateDatabase "livecode_script", tLibA, true + put revDocsFormatLibraryDocArrayAsJSON(tLibA) into tJSON + revIDESetUTF8FileContents tOutput, tJSON + end if + end repeat end revIDEGenerateDistributedAPI on revIDEEnsureDictionaryUrl pWhich @@ -10821,29 +11303,20 @@ end revIDEGenerateDictionaryHTML local sNamesToColorsA, sColorsToNamesA -private function __colorsResourcePath - set the itemdelimiter to slash - return item 1 to -3 of the filename of stack "home" & "/Toolset/resources/supporting_files/colors" -end __colorsResourcePath - -private function fetchMapping pFile - local tData, tMappingA - put url ("file:" & __colorsResourcePath() & slash & pFile) into tData - repeat for each line tLine in tData - if token 1 of tLine is empty then - next repeat - end if - put item 2 to -1 of tLine into tMappingA[item 1 of tLine] - end repeat - return tMappingA -end fetchMapping - private on __fetchNamesToColors - put fetchMapping("namesToColors.txt") into sNamesToColorsA + local tColorRGB + + repeat for each line tColorName in the colorNames + set the colorOverlay["color"] of the templateGraphic to tColorName + put the colorOverlay["color"] of the templateGraphic into tColorRGB + put tColorRGB into sNamesToColorsA[tColorName] + end repeat end __fetchNamesToColors private on __fetchColorsToNames - put fetchMapping("namesToColors.txt") into sColorsToNamesA + repeat for each line tColor in the colorNames + put tColor into sColorsToNamesA[revIDENamedColorToRGB(tColor)] + end repeat end __fetchColorsToNames function revIDENamedColorToRGB pName @@ -10877,6 +11350,7 @@ on revIDESetGeometry pObject, pProperty, pGeometryArray repeat for each key tKey in pGeometryArray["geometry"] revSetGeometry tKey, pGeometryArray["geometry"][tKey] end repeat + revClearExtraGeometrySettings end revIDESetGeometry function revIDEGetGeometry pObject, pProperty @@ -10896,11 +11370,18 @@ end revIDEGetGeometry private function __publicScriptHandlers pObject local tScript, tHandlers + repeat while pObject is not empty try - put the script of pObject into tScript + put the script of pObject & return after tScript + put the owner of pObject into pObject catch tError - return empty + exit repeat end try + end repeat + + if tScript is empty then + return empty + end if repeat for each line tLine in tScript if token 1 of tLine is among the items of "on,command" then @@ -10913,9 +11394,9 @@ private function __publicScriptHandlers pObject return tHandlers end __publicScriptHandlers -private command __tryToDoScriptInObject pObject, pToDo, @rValidScript +private command __TryToAutocompleteScript pObject, pScript, @rNewScript if pObject is empty then - return "No such object" + return empty end if local tHandlerList @@ -10930,20 +11411,20 @@ private command __tryToDoScriptInObject pObject, pToDo, @rValidScript -- Check to see if any handler in the message path matches the executed script local tTargetHandler, tIsPutOrGet - put token 1 of pToDo into tTargetHandler + put token 1 of pScript into tTargetHandler put false into tIsPutOrGet if tTargetHandler is among the items of "put,get" then put true into tIsPutOrGet - if token 2 of pToDo is "the" then - put token 3 of pToDo into tTargetHandler + if token 2 of pScript is "the" then + put token 3 of pScript into tTargetHandler else - put token 2 of pToDo into tTargetHandler + put token 2 of pScript into tTargetHandler end if end if - local tDoScript - put pToDo into tDoScript - set the itemdelimiter to ";" + local tDoScript, tFound + put false into tFound + put pScript into tDoScript repeat for each line tLine in tHandlerList local tHandlerName, tHandlerType put segment 1 of tLine into tHandlerType @@ -10955,99 +11436,111 @@ private command __tryToDoScriptInObject pObject, pToDo, @rValidScript local tParams if not tIsPutOrGet and tHandlerType is "M" then -- If this is a command that matches, just send the message - put pToDo into tDoScript + put pScript into tDoScript + put true into tFound exit repeat else if tHandlerType is "F" then -- otherwise this is a function that matches if tIsPutOrGet then - put pToDo into tDoScript + put pScript into tDoScript else -- autocomplete the 'put' if necessary - put "put" && pToDo into tDoScript + put "put" && pScript into tDoScript end if + put true into tFound exit repeat end if end repeat - - local tError - ideCompileCheck tDoScript - put the result into tError - if tError is empty then - try - send "-- execute in object context" & return & tDoScript to pObject - catch tError - - end try - end if - if tError is empty then - put tDoScript into rValidScript - end if - - return tError -end __tryToDoScriptInObject -command ideExecuteScript pScript, pDefaultStack, pIntelligenceObject, pDebugMode, @rValidScript - local tOldDefault - put the defaultStack into tOldDefault - if pDefaultStack is not empty then - set the defaultStack to pDefaultStack - end if + put tDoScript into rNewScript + return tFound +end __TryToAutocompleteScript + +command ideExecuteScript pScript, pObject, pDebugMode, @rValidScript + local tDefaultStack + put the defaultStack into tDefaultStack if pScript is empty then exit ideExecuteScript - # Try executing as a command first - if word 1 of pScript is among the lines of the commandNames then - ideDoMessage pScript, pDebugMode - if the result is empty then - put pScript into rValidScript - return empty - end if + if pObject is empty then + put the long id of this card of the defaultStack into pObject + else + set the defaultStack to the short name of ideStackOfObject(pObject) + end if + + -- Need to target 'this card' if a stack is selected + if word 1 of pObject is "stack" then + put the long id of this card of pObject into pObject end if -- check if word 1 of pScript is a handler in the intelligence object's script or the default stack's script - local tValidScript - __tryToDoScriptInObject pIntelligenceObject, pScript, tValidScript - if the result is not empty then - __tryToDoScriptInObject the long id of this card of the defaultStack, pScript, tValidScript + local tScript, tValidScript, tCompileError, tOriginalCompileError + ideCompileCheck pScript + put the result into tOriginalCompileError + + __TryToAutocompleteScript pObject, pScript, tScript + -- If we found a handler already, just execute the script + if the result is true then + ideCompileCheck tScript + put the result into tCompileError + if tCompileError is empty then + put tScript into tValidScript + end if end if - if the result is empty then - put tValidScript into rValidScript - return empty + # Try executing as a command + if tValidScript is empty and \ + word 1 of tScript is among the lines of the commandNames then + ideCompileCheck tScript + put the result into tCompileError + if tCompileError is empty then + put tScript into tValidScript + end if end if - put empty into tValidScript --deals with the put command, if the put command cannot be executed as is then: --the message box will attempt to auto complete the typing of a name of an object property and the contents of that property into the results area --where the intelligence object has been set in the preferences (currently selected object or the object directly underneath the mouse) ;s lock screen - if not (token 1 of pScript is "get") then + if tValidScript is empty and not (token 1 of tScript is "get") then # Try executing as a function or property local tTryProperty # Build the string so that it starts with "put the" - if not (token 1 of pScript is "the") then - put "the" && pScript into tTryProperty + if not (token 1 of tScript is "the") then + put "the" && tScript into tTryProperty else - put pScript into tTryProperty + put tScript into tTryProperty end if if not (token 1 of tTryProperty is "put ") then put "put " before tTryProperty end if set the wholeMatches to true - local tIsProperty - put word 3 of tTryProperty is among the lines of the propertyNames into tIsProperty + local tIsProperty, tToken + put word 3 of tTryProperty into tToken + put tToken is among the lines of the propertyNames into tIsProperty + + # Try as a function or global property + if tIsProperty or tToken is among the lines of the functionNames then + ideCompileCheck tTryProperty + put the result into tCompileError + if tCompileError is empty then + put tTryProperty into tValidScript + end if + end if - # Try as an object property of the intelligence object - if tValidScript is empty and tIsProperty and pIntelligenceObject is not empty then - ideDoMessage tTryProperty && "of" && pIntelligenceObject, pDebugMode - if the result is empty then + # If it wasn't valid as an object property of the intelligence object + # then try as an object property of the intelligence object + if tValidScript is empty and tIsProperty and pObject is not empty then + ideCompileCheck tTryProperty && "of" && pObject + put the result into tCompileError + if tCompileError is empty then local tName # pIntelligence object may be a bad reference or no longer exist try - put the name of pIntelligenceObject into tName + put the name of pObject into tName catch tError end try if tError is empty then @@ -11056,49 +11549,35 @@ command ideExecuteScript pScript, pDefaultStack, pIntelligenceObject, pDebugMode end if end if - # If it wasn't valid as an object property of the intelligence object - # then try as a function or global property - if tValidScript is empty then - if tIsProperty or word 3 of tTryProperty is among the lines of the functionNames then - ideDoMessage tTryProperty, pDebugMode - if the result is empty then - put tTryProperty into tValidScript - end if - end if - end if - ## If not a function, global property or object property then ## try as a boolean expression + if tValidScript is empty then local tBooleanExpression - # Build the string so that it starts with "put" - put "put" && pScript into tBooleanExpression - - # Try as a boolean expression - if tValidScript is empty then - ideDoMessage tBooleanExpression, pDebugMode - if the result is empty then + put "put" && tScript into tBooleanExpression + ideCompileCheck tBooleanExpression + put the result into tCompileError + if tCompileError is empty then put tBooleanExpression into tValidScript end if end if - end if - # Otherwise just try as is and ensure we get the correct error if tValidScript is empty then - ideDoMessage pScript, pDebugMode - if the result is empty then + if tOriginalCompileError is not empty then + return tOriginalCompileError for error + else put pScript into tValidScript end if end if - - if tValidScript is empty then - return the result - end if unlock screen + local tResult put tValidScript into rValidScript - return empty + ideDoMessage tValidScript, pDebugMode, pObject + put the result into tResult + set the defaultStack to tDefaultStack + return tResult for value end ideExecuteScript /** @@ -11125,42 +11604,81 @@ on ideCompileCheck pScript return empty end ideCompileCheck -command ideDoMessage pScript, pDebugMode - ideCompileCheck pScript - if the result is not empty then - return "compile error" & return & the result - end if +function ideIsDebugging + return revTopMostScriptEditor("debug") is not empty +end ideIsDebugging + +private command __removeMessageBoxFromDebugContexts @xContexts + local tTarget + put the long id of the target into tTarget + local tFirst, tLast, tCount, tObject + put 1 into tFirst + put 0 into tLast + repeat for each line tLine in xContexts + add 1 to tCount + put item 2 of tLine into tObject + if tObject is not empty then + put the long id of tObject into tObject + end if + -- Message box execution always begins with 'returnInField' from the target + if item 3 of tLine is "returnInField" and \ + tObject is tTarget then + put tCount into tLast + end if + end repeat - do "global" && the globals + delete line tFirst to tLast of xContexts +end __removeMessageBoxFromDebugContexts + +function ideDeclaredGlobalVariables + -- Return globals without 'each' or any of the env vars + local tGlobals + put the globals into tGlobals + replace comma with return in tGlobals + filter tGlobals without "$*" + filter tGlobals without "each" + return tGlobals +end ideDeclaredGlobalVariables + +command ideDoMessage pScript, pDebugMode, pObject + local tScriptError, tGlobals + put ideDeclaredGlobalVariables() into tGlobals + replace return with comma in tGlobals + put "global" && tGlobals & return before pScript - local tScriptError try if pDebugMode then - # OK-2010-01-02: Remove the message box itself from the debug context. - # Line 1 will be revDebugDoMessage - # Line 2 is revExecuteMessage (message box field) - # Line 3 is returnInField (message box field) - # Line 4 will hopefully be the user code (assuming of course the message box isnt' changed). - # Note that this code is called from both the single and multi-line fields, but luckily they both - # have the same number of calls. - local tContext, tContextNumber - get revDebuggerContexts() - put line 4 of it into tContext - + local tContext, tScriptEditor + put revTopMostScriptEditor("debug") into tScriptEditor + -- Ensure a user-selected debug context in the script editor is the first + -- option for execution context in the message box + if tScriptEditor is not empty then + dispatch function "seGetSelectedDebugContext" to tScriptEditor + put the result into tContext + end if + -- Otherwise, remove the chain of message box execution contexts + -- from the list, and take the next one. + if tContext is empty then + local tContexts + put revDebuggerContexts() into tContexts + __removeMessageBoxFromDebugContexts tContexts + put line 1 of tContexts into tContext + end if local tResult revDebuggerDo pScript, tContext - get the result - put line 1 of it into tResult - put line 2 to -1 of it into tScriptError + put the result into tResult + put line 2 to -1 of tResult into tScriptError + put line 1 of tResult into tResult + else - do pScript + if pObject is empty then + put the long id of this card of this stack into pObject + end if + send script pScript to pObject end if catch tScriptError end try - if tScriptError is not empty then - put "execution error" & return before tScriptError - end if return tScriptError end ideDoMessage @@ -11386,6 +11904,8 @@ function revIDEObjectIsOpen pLongID return exists(pLongID) end revIDEObjectIsOpen +constant kExtensionErrorCode = 863 +constant kExternalHandlerErrorCode = 634 /** Returns the error description associated with the given error code. @@ -11397,11 +11917,29 @@ Returns : The description of the specified error. >*Note:* if <pType> is "warning", this function will currently return empty. */ -function revIDELookupError pType, pCode +function revIDELookupError pType, pError + local tCode + put item 1 of line 1 of pError into tCode if pType is "compilation" then - return line pCode of the scriptParsingErrors + return line tCode of the scriptParsingErrors else if pType is "execution" then - return line pCode of the scriptExecutionErrors + if tCode is kExtensionErrorCode then + local tLine, tFile, tDesc + put item 4 to -1 of line 2 of pError into tDesc + put item 4 to -1 of line 3 of pError into tFile + put item 4 to -1 of line 4 of pError into tLine + return merge("LCB Error in file [[tFile]] at line [[tLine]]: [[tDesc]]") + else if tCode is kExternalHandlerErrorCode then + return "External handler execution error:" && item 4 to -1 of line 1 of pError + end if + + if tCode is an integer then + get line tCode of the scriptExecutionErrors + if it is not empty then + return it + end if + end if + return tCode else if pType is "warning" then return empty end if @@ -11701,3 +12239,81 @@ function revIDEObjectsAreSelectable pObjects return true end revIDEObjectsAreSelectable + +on revIDEFindMoreWidgets + lock screen + revIDEOpenPalette "extension manager" + send "showExtensionStore" to \ + stack revIDEPaletteToStackName("extension manager") + unlock screen +end revIDEFindMoreWidgets + +command ideShowUpgradeOptions + if ideCanShowUpgradeOptions() then + lock screen + if the mode of stack revIDEPaletteToStackName("start center") is 0 then + revIDEOpenPalette "start center" + end if + dispatch "ideAction" to stack revIDEPaletteToStackName("start center") with "launchAdWithUrl" + unlock screen + else if ideShouldShowUpgradeOptions() then + local tUpgradeEdition + put revEnvironmentEditionProperty("upgrade_edition") into tUpgradeEdition + launch url revEnvironmentEditionProperty("edition_external_url", tUpgradeEdition) + end if +end ideShowUpgradeOptions + +function ideCanShowUpgradeOptions + return ideShouldShowUpgradeOptions() \ + and hasConnection() \ + and not revIDEBrowserWidgetUnavailable() +end ideCanShowUpgradeOptions + +function ideShouldShowUpgradeOptions + return \ + revEnvironmentEditionProperty("upgrade_mini_url") is not empty \ + and revEnvironmentEditionProperty("upgrade_edition") is not empty +end ideShouldShowUpgradeOptions + +private function hasConnection + return url("http://google.com/") is not empty +end hasConnection + +on ideDesktopChanged + ideSetWindowBoundingRect +end ideDesktopChanged + +/** + +Update the window bounding rect for the current IDE palette layout + +*/ + +command ideSetWindowBoundingRect + local tMenuBar + put revIDEPaletteToStackName("menubar") into tMenuBar + + local tTools + put revIDEPaletteToStackName("tools") into tTools + + local tToolsSlop + put the width of stack tTools + 50 into tToolsSlop + + local tWindowRect + put revIDEStackScreenRect(tMenuBar, true) into tWindowRect + if tWindowRect is not empty then + if the screen of stack tTools is the screen of stack tMenubar then + if the right of stack tTools < (item 1 of tWindowRect + tToolsSlop) then + put the right of stack tTools + 5 into item 1 of tWindowRect + else if the left of stack tTools > (item 3 of tWindowRect - tToolsSlop) then + put the left of stack tTools - 5 into item 3 of tWindowRect + end if + end if + + -- revMenubar may not be visible on macOS with text and icons off + if the visible of stack tMenubar then + put the bottom of stack tMenuBar + 5 into item 2 of tWindowRect + end if + set the windowBoundingRect to tWindowRect + end if +end ideSetWindowBoundingRect diff --git a/Toolset/libraries/revidelibrary.livecodescript b/Toolset/libraries/revidelibrary.livecodescript deleted file mode 100644 index 0737dcbce8..0000000000 --- a/Toolset/libraries/revidelibrary.livecodescript +++ /dev/null @@ -1,518 +0,0 @@ -script "revoldidelibrary" - -on revLoadLibrary - if the target is me then - insert the script of me into back - end if -end revLoadLibrary - -on revUnloadLibrary - if the target is me then - remove the script of me from back - end if -end revUnloadLibrary - -//////////////////////////////////////////////////////////////////////////////// - -# LG-2008-04-22 -command revIDEStartCenterCheckOnStackClose pStackName - -- Want to check if there are any user stacks open. If there are not we want to display the - -- start center. - - if revOkTarget(the long id of stack pStackName) or the cStartPageShow of stack "revPreferences" is false or the cReloadStartCenter of stack "revPreferences" is false then - exit revIDEStartCenterCheckOnStackClose - end if - - # LG-2008-06-20 - Bug 6600 - # The stack being closed may still be in the openStacks as revIDEStartCenterCheckOnStackClose is no longer sent in time. - # Therefore the stack must be filtered out of the openStacks list. - repeat for each line openStack in the openStacks - -- Check is openStack is a user stack - --if char 1 to 3 of openStack is not "rev" or openStack is not among the items of "Message Box,Home,answer dialog,ask dialog,script debugger,file selector,color chooser" then - if ((not revOkTarget(the long id of stack openStack)) and (the short name of stack openStack is not pStackName)) then - exit revIDEStartCenterCheckOnStackClose - end if - - # OK-2009-01-20 : Additionally there are certain IDE stacks which we don't want the start centre to jump up over. These are - # basically most windows other than the tools palette, menubar and possibly message box and property inspector. - if (the short name of stack openStack is not pStackName) and (openStack is not among the lines of revIDESideWindows()) then - exit revIDEStartCenterCheckOnStackClose - end if - end repeat - - # LG-2008-06-20 - Bug 6600 - # Now sent in time so the start center will appear after the stack disappears. - send "revIDEShowStartCenter" to me in 0 milliseconds -end revIDEStartCenterCheckOnStackClose - -# Returns -# A list of the short names of IDE stacks which are considered not to be "main windows", i.e they could be open most of the time -# Even when the user is not actually using them. This may require some tweaking to get right... -function revIDESideWindows - local tWindows - put "revMenubar" & return & \ - "revTools" & return & \ - "message box" & return & \ - "revApplicationOverview" & return into tWindows - - # The property inspector needs a little more work to deal with... - repeat for each line tStack in the mainstacks - if word 1 of the short name of stack tStack is "revPropertyPalette" and word 2 of the short name of stack tStack is a number then - put the short name of stack tStack & return after tWindows - end if - end repeat - delete the last char of tWindows - - return tWindows -end revIDESideWindows - -command revIDEShowSearchEngine - revIDEOpenPalette "search engine" -end revIDEShowSearchEngine - -# OK-2008-06-24: Bug 6575 - Message box command + m shortcut not working in script editor -# Description -# Launches and shows the message box, the same as the Tools -> Message box menu item -command revIDEShowMessageBox - # BB-2015-05-21 - This handler should ultimately be deleted. Calling into new IDE library - # to open the message box. - revIDEOpenPalette "message box" - exit revIDEShowMessageBox - - set the cUserOpen of stack "Message Box" to true - if the mode of stack "Message Box" is 0 then - set the visible of stack "Message Box" to true - go stack "Message Box" - else if "Message Box" is not in the openStacks then - if the selectedField is not "message" or the number of this card of stack "message box" is not 1 then - lock screen - go card 1 of stack "Message box" - set the title of stack "Message box" to "Message Box (Single Line)" - --set the hilitedButtonName of group "button tabs" of stack "message box" to "Single Line" - # DW-2013-03-26 - # fixing message box not hiliting first line in 6.0rc3 due to objects being referenced by number rather than a unique name - --focus on field 1 of stack "message box" - --focus on field 2 of stack "message box" - focus on field 3 of stack "message box" - select text of field 3 of stack "message box" - end if - else - set the cUserOpen of stack "Message Box" to false - close stack "Message Box" - end if -end revIDEShowMessageBox - ---local sAddedObjects - -# Parameters -# pRootObject : the object to list the tree for, this is a reference to any LiveCode object -# pIncludeSubstacks : if pRootObject is a mainstack, this determines whether or not its substacks are searched. Otherwise its ignored. -# Returns -# Empty if all possible objects were returned, otherwise a warning string explaining why some / all were ommited. -# Description -# rList will be set to the list of objects underneath the root object. This is inclusive, i.e. it includes pRootObject. -# If pRootObject is a mainstack, the stack will be searched, followed by all mainstacks if pIncludeSubstacks is true. -# If pRootObject is a stack, the object list is the stack, all its cards, and all objects on each card -# If pRootObject is a card the list is the card and all objects on it -# If pRootObject is any other control, the list is pRootObject. -function revIDEListSearchObjectTree pRootObject, pObeyDontSearch, pMarked, pIncludeSubstacks, pIgnorePasswordProtected, pScriptsOnly, @xList - --delete variable sAddedObjects - - # Put the root object into the list first. If this is not possible because to dontSearch or card marking then - # return an error and put empty into the list. What might also happen is that one of the child objects - # as its dontSearch set to true. In this case, we'll return a partial list. - if pObeyDontSearch and word 1 of the name of pRootObject is among the words of "field group card" and the dontSearch of pRootObject then - return "dontSearch of root object set" - end if - - # Set the HCAddressing property of the owning stack of pRootObject to false, as this will mess - # up everything otherwise. - local tOldHCAddressing - put the hcAddressing of stack revTargetStack(pRootObject) into tOldHCAddressing - set the hcAddressing of stack revTargetStack(pRootObject) to false - - # If the root object is a mainstack, we add the stack itself, then all its substacks if applicable - local tResult - switch word 1 of pRootObject - case "stack" - if the mainstack of pRootObject is the short name of pRootObject and pIncludeSubstacks then - addStack pRootObject, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly - put the result into tResult - - repeat for each line tSubstack in the substacks of pRootObject - local tSubstackResult - addStack the name of stack tSubstack, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly - put the result into tSubstackResult - if tResult is empty then - put tSubstackResult into tResult - end if - end repeat - else - # If its not a mainstack, or we're not adding substacks, just add the stack - addStack pRootObject, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly - put the result into tResult - end if - break - case "card" - # If its a card then add the card and all its controls - addCard pRootObject, pObeyDontSearch, pMarked, xList, pScriptsOnly - put the result into tResult - break - case "group" - # If its a group then add the group and all its control - addGroup pRootObject, pObeyDontSearch, xList, pScriptsOnly - put the result into tResult - break - default - # All other objects, i.e non-containers, just add the single object to the list. - addObject pRootObject, pObeyDontSearch, xList, pScriptsOnly - put the result into tResult - break - end switch - - set the hcAddressing of stack revTargetStack(pRootObject) to tOldHCAddressing - - return tResult -end revIDEListSearchObjectTree - -private command addObject pObject, pObeyDontSearch, @xList, pScriptsOnly - if pObeyDontSearch and word 1 of the name of pObject is among the words of "card group field" and the dontSearch of pObject then - return "dontSearch set on object" - end if - - if not pScriptsOnly or the script of pObject is not empty then - put true into xList[the long id of pObject] - end if - - local tBehavior - put the behavior of pObject into tBehavior - repeat while exists(tBehavior) - put true into xList[the long id of tBehavior] - put the behavior of tBehavior into tBehavior - end repeat - - return empty -end addObject - -private command addCard pCard, pObeyDontSearch, pMarked, @xList, pScriptsOnly - if pMarked is not empty and pMarked is not the mark of pCard then - return "marked mismatch" - end if - - # Add the card itself - local tResult - addObject pCard, pObeyDontSearch, xList, pScriptsOnly - put the result into tResult - - # Add the non-grouped controls - local tObjectResult - local tControlID - repeat for each line tControlID in the childControlIDs of pCard - # Don't add groups - if word 1 of the name of control id tControlID of pCard is among the words of "group bkgnd" then - next repeat - end if - - # Don't add grouped controls - if the owner of control id tControlID of pCard is not empty and word 1 of the name of the owner of control id tControlID of pCard is among the words of "group bkgnd" then - next repeat - end if - - addObject the long id of control id tControlID of pCard, pObeyDontSearch, xList, pScriptsOnly - put the result into tObjectResult - - if tResult is empty then - put tObjectResult into tResult - end if - end repeat - - # Add any groups. - local tGroup, tGroupResult - local tID - repeat for each line tId in the groupIds of pCard - put the long id of group id tId of pCard into tGroup - if the sharedBehavior of tGroup then - next repeat - end if - - # Note that if a group on the card does not have its backgroundBehavior set, but is placed on multiple cards, - # it will be duplicated in the list. I'm not sure if this is correct or not... - addGroup tGroup, pObeyDontSearch, xList, pScriptsOnly - put the result into tGroupResult - - if tResult is empty then - put tGroupResult into tResult - end if - end repeat - - return tResult -end addCard - -private command addGroup pGroup, pObeyDontSearch, @xList, pScriptsOnly - if pObeyDontSearch and the dontSearch of pGroup then - return "dontSearch set on group" - end if - - local tResult - addObject pGroup, pObeyDontSearch, xList, pScriptsOnly - put the result into tResult - - local tObjectResult - local tControlID - repeat for each line tControlID in the childControlIDs of pGroup - addObject the long id of control id tControlID of pGroup, pObeyDontSearch, xList, pScriptsOnly - put the result into tObjectResult - - if tResult is empty then - put tObjectResult into tResult - end if - end repeat - - return tResult -end addGroup - -private command addStack pStack, pObeyDontSearch, pMarked, pIgnorePasswordProtected, @xList, pScriptsOnly - local tResult - - if pIgnorePasswordProtected then - try - get the script of pStack - catch tError - return "Stack password protected" - end try - end if - - # The stack itself - addObject pStack, pObeyDontSearch, xList, pScriptsOnly - put the result into tResult - - # All shared groups groups on the stack - local tSharedGroupResult - local tGroupID - repeat for each line tGroupID in the sharedGroupIDs of pStack - addGroup the long id of control id tGroupID of pStack, pObeyDontSearch, xList, pScriptsOnly - put the result into tSharedGroupResult - - if tResult is empty then - put tSharedGroupResult into tResult - end if - end repeat - - # All the cards on the stack - local tCardResult - local tCardID - repeat for each line tCardID in the cardIDs of pStack - addCard the long id of card id tCardID of pStack, pObeyDontSearch, pMarked, xList, pScriptsOnly - put the result into tCardResult - - if tResult is empty then - put tCardResult into tResult - end if - end repeat - - return tResult -end addStack - -function revIDEImmediateOwner pObject, pType - # Start with the object itself - local tObject - put revRuggedId(pObject) into tObject - - repeat - # First check if the current object is of the type we want, if so, return it - if pType is "card" then - if word 1 of the name of tObject is "card" then - return tObject - else if word 1 of the name of tObject is "stack" then - return tObject - end if - end if - - # If the object has no owner we can't continue, this can only happen if the caller requests the card that owns a stack, - # so is a bug. - if the owner of tObject is empty then - exit repeat - end if - - # This means the object was not of the type we wanted, but it does have an owner, so we check its owner. - put the owner of tObject into tObject - end repeat - - # Should never get here... -end revIDEImmediateOwner - -private function idePrefToPropertyName pPref - return "c" & pPref -end idePrefToPropertyName - -function revIDEPrefGet pPref - local tPropname - put idePrefToPropertyName(pPref) into tPropname - return the tPropname of stack "revPreferences" -end revIDEPrefGet - -command revIDEPrefSet pPref, pValue - local tPropname - put idePrefToPropertyName(pPref) into tPropname - set the tPropname of stack "revPreferences" to pValue -end revIDEPrefSet - -//////////////////////////////////////////////////////////////////////////////// - -# Parameters -# pPath : The full path of a stack -# Description -# Returns true if pPath is the path of an IDE stack, false otherwise. -function revIDEStack pPath - # OK-2008-06-16 : There is of course one other IDE mainstack that is not a stackFile of stack "Home".... - if pPath is the filename of stack "Home" then - return true - end if - - local tStackfilePath - repeat for each line tStackfile in the stackfiles of stack "home" - put item 2 to -1 of tStackfile into tStackfilePath - if pPath is tStackfilePath then - return true - end if - end repeat - return false -end revIDEStack - -# OK-2007-11-29 : Bug 5597 -# Parameters -# <none> -# Description -# Sent when the user has requested to "Save" either by clicking in File -> Save As or by pressing ctrl-s. -# This command attempts to save the topStack if appropriate. Note that if the shiftKey is down, the command -# exits, this was kept to preserve existing behavior. Sends "closeField" to the focused field of the property -# inspector if it is open. -command revIDESaveRequest - if the mode of the topStack is not 1 then - exit revIDESaveRequest - end if - if the shiftKey is down then - exit revIDESaveRequest - end if - - if (the focusedObject) is not empty and word 1 of revTargetStack(the focusedObject) is "revPropertyPalette" and word 1 of (the focusedObject) is "field" then - local tObject - put the focusedObject into tObject - send "closeField" to tObject - end if - - if the effective filename of the topStack is not empty then - revSave (the short name of the topStack) - else - revSaveAs (the short name of the topStack) - end if -end revIDESaveRequest - -# Returns whether the path pPath is case sensitive. pPath must point to a file. -private function utilityPathIsCaseSensitive pPath - local tFolder - - local tOriginalFolder - put the folder into tOriginalFolder - - set the itemDelimiter to slash - put item 1 to -2 of pPath into tFolder - - local tIsCaseSensitive - put false into tIsCaseSensitive - - set the folder to tolower(tFolder) - if the result is not empty then - put true into tIsCaseSensitive - end if - - set the folder to toupper(tFolder) - if the result is not empty then - put true into tIsCaseSensitive - end if - - set the folder to tOriginalFolder - - return tIsCaseSensitive -end utilityPathIsCaseSensitive - -# Given two different paths where the filename is the same, returns a portion of pPath appropriate to differentiate -# it from pDuplicatePath. This is used for the recent file menu. This is slightly experimental in an attempt to -# improve the existing way of doing this. -private function utilityDifferentialPath pPath, pDuplicatePath - set the itemDelimiter to slash - - local tItemCount - put the number of items of pPath into tItemCount - - if the number of items of pPath = 1 then - return pPath - end if - - # tDifferentialPath will be the path that we return. We always return at least the filename. - local tDifferentialPath - put item -1 of pPath into tDifferentialPath - - # Starting with the item before the filename, loop back through pPath, comparing each item with pDuplicatePath. - # Once a difference is found, we make the different item the first item in our differential path. If the path is - # relative, add "../" at the start. - repeat with tItem = -2 down to -(tItemCount) - put item tItem of pPath & slash before tDifferentialPath - if item tItem of pPath <> item tItem of pDuplicatePath then - if tItem <> 1 then - put "../" before tDifferentialPath - exit repeat - end if - end if - end repeat - if the first char of tDifferentialPath is slash then - delete the first char of tDifferentialPath - end if - - return tDifferentialPath -end utilityDifferentialPath - -# Wrapper round the platform to ease testing of platform specific code -private function utilityGetPlatform - return the platform -end utilityGetPlatform - -# Returns the *actual* path of the file specified by pPath. Returns empty if the file doesnt exist -private function utilityCanonicalizePath pPath - local tDefaultFolder - put the defaultFolder into tDefaultFolder - - set the itemDelimiter to slash - - local tFolder, tFilename - put item 1 to -2 of pPath into tFolder - put item -1 of pPath into tFilename - - set the defaultFolder to tFolder - - set the caseSensitive to utilityPathIsCaseSensitive(pPath) - - local tFiles - put the files into tFiles - - local tLineNumber - set the wholeMatches to true - put lineOffset(tFilename, tFiles) into tLineNumber - - local tExists - if tLineNumber = 0 then - put false into tExists - else - put true into tExists - end if - - local tCanonicalFolder - put the defaultFolder into tCanonicalFolder - set the defaultFolder to tDefaultFolder - - if tExists then - return tCanonicalFolder & slash & line tLineNumber of tFiles - else - return empty - end if -end utilityCanonicalizePath diff --git a/Toolset/libraries/revidemessagehandlerlibrary.livecodescript b/Toolset/libraries/revidemessagehandlerlibrary.livecodescript index 2fdb4ef99f..a4e6ce0cd5 100644 --- a/Toolset/libraries/revidemessagehandlerlibrary.livecodescript +++ b/Toolset/libraries/revidemessagehandlerlibrary.livecodescript @@ -1,17 +1,17 @@ script "revIdeMessageHandlerLibrary" -on revLoadLibrary +on extensionInitialize if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is not me then - pass "revUnloadLibrary" + pass "extensionFinalize" end if remove the script of me from front -end revUnloadLibrary +end extensionFinalize ################################# # Messages handled and sent on to object @@ -343,7 +343,7 @@ end moveControl on mouseMove pX, pY local tTarget, tParams put the long id of the target into tTarget - if not revIDEStackIsIDEStack(tTarget) then + if not revIDEObjectIsOnIDEStack(tTarget) then put pX into tParams[1] put pY into tParams[2] put tTarget into tParams[3] @@ -355,7 +355,7 @@ end mouseMove on mouseDown pButton local tTarget, tParams put the long id of the target into tTarget - if not revIDEStackIsIDEStack(tTarget) then + if not revIDEObjectIsOnIDEStack(tTarget) then put pButton into tParams[1] put tTarget into tParams[2] send "ideMessageSendWithParameters" && "ideMouseDown, tTarget, tParams" to stack "revIDELibrary" in 0 milliseconds @@ -366,7 +366,7 @@ end mouseDown on mouseUp pButton local tTarget, tParams put the long id of the target into tTarget - if not revIDEStackIsIDEStack(tTarget) then + if not revIDEObjectIsOnIDEStack(tTarget) then put pButton into tParams[1] put tTarget into tParams[2] send "ideMessageSendWithParameters" && "ideMouseUp, tTarget, tParams" to stack "revIDELibrary" in 0 milliseconds @@ -377,7 +377,7 @@ end mouseUp on mouseDoubleUp pButton local tTarget, tParams put the long id of the target into tTarget - if not revIDEStackIsIDEStack(tTarget) then + if not revIDEObjectIsOnIDEStack(tTarget) then put pButton into tParams[1] put tTarget into tParams[2] send "ideMessageSendWithParameters" && "ideMouseDoubleUp, tTarget, tParams" to stack "revIDELibrary" in 0 milliseconds @@ -391,7 +391,29 @@ on closeStackRequest -- closeStackRequest is sent to the card, so the owner of the target is the stack put the long id of the owner of the target into tLongID if not revIDEStackIsIDEStack(tLongID) then - send "ideMessageSendWithTrigger" && "ideCloseStackRequest, tLongID, tLongID" to stack "revIDELibrary" in 0 milliseconds + send "ideMessageSendWithParameters" && "ideCloseStackRequest, tLongID, tLongID" to stack "revIDELibrary" in 0 milliseconds end if pass closeStackRequest end closeStackRequest + +on msgChanged pHandler, pLine + local tTarget + put the long id of the target into tTarget + + local tParams + put tTarget into tParams[1] + put pHandler into tParams[2] + put pLine into tParams[3] + put msg into tParams[4] + send "ideMessageSendWithParameters" && "ideMsgChanged, tTarget, tParams" to stack "revIDELibrary" in 0 milliseconds + pass msgChanged +end msgChanged + +on logChanged pLog + send "ideMessageSend ideExtensionLog, pLog" to stack "revIDELibrary" in 0 milliseconds +end logChanged + +on desktopChanged + send "ideMessageSend ideDesktopChanged" to stack "revIDELibrary" in 0 milliseconds + pass desktopChanged +end desktopChanged diff --git a/Toolset/libraries/revinitialisationlibrary.livecodescript b/Toolset/libraries/revinitialisationlibrary.livecodescript index 2f1c614576..ee68643138 100644 --- a/Toolset/libraries/revinitialisationlibrary.livecodescript +++ b/Toolset/libraries/revinitialisationlibrary.livecodescript @@ -3,7 +3,9 @@ // sLoadedLibraries["library name"] = true local sLoadedLibraries -command revInternal__LoadLibrary pLibrary +constant kLCLibraryPrefix = "com.livecode.library" + +command revInternal__LoadLibrary pLibrary, pFullPath // Create the path to the library file. Assumption is made that the directory, file and stack name are all the same. //set the itemdel to "/" @@ -15,68 +17,62 @@ command revInternal__LoadLibrary pLibrary return "Library" && pLibrary && "already loaded as" && sLoadedLibraries[pLibrary] end if - // AL-2015-02-20: [[ IDE Restructure ]] Look for libraries in the correct locations. - set the itemDelimiter to "." - if the environment begins with "development" then - local tLibraryPath, tLibSuffix - - if not revEnvironmentIsInstalled() then - -- look for libraries in parent repository - if there is a file (revEnvironmentRepositoryPath() & "/ide-support/" & pLibrary & ".livecodescript") then - put revEnvironmentRepositoryPath() & "/ide-support/" & pLibrary & ".livecodescript" into tLibraryPath - else - put the last item of pLibrary into tLibSuffix - if there is a file (revEnvironmentRepositoryPath() & "/extensions/script-libraries/" & tLibSuffix & slash & tLibSuffix & ".livecodescript") then - put revEnvironmentRepositoryPath() & "/extensions/script-libraries/" & tLibSuffix & slash & tLibSuffix & ".livecodescript" into tLibraryPath - end if - end if - end if - - if tLibraryPath is empty then - if there is a file (revEnvironmentToolsetPath() & "/libraries/" & pLibrary & ".livecodescript") then - put revEnvironmentToolsetPath() & "/libraries/" & pLibrary & ".livecodescript" into tLibraryPath - else - put the last item of pLibrary into tLibSuffix - if there is a file (revEnvironmentToolsetPath() & "/libraries/" & tLibSuffix & slash & tLibSuffix & ".livecodescript") then - put revEnvironmentToolsetPath() & "/libraries/" & tLibSuffix & slash & tLibSuffix & ".livecodescript" into tLibraryPath - end if - end if - end if - set the itemDelimiter to comma - - if tLibraryPath is empty then - answer "no file for library" && pLibrary - end if - - try - // Get its name - local tStackName - put the name of stack tLibraryPath into tStackName - send "revLoadLibrary" to stack tStackName - put tStackName into sLoadedLibraries[pLibrary] - return true - catch tError - answer "Error while loading stack:" && tLibraryPath - end try - + local tStackName + if there is a stack pLibrary then + put pLibrary into tStackName + else if there is a stack (kLCLibraryPrefix & "." & pLibrary) then + put kLCLibraryPrefix & "." & pLibrary into tStackName + else if the environment begins with "development" and \ + there is a stack pFullPath then + put the short name of stack pFullPath into tStackName else + return "no stack for library" && pLibrary + end if + + local tError, tLegacyError + try + // TODO: Remove legacy message name + dispatch "revLoadLibrary" to stack tStackName + if it is not "handled" then + throw "No revLoadLibrary handler found" + end if + catch tLegacyError + end try + + if tLegacyError is not empty then try - send "revLoadLibrary" to stack pLibrary + send "extensionInitialize" to stack tStackName catch tError - write ("Error" && tError && "while loading stack:" && pLibrary) to stderr end try end if + + if tError is not empty then + write ("Error" && tError && "while loading stack:" && pLibrary) \ + & return to stderr + return "Error loading" && pLibrary & return & tError + end if + + put tStackName into sLoadedLibraries[pLibrary] + return empty end revInternal__LoadLibrary command revInternal__LoadIfLibrary pLibrary try - if the revAvailableHandlers of stack pLibrary contains "revLoadLibrary" then - send "revLoadLibrary" to stack pLibrary - local tStackName - put the name of stack pLibrary into tStackName - put tStackName into sLoadedLibraries[pLibrary] - return true + local tAvailable, tMsg + put the revAvailableHandlers of stack pLibrary into tAvailable + if tAvailable contains "extensionInitialize" then + put "extensionInitialize" into tMsg + // TODO: Remove legacy message name + else if tAvailable contains "revLoadLibrary" then + put "revLoadLibrary" into tMsg + else + throw "not a library" end if + send tMsg to stack pLibrary + local tStackName + put the name of stack pLibrary into tStackName + put tStackName into sLoadedLibraries[pLibrary] + return true end try delete stack pLibrary return false @@ -92,16 +88,30 @@ command revInternal__UnloadLibrary pLibraryName put sLoadedLibraries[pLibraryName] into tStackName if there is not a stack tStackName then return "library not loaded" + local tError, tLegacyError try - // Request the library shuts down - send "revUnloadLibrary" to stack tStackName - - delete variable sLoadedLibraries[pLibraryName] - - return true - catch tError - return "Error while unloading library. Library" && pLibraryName && "did not complete the reVUnloadLibrary request" + // TODO: Remove legacy message name + dispatch "revUnloadLibrary" to stack tStackName + if it is not "handled" then + throw "No revUnloadLibrary handler found" + end if + catch tLegacyError end try + + if tLegacyError is not empty then + try + // Request the library shuts down + send "extensionFinalize" to stack tStackName + catch tError + end try + end if + + if tError is not empty then + return "Error while unloading library. Library" && pLibraryName \ + && "did not complete the extensionFinalize request" + end if + delete variable sLoadedLibraries[pLibraryName] + return empty end revInternal__UnloadLibrary function revInternal__ListLoadedLibraries @@ -111,6 +121,10 @@ function revInternal__ListLoadedLibraries return tLibs end revInternal__ListLoadedLibraries +function revInternal__LoadedLibraryStackName pLibName + return sLoadedLibraries[pLibName] +end revInternal__LoadedLibraryStackName + command revInternal__SetAppIcon pAppIcon global gRevAppIcon set the paintCompression to "png" -- match the engine @@ -122,3 +136,45 @@ command revInternal__SetSmallAppIcon pSmallAppIcon set the paintCompression to "png" -- match the engine put pSmallAppIcon into gRevSmallAppIcon end revInternal__SetSmallAppIcon + +command revInternal_SetJAVA_HOME + if $JAVA_HOME is empty then + local tPath + switch the platform + case "MacOS" + put word 1 to -1 of shell("/usr/libexec/java_home") into tPath + break + case "Linux" + local tJAVAC + put "/bin/javac" into tJAVAC + put word 1 to -1 of shell("/usr/bin/env readlink -f /usr" & tJAVAC) into tPath + if there is a file tPath and tPath ends with tJAVAC then + set the itemDelimiter to slash + delete item -2 to -1 of tPath + end if + break + end switch + if there is a folder tPath then + put tPath into $JAVA_HOME + end if + end if +end revInternal_SetJAVA_HOME + +command revInternal_SetCLASSPATH + local tJarFiles, tFolder, tClasspath + put specialFolderPath("resources") & "/Externals/JVM" into tFolder + + put files(tFolder) into tJarFiles + filter tJarFiles with "*.jar" + + repeat for each line tJar in tJarFiles + put tFolder & slash before tJar + if tClasspath is empty then + put tJar into tClasspath + else + put ":" & tJar after tClasspath + end if + end repeat + + put tClasspath into $CLASSPATH +end revInternal_SetCLASSPATH diff --git a/Toolset/libraries/revmetadatalibrary.livecodescript b/Toolset/libraries/revmetadatalibrary.livecodescript index 8a9424ed94..f57345ddcd 100644 --- a/Toolset/libraries/revmetadatalibrary.livecodescript +++ b/Toolset/libraries/revmetadatalibrary.livecodescript @@ -1,16 +1,16 @@ script "revmetadatalibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize ################################################################################ # diff --git a/Toolset/libraries/revnomessageslibrary.livecodescript b/Toolset/libraries/revnomessageslibrary.livecodescript index 88afaac377..2973b1137b 100644 --- a/Toolset/libraries/revnomessageslibrary.livecodescript +++ b/Toolset/libraries/revnomessageslibrary.livecodescript @@ -1,17 +1,17 @@ script "revnomessageslibrary" -on revLoadLibrary +on extensionInitialize // SN-2015-05-13: [[ Bug 15365 ]] Make sure that we don't catch - // revLoadLibrary message if we are not the target + // extensionInitialize message if we are not the target if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of stack "revNoMessagesLibrary" into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize remove the script of stack "revNoMessagesLibrary" from front -end revUnloadLibrary +end extensionFinalize --Bug 5765: Added try/catches to handle errors. # OK-2008-03-13 : Bug 6009 and 6007, Added pass to metacard to mouseDown and all key messages. Added explicit @@ -182,8 +182,8 @@ end closeField on exitField if revOKTarget() then pass exitField try - if "exitField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send exitField to stack "revFrontScriptLibrary" - if "exitField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send exitField to stack "revBackScriptLibrary" + if "exitField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "exitField" to stack "revFrontScriptLibrary" + if "exitField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "exitField" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -286,8 +286,8 @@ end functionKey on pasteKey if revOKTarget() then pass pasteKey try - if "pasteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send pasteKey to stack "revFrontScriptLibrary" - if "pasteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send pasteKey to stack "revBackScriptLibrary" + if "pasteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "pasteKey" to stack "revFrontScriptLibrary" + if "pasteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "pasteKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -299,8 +299,8 @@ end pasteKey on cutKey if revOKTarget() then pass cutKey try - if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send cutKey to stack "revFrontScriptLibrary" - if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send cutKey to stack "revBackScriptLibrary" + if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "cutKey" to stack "revFrontScriptLibrary" + if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "cutKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -312,8 +312,8 @@ end cutKey on copyKey if revOKTarget() then pass copyKey try - if "copyKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send copyKey to stack "revFrontScriptLibrary" - if "copyKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send copyKey to stack "revBackScriptLibrary" + if "copyKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "copyKey" to stack "revFrontScriptLibrary" + if "copyKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "copyKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -325,8 +325,8 @@ end copyKey on backSpaceKey if revOKTarget() then pass backSpaceKey try - if "backSpaceKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send backSpaceKey to stack "revFrontScriptLibrary" - if "backSpaceKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send backSpaceKey to stack "revBackScriptLibrary" + if "backSpaceKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "backSpaceKey" to stack "revFrontScriptLibrary" + if "backSpaceKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "backSpaceKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -338,8 +338,8 @@ end backSpaceKey on deleteKey if revOKTarget() then pass deleteKey try - if "deleteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteKey to stack "revFrontScriptLibrary" - if "deleteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteKey to stack "revBackScriptLibrary" + if "deleteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteKey" to stack "revFrontScriptLibrary" + if "deleteKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -351,8 +351,8 @@ end deleteKey on returnInField if revOKTarget() then pass returnInField try - if "returnInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send returnInField to stack "revFrontScriptLibrary" - if "returnInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send returnInField to stack "revBackScriptLibrary" + if "returnInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "returnInField" to stack "revFrontScriptLibrary" + if "returnInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "returnInField" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -365,8 +365,8 @@ end returnInField on enterInField if revOKTarget() then pass enterInField try - if "enterInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send enterInField to stack "revFrontScriptLibrary" - if "enterInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send enterInField to stack "revBackScriptLibrary" + if "enterInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "enterInField" to stack "revFrontScriptLibrary" + if "enterInField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "enterInField" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -379,8 +379,8 @@ end enterInField on returnKey if revOKTarget() then pass returnKey try - if "returnKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send returnKey to stack "revFrontScriptLibrary" - if "returnKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send returnKey to stack "revBackScriptLibrary" + if "returnKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "returnKey" to stack "revFrontScriptLibrary" + if "returnKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "returnKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -393,8 +393,8 @@ end returnKey on enterKey if revOKTarget() then pass enterKey try - if "enterKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send enterKey to stack "revFrontScriptLibrary" - if "enterKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send enterKey to stack "revBackScriptLibrary" + if "enterKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "enterKey" to stack "revFrontScriptLibrary" + if "enterKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "enterKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -407,8 +407,8 @@ end enterKey on idle if revOKTarget() then pass idle try - if "idle" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send idle to stack "revFrontScriptLibrary" - if "idle" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send idle to stack "revBackScriptLibrary" + if "idle" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "idle" to stack "revFrontScriptLibrary" + if "idle" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "idle" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -433,8 +433,8 @@ end controlKeyDown on focusIn if revOKTarget() then pass focusIn try - if "focusIn" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send focusIn to stack "revFrontScriptLibrary" - if "focusIn" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send focusIn to stack "revBackScriptLibrary" + if "focusIn" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "focusIn" to stack "revFrontScriptLibrary" + if "focusIn" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "focusIn" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -445,8 +445,8 @@ end focusIn on focusOut if revOKTarget() then pass focusOut try - if "focusOut" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send focusOut to stack "revFrontScriptLibrary" - if "focusOut" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send focusOut to stack "revBackScriptLibrary" + if "focusOut" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "focusOut" to stack "revFrontScriptLibrary" + if "focusOut" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "focusOut" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -469,8 +469,8 @@ end scrollBarDrag on preOpenCard if revOKTarget() then pass preOpenCard try - if "preOpenCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send preOpenCard to stack "revFrontScriptLibrary" - if "preOpenCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send preOpenCard to stack "revBackScriptLibrary" + if "preOpenCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "preOpenCard" to stack "revFrontScriptLibrary" + if "preOpenCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "preOpenCard" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -481,8 +481,8 @@ end preOpenCard on openCard if revOKTarget() then pass openCard try - if "openCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send openCard to stack "revFrontScriptLibrary" - if "openCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send openCard to stack "revBackScriptLibrary" + if "openCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "openCard" to stack "revFrontScriptLibrary" + if "openCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "openCard" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -497,7 +497,7 @@ on preOpenStack # stack had been opened. Changed so that the target can be forwarded to revFrontScript. #if "preOpenStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send preOpenStack to stack "revFrontScriptLibrary" revIDEHandleNewStack the long id of the target - if "preOpenStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send preOpenStack to stack "revBackScriptLibrary" + if "preOpenStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "preOpenStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -508,8 +508,8 @@ end preOpenStack on openStack if revOKTarget() then pass openStack try - if "openStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send openStack to stack "revFrontScriptLibrary" - if "openStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send openStack to stack "revBackScriptLibrary" + if "openStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "openStack" to stack "revFrontScriptLibrary" + if "openStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "openStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -520,8 +520,8 @@ end openStack on startUp if revOKTarget() then pass startUp try - if "startUp" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send startUp to stack "revFrontScriptLibrary" - if "startUp" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send startUp to stack "revBackScriptLibrary" + if "startUp" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "startUp" to stack "revFrontScriptLibrary" + if "startUp" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "startUp" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -532,8 +532,8 @@ end startUp on closeStack if revOKTarget() then pass closeStack try - if "closeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send closeStack to stack "revFrontScriptLibrary" - if "closeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send closeStack to stack "revBackScriptLibrary" + if "closeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "closeStack" to stack "revFrontScriptLibrary" + if "closeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "closeStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then --write tError & return to stderr @@ -566,8 +566,8 @@ end closeStackRequest on quitMC if revOKTarget() then pass quitMC try - if "quitMC" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send quitMC to stack "revFrontScriptLibrary" - if "quitMC" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send quitMC to stack "revBackScriptLibrary" + if "quitMC" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "quitMC" to stack "revFrontScriptLibrary" + if "quitMC" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "quitMC" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -578,8 +578,8 @@ end quitMC on playStopped if revOKTarget() then pass playStopped try - if "playStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send playStopped to stack "revFrontScriptLibrary" - if "playStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send playStopped to stack "revBackScriptLibrary" + if "playStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "playStopped" to stack "revFrontScriptLibrary" + if "playStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "playStopped" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -590,8 +590,8 @@ end playStopped on moveStopped if revOKTarget() then pass moveStopped try - if "moveStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send moveStopped to stack "revFrontScriptLibrary" - if "moveStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send moveStopped to stack "revBackScriptLibrary" + if "moveStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "moveStopped" to stack "revFrontScriptLibrary" + if "moveStopped" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "moveStopped" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -600,16 +600,17 @@ on moveStopped end moveStopped on nameChanged pOldName, pNewName - if revOKTarget() then pass nameChanged - try - put the long id of the target into tTarget - if "nameChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "nameChanged pOldName, pNewName, tTarget" to stack "revFrontScriptLibrary" - if "nameChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "nameChanged pOldName, pNewName, tTarget" to stack "revBackScriptLibrary" - catch tError - if gREVDevelopment then - writeError (tError) - end if - end try + if revOKTarget() then pass nameChanged + local tTarget + try + put the long id of the target into tTarget + if "nameChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "nameChanged pOldName, pNewName, tTarget" to stack "revFrontScriptLibrary" + if "nameChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "nameChanged pOldName, pNewName, tTarget" to stack "revBackScriptLibrary" + catch tError + if gREVDevelopment then + writeError (tError) + end if + end try end nameChanged on idChanged pOldID, pNewID @@ -627,8 +628,8 @@ end idChanged on saveRequest if revOKTarget() then pass saveRequest try - if "saveRequest" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send saveRequest to stack "revFrontScriptLibrary" - if "saveRequest" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send saveRequest to stack "revBackScriptLibrary" + if "saveRequest" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "saveRequest" to stack "revFrontScriptLibrary" + if "saveRequest" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "saveRequest" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -640,9 +641,9 @@ end saveRequest on moveControl if revOKTarget() then pass moveControl try - if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send moveControl to stack "revFrontScriptLibrary" - if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send moveControl to stack "revBackScriptLibrary" - if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revGeometryLibrary" then send moveControl to stack "revGeometryLibrary" + if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "moveControl" to stack "revFrontScriptLibrary" + if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "moveControl" to stack "revBackScriptLibrary" + if "moveControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revGeometryLibrary" then send "moveControl" to stack "revGeometryLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -653,9 +654,9 @@ end moveControl on resizeControl if revOKTarget() then pass resizeControl try - if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send resizeControl to stack "revFrontScriptLibrary" - if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send resizeControl to stack "revBackScriptLibrary" - if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revGeometryLibrary" then send resizeControl to stack "revGeometryLibrary" + if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "resizeControl" to stack "revFrontScriptLibrary" + if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "resizeControl" to stack "revBackScriptLibrary" + if "resizeControl" is among the lines of the cREVGeneral["handlerlist"] of stack "revGeometryLibrary" then send "resizeControl" to stack "revGeometryLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -682,8 +683,8 @@ end menuPick on selectionChanged if revOKTarget() then pass selectionChanged try - if "selectionChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send selectionChanged to stack "revFrontScriptLibrary" - if "selectionChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send selectionChanged to stack "revBackScriptLibrary" + if "selectionChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "selectionChanged" to stack "revFrontScriptLibrary" + if "selectionChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "selectionChanged" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -694,8 +695,8 @@ end selectionChanged on selectedObjectChanged if revOKTarget() then pass selectedObjectChanged try - if "selectedObjectChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send selectedObjectChanged to stack "revFrontScriptLibrary" - if "selectedObjectChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send selectedObjectChanged to stack "revBackScriptLibrary" + if "selectedObjectChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "selectedObjectChanged" to stack "revFrontScriptLibrary" + if "selectedObjectChanged" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "selectedObjectChanged" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -731,8 +732,8 @@ end moveStack on closeCard if revOKTarget() then pass closeCard try - if "closeCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send closeCard to stack "revFrontScriptLibrary" - if "closeCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send closeCard to stack "revBackScriptLibrary" + if "closeCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "closeCard" to stack "revFrontScriptLibrary" + if "closeCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "closeCard" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -743,8 +744,8 @@ end closeCard on resumeStack if revOKTarget() then pass resumeStack try - if "resumeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send resumeStack to stack "revFrontScriptLibrary" - if "resumeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send resumeStack to stack "revBackScriptLibrary" + if "resumeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "resumeStack" to stack "revFrontScriptLibrary" + if "resumeStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "resumeStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -756,7 +757,7 @@ on suspendStack if revOKTarget() then pass suspendStack try if "suspendStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "revIDESuspendStackFront" to stack "revFrontScriptLibrary" - if "suspendStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send suspendStack to stack "revBackScriptLibrary" + if "suspendStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "suspendStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -767,8 +768,8 @@ end suspendStack on iconifyStack if revOKTarget() then pass iconifyStack try - if "iconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send iconifyStack to stack "revFrontScriptLibrary" - if "iconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send iconifyStack to stack "revBackScriptLibrary" + if "iconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "iconifyStack" to stack "revFrontScriptLibrary" + if "iconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "iconifyStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -812,25 +813,11 @@ on currentTimeChanged pTime end try end currentTimeChanged -on cutKey - if revOKTarget() then pass cutKey - try - if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send cutKey to stack "revFrontScriptLibrary" - if "cutKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send cutKey to stack "revBackScriptLibrary" - catch tError - if gREVDevelopment then - writeError (tError) - end if - end try - - pass cutKey to metacard -end cutKey - on deletebackground if revOKTarget() then pass deletebackground try - if "deletebackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deletebackground to stack "revFrontScriptLibrary" - if "deletebackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deletebackground to stack "revBackScriptLibrary" + if "deletebackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deletebackground" to stack "revFrontScriptLibrary" + if "deletebackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deletebackground" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -841,8 +828,8 @@ end deletebackground on deleteButton if revOKTarget() then pass deleteButton try - if "deleteButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteButton to stack "revFrontScriptLibrary" - if "deleteButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteButton to stack "revBackScriptLibrary" + if "deleteButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteButton" to stack "revFrontScriptLibrary" + if "deleteButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteButton" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -853,8 +840,8 @@ end deleteButton on deletecard if revOKTarget() then pass deletecard try - if "deletecard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deletecard to stack "revFrontScriptLibrary" - if "deletecard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deletecard to stack "revBackScriptLibrary" + if "deletecard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deletecard" to stack "revFrontScriptLibrary" + if "deletecard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deletecard" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -865,8 +852,8 @@ end deletecard on deleteEPS if revOKTarget() then pass deleteEPS try - if "deleteEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteEPS to stack "revFrontScriptLibrary" - if "deleteEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteEPS to stack "revBackScriptLibrary" + if "deleteEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteEPS" to stack "revFrontScriptLibrary" + if "deleteEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteEPS" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -877,8 +864,8 @@ end deleteEPS on deleteField if revOKTarget() then pass deleteField try - if "deleteField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteField to stack "revFrontScriptLibrary" - if "deleteField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteField to stack "revBackScriptLibrary" + if "deleteField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteField" to stack "revFrontScriptLibrary" + if "deleteField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteField" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -889,8 +876,8 @@ end deleteField on deleteGraphic if revOKTarget() then pass deleteGraphic try - if "deleteGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteGraphic to stack "revFrontScriptLibrary" - if "deleteGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteGraphic to stack "revBackScriptLibrary" + if "deleteGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteGraphic" to stack "revFrontScriptLibrary" + if "deleteGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteGraphic" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -901,8 +888,8 @@ end deleteGraphic on deleteImage if revOKTarget() then pass deleteImage try - if "deleteImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deleteImage to stack "revFrontScriptLibrary" - if "deleteImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deleteImage to stack "revBackScriptLibrary" + if "deleteImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deleteImage" to stack "revFrontScriptLibrary" + if "deleteImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deleteImage" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -913,8 +900,8 @@ end deleteImage on deletePlayer if revOKTarget() then pass deletePlayer try - if "deletePlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send deletePlayer to stack "revFrontScriptLibrary" - if "deletePlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send deletePlayer to stack "revBackScriptLibrary" + if "deletePlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "deletePlayer" to stack "revFrontScriptLibrary" + if "deletePlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "deletePlayer" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -925,8 +912,8 @@ end deletePlayer on dragMove if revOKTarget() then pass dragMove try - if "dragMove" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send dragMove to stack "revFrontScriptLibrary" - if "dragMove" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send dragMove to stack "revBackScriptLibrary" + if "dragMove" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "dragMove" to stack "revFrontScriptLibrary" + if "dragMove" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "dragMove" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -937,8 +924,8 @@ end dragMove on dragEnter if revOKTarget() then pass dragEnter try - if "dragEnter" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send dragEnter to stack "revFrontScriptLibrary" - if "dragEnter" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send dragEnter to stack "revBackScriptLibrary" + if "dragEnter" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "dragEnter" to stack "revFrontScriptLibrary" + if "dragEnter" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "dragEnter" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -961,8 +948,8 @@ end errorDialog on escapeKey if revOKTarget() then pass escapeKey try - if "escapeKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send escapeKey to stack "revFrontScriptLibrary" - if "escapeKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send escapeKey to stack "revBackScriptLibrary" + if "escapeKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "escapeKey" to stack "revFrontScriptLibrary" + if "escapeKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "escapeKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -973,8 +960,8 @@ end escapeKey on help if revOKTarget() then pass help try - if "help" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send help to stack "revFrontScriptLibrary" - if "help" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send help to stack "revBackScriptLibrary" + if "help" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "help" to stack "revFrontScriptLibrary" + if "help" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "help" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -985,8 +972,8 @@ end help on libraryStack if revOKTarget() then pass libraryStack try - if "libraryStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send libraryStack to stack "revFrontScriptLibrary" - if "libraryStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send libraryStack to stack "revBackScriptLibrary" + if "libraryStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "libraryStack" to stack "revFrontScriptLibrary" + if "libraryStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "libraryStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -997,8 +984,8 @@ end libraryStack on newBackground if revOKTarget() then pass newBackground try - if "newBackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newBackground to stack "revFrontScriptLibrary" - if "newBackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newBackground to stack "revBackScriptLibrary" + if "newBackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newBackground" to stack "revFrontScriptLibrary" + if "newBackground" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newBackground" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1009,8 +996,8 @@ end newBackground on NewButton if revOKTarget() then pass NewButton try - if "NewButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send NewButton to stack "revFrontScriptLibrary" - if "NewButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send NewButton to stack "revBackScriptLibrary" + if "NewButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "NewButton" to stack "revFrontScriptLibrary" + if "NewButton" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "NewButton" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1021,8 +1008,8 @@ end NewButton on newPlayer if revOKTarget() then pass newPlayer try - if "newPlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newPlayer to stack "revFrontScriptLibrary" - if "newPlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newPlayer to stack "revBackScriptLibrary" + if "newPlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newPlayer" to stack "revFrontScriptLibrary" + if "newPlayer" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newPlayer" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1033,8 +1020,8 @@ end newPlayer on newCard if revOKTarget() then pass newCard try - if "newCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newCard to stack "revFrontScriptLibrary" - if "newCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newCard to stack "revBackScriptLibrary" + if "newCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newCard" to stack "revFrontScriptLibrary" + if "newCard" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newCard" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1045,8 +1032,8 @@ end newCard on newEPS if revOKTarget() then pass newEPS try - if "newEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newEPS to stack "revFrontScriptLibrary" - if "newEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newEPS to stack "revBackScriptLibrary" + if "newEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newEPS" to stack "revFrontScriptLibrary" + if "newEPS" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newEPS" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1057,8 +1044,8 @@ end newEPS on newField if revOKTarget() then pass newField try - if "newField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newField to stack "revFrontScriptLibrary" - if "newField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newField to stack "revBackScriptLibrary" + if "newField" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newField" to stack "revFrontScriptLibrary" + if "newField" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newField" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1069,8 +1056,8 @@ end newField on newGraphic if revOKTarget() then pass newGraphic try - if "newGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newGraphic to stack "revFrontScriptLibrary" - if "newGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newGraphic to stack "revBackScriptLibrary" + if "newGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newGraphic" to stack "revFrontScriptLibrary" + if "newGraphic" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newGraphic" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1081,8 +1068,8 @@ end newGraphic on newGroup if revOKTarget() then pass newGroup try - if "newGroup" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newGroup to stack "revFrontScriptLibrary" - if "newGroup" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newGroup to stack "revBackScriptLibrary" + if "newGroup" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newGroup" to stack "revFrontScriptLibrary" + if "newGroup" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newGroup" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1093,8 +1080,8 @@ end newGroup on newImage if revOKTarget() then pass newImage try - if "newImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newImage to stack "revFrontScriptLibrary" - if "newImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newImage to stack "revBackScriptLibrary" + if "newImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newImage" to stack "revFrontScriptLibrary" + if "newImage" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newImage" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1105,8 +1092,8 @@ end newImage on newScrollbar if revOKTarget() then pass newScrollbar try - if "newScrollbar" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newScrollbar to stack "revFrontScriptLibrary" - if "newScrollbar" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newScrollbar to stack "revBackScriptLibrary" + if "newScrollbar" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newScrollbar" to stack "revFrontScriptLibrary" + if "newScrollbar" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newScrollbar" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1117,8 +1104,8 @@ end newScrollbar on newStack if revOKTarget() then pass newStack try - if "newStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send newStack to stack "revFrontScriptLibrary" - if "newStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send newStack to stack "revBackScriptLibrary" + if "newStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "newStack" to stack "revFrontScriptLibrary" + if "newStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "newStack" to stack "revBackScriptLibrary" catch tError if gRevDevelopment then writeError (tError) @@ -1285,8 +1272,8 @@ end socketTimeout on tabKey if revOKTarget() then pass tabKey try - if "tabKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send tabKey to stack "revFrontScriptLibrary" - if "tabKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send tabKey to stack "revBackScriptLibrary" + if "tabKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "tabKey" to stack "revFrontScriptLibrary" + if "tabKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "tabKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1299,8 +1286,8 @@ end tabKey on undoKey if revOKTarget() then pass undoKey try - if "undoKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send undoKey to stack "revFrontScriptLibrary" - if "undoKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send undoKey to stack "revBackScriptLibrary" + if "undoKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "undoKey" to stack "revFrontScriptLibrary" + if "undoKey" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "undoKey" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) @@ -1313,8 +1300,8 @@ end undoKey on uniconifyStack if revOKTarget() then pass uniconifyStack try - if "uniconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send uniconifyStack to stack "revFrontScriptLibrary" - if "uniconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send uniconifyStack to stack "revBackScriptLibrary" + if "uniconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revFrontScriptLibrary" then send "uniconifyStack" to stack "revFrontScriptLibrary" + if "uniconifyStack" is among the lines of the cREVGeneral["handlerlist"] of stack "revBackScriptLibrary" then send "uniconifyStack" to stack "revBackScriptLibrary" catch tError if gREVDevelopment then writeError (tError) diff --git a/Toolset/libraries/revprintlibrary.livecodescript b/Toolset/libraries/revprintlibrary.livecodescript index 6556cb42ee..eaeabd6b82 100644 --- a/Toolset/libraries/revprintlibrary.livecodescript +++ b/Toolset/libraries/revprintlibrary.livecodescript @@ -1,16 +1,16 @@ script "revprintlibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize ----------------------printing handlers local lPageNumber, pageNumber --holds lPageNumber between handlers @@ -41,8 +41,11 @@ on revPrintText pText,pHeader,pFooter,pSourceFieldRef,pHeaderFldRef,pFooterFldRe local tPrintMargins --margins stored in array for script simplification local tPageWidth,tPageHeight --height and width of the page local tScrolling,tPageLine,tScrollList --scroll values for text height calculations + local tDefaultStack lock messages --General Initialization + put the defaultStack into tDefaultStack + if the printPageNumber is empty then if lAnswerPrinter is empty then put true into lAnswerPrinter if lPageSetUp is empty then put true into lPageSetup @@ -176,6 +179,7 @@ on revPrintText pText,pHeader,pFooter,pSourceFieldRef,pHeaderFldRef,pFooterFldRe close printing if there is a stack "revTempHeader" then delete stack "revTempHeader" if there is a stack "revTempFooter" then delete stack "revTempFooter" + set the defaultStack to tDefaultStack delete stack gREVPrintFileName reset the templateStack reset the templateField diff --git a/Toolset/libraries/revprofileslibrary.livecodescript b/Toolset/libraries/revprofileslibrary.livecodescript index 9a9224595b..ac2838f19d 100644 --- a/Toolset/libraries/revprofileslibrary.livecodescript +++ b/Toolset/libraries/revprofileslibrary.livecodescript @@ -1,16 +1,16 @@ script "revprofileslibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize # OK-2008-04-14 : Added variable declarations when investigating a bug diff --git a/Toolset/libraries/revreshapelibrary.livecodescript b/Toolset/libraries/revreshapelibrary.livecodescript index f75ac405ab..a4f960bc8b 100644 --- a/Toolset/libraries/revreshapelibrary.livecodescript +++ b/Toolset/libraries/revreshapelibrary.livecodescript @@ -1,17 +1,17 @@ script "revreshapelibrary" -on revLoadLibrary +on extensionInitialize // SN-2015-05-13: [[ Bug 15365 ]] Make sure that we don't catch - // revLoadLibrary message if we are not the target + // extensionInitialize message if we are not the target if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize remove the script of me from front -end revUnloadLibrary +end extensionFinalize on revNewTool if the long id of me is among the lines of the frontScripts then diff --git a/Toolset/libraries/revrulersscriptlibrary.livecodescript b/Toolset/libraries/revrulersscriptlibrary.livecodescript index b2c909aaae..a670d8cec9 100644 --- a/Toolset/libraries/revrulersscriptlibrary.livecodescript +++ b/Toolset/libraries/revrulersscriptlibrary.livecodescript @@ -1,17 +1,17 @@ script "revrulersscriptlibrary" -on revLoadLibrary +on extensionInitialize // SN-2015-05-13: [[ Bug 15365 ]] Make sure that we don't catch - // revLoadLibrary message if we are not the target + // extensionInitialize message if we are not the target if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize remove script of me from front -end revUnloadLibrary +end extensionFinalize local lPaused @@ -92,12 +92,9 @@ on resumeStack pass resumeStack else put false into lPaused - if not the visible of stack "revRulersH" then + if not the visible of stack "revRulersH" and "revRulersH" is among the lines of the openstacks then show stack "revRulersH" show stack "revRulersV" - else - palette "revRulersV" - palette "revRulersH" end if revPartCalculateRulers unlock messages diff --git a/Toolset/libraries/revshortcutslibrary.livecodescript b/Toolset/libraries/revshortcutslibrary.livecodescript index a7bd26af23..7c13e6d539 100644 --- a/Toolset/libraries/revshortcutslibrary.livecodescript +++ b/Toolset/libraries/revshortcutslibrary.livecodescript @@ -1,17 +1,17 @@ script "revshortcutslibrary" -on revLoadLibrary +on extensionInitialize // SN-2015-05-13: [[ Bug 15365 ]] Make sure that we don't catch - // revLoadLibrary message if we are not the target + // extensionInitialize message if we are not the target if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize remove the script of me from front -end revUnloadLibrary +end extensionFinalize on revNewTool # AL-2015-03-26: [[ Bug 15045 ]] Deal with the newTool message correctly @@ -79,22 +79,8 @@ on arrowKey pDirection, pTarget put 1 into tDistance end if - repeat for each line tObject in (the selObj) - switch pDirection - case "left" - set the left of tObject to the left of tObject - tDistance - break - case "right" - set the left of tObject to the left of tObject + tDistance - break - case "up" - set the top of tObject to the top of tObject - tDistance - break - case "down" - set the top of tObject to the top of tObject + tDistance - break - end switch - end repeat + revIDENudgeControls the selobj, pDirection, tDistance + revSendDimensionsUpdate unlock screen exit to top @@ -259,6 +245,7 @@ on tabKey else revIDESetTool "pointer" end if + unlock cursor exit tabKey end if diff --git a/Toolset/libraries/revtablelibrary.livecodescript b/Toolset/libraries/revtablelibrary.livecodescript index f016164bd5..3dbaf81b27 100644 --- a/Toolset/libraries/revtablelibrary.livecodescript +++ b/Toolset/libraries/revtablelibrary.livecodescript @@ -1,18 +1,18 @@ script "revtablelibrary" -on revLoadLibrary +on extensionInitialize if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is not me then - pass "revUnloadLibrary" + pass "extensionFinalize" end if remove the script of me from front -end revUnloadLibrary +end extensionFinalize -- Table library diff --git a/Toolset/libraries/revwidgettrackerlibrary.livecodescript b/Toolset/libraries/revwidgettrackerlibrary.livecodescript index ad0e3596d9..e6c8531e3f 100644 --- a/Toolset/libraries/revwidgettrackerlibrary.livecodescript +++ b/Toolset/libraries/revwidgettrackerlibrary.livecodescript @@ -1,17 +1,17 @@ script "revwidgettrackerlibrary" -on revLoadLibrary +on extensionInitialize // SN-2015-05-13: [[ Bug 15365 ]] Make sure that we don't catch - // revLoadLibrary message if we are not the target + // extensionInitialize message if we are not the target if the target is not me then - pass "revLoadLibrary" + pass "extensionInitialize" end if insert the script of me into front -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize remove the script of me from front -end revUnloadLibrary +end extensionFinalize local lTrackingIcon, lTracking, lCancelID global gREVCurrentWidget diff --git a/Toolset/libraries/revxmlrpclibrary.livecodescript b/Toolset/libraries/revxmlrpclibrary.livecodescript index 5e29f56fd8..f6dfdb81ff 100644 --- a/Toolset/libraries/revxmlrpclibrary.livecodescript +++ b/Toolset/libraries/revxmlrpclibrary.livecodescript @@ -1,16 +1,16 @@ script "revxmlrpclibrary" -on revLoadLibrary +on extensionInitialize if the target is me then insert the script of me into back end if -end revLoadLibrary +end extensionInitialize -on revUnloadLibrary +on extensionFinalize if the target is me then remove the script of me from back end if -end revUnloadLibrary +end extensionFinalize ----- LiveCode XML-RPC library ------ diff --git a/Toolset/palettes/behaviors/revaboutcardbehavior.livecodescript b/Toolset/palettes/behaviors/revaboutcardbehavior.livecodescript new file mode 100644 index 0000000000..43de718836 --- /dev/null +++ b/Toolset/palettes/behaviors/revaboutcardbehavior.livecodescript @@ -0,0 +1,76 @@ +script "revAboutCardBehavior" +on preOpenStack + local tEdition, tPath + + lock screen + + put revEnvironmentEditionProperty("name") && "Edition" into field "Edition" + + put the version && "| Build" && the buildNumber into field "version" + set the blendLevel of field "version" to 40 + + set the htmlText of field "Copyright" of me to "<p>© 2000-" & word -1 of the long date && "LiveCode Ltd.</p>" + revFontApplySystemStyle the long id of field "Copyright" of me, empty, empty + + set the textColor of char 1 to -1 of field "displayData" of me to empty + set the textColor of char 1 to 5 of field "displayData" of me to aboutHiliteColor() + loadText "about" + + set the title of this stack to "About LiveCode" && line 4 of the revLicenseInfo + + if char 1 of the version < 7 then + put ideCoreFolderPath("skin", "about-background_legacy.png") into tPath + set the textColor of field "version" of me to "white" + set the textColor of field "edition" of me to "white" + else + put ideCoreFolderPath("skin", "about-background.png") into tPath + set the textColor of field "version" of me to empty + set the textColor of field "edition" of me to empty + end if + + setBackgroundImage tPath + set the windowShape of this stack to 102250 + set the loc of this stack to the screenLoc + unlock screen +end preOpenStack + +on preOpenCard + if the editionType is "commercial" and revLicenseInfo["com.livecode.norevenuelimit"] is empty then + set the visible of field "License" to true + else + set the visible of field "License" to false + end if +end preOpenCard + +on openCard + send "revStartScroll" to field "Credits" +end openCard + +on mouseUp + close this stack +end mouseUp + +on setBackgroundImage pImagePath + set the filename of image id 102250 to pImagePath + set the topLeft of image id 102250 to 0,0 + set the rect of this stack to the rect of image id 102250 + set the windowShape of this stack to 102250 +end setBackgroundImage + +on loadText pType + local tFilePath + set the itemDel to "/" + switch pType + case "about" + put item 1 to -3 of the filename of stack "home" & "/about.txt" into tFilePath + break + case "legal" + put item 1 to -3 of the filename of stack "home" & "/Open Source Licenses.txt" into tFilePath + break + end switch + put textDecode(url ("binfile:" & tFilePath), "utf-8") into field "credits" of me +end loadText + +function aboutHiliteColor + return revEnvironmentEditionProperty("revabout_hilite_color") +end aboutHiliteColor diff --git a/Toolset/palettes/behaviors/revcorestackbehavior.livecodescript b/Toolset/palettes/behaviors/revcorestackbehavior.livecodescript new file mode 100644 index 0000000000..979c0ef592 --- /dev/null +++ b/Toolset/palettes/behaviors/revcorestackbehavior.livecodescript @@ -0,0 +1,815 @@ +script "revCoreStackBehavior" +################################################################ +# Reading object properties used to the project browser and application browser +# There are two variations. Each wants slightly different properties so for +# optimisations sake we've implemented two functions +################################################################ +function idePropertyInspectorReadProperties pList + local tProps, tPropGetScript + // Get the core properties + repeat for each line tProp in pList + if tProp is "allcustomproperties" then + local tCustomPropertySets, tCustomProperties + set the custompropertyset of the target to empty + put the customproperties of the target into tCustomProperties["default"] + + put the custompropertysets of the target into tCustomPropertySets + + repeat for each line tCustomPropertySet in tCustomPropertySets + put the customproperties[tCustomPropertySet] of the target into tCustomProperties[tCustomPropertySet] + end repeat + put tCustomProperties into tProps["allcustomproperties"] + else if tProp contains "dgProp" then + // This is a dataGrid property + put "get the" && tProp && "of" && the target into tPropGetScript + try + do tPropGetScript + put the result into tProps[tProp] + end try + else + try + put the tProp of the target into tProps[tProp] + end try + end if + end repeat + + put the short name of the target into tProps["name"] + + return tProps +end idePropertyInspectorReadProperties + +function ideProjectBrowserReadProperties pList + local tProps, tScriptLines, tLabel, tTarget + // Get the core properties + local tLongID, tShortName, tCard + + put the long id of the target into tLongID + put the short name of the target into tShortName + put ideCoreCardOfControl(tLongID) into tCard + + repeat for each line tProp in pList + if tProp is "type" then + put word 1 of the name of the Target into tProps["type"] + else if tProp is "script_lines" then + try + put the num of lines in the script of the Target into tScriptLines + catch tError + put "pwd" into tScriptLines + end try + put tScriptLines into tProps["script_lines"] + else if tProp is "label" then + if word 1 of the name of the Target is "button" then + put the label of the Target into tLabel + replace return with space in tLabel + else + put empty into tLabel + end if + put tLabel into tProps["label"] + else if tProp is "custom Control" then + if the the cIDEProperties["cCustomControl"] of the Target is "true" then + put "true" into tProps["custom Control"] + else if the dgProp["control type"] of the target is "Data Grid" then + put "true" into tProps["custom Control"] + else + put "false" into tProps["custom Control"] + end if + else if tProp is "behavior_control" then + if the behavior of the Target is not empty then + put the behavior of the Target into tProps["behavior_control"] + else + put empty into tProps["behavior_control"] + end if + else if tProp is "behavior_script_lines" then + if the behavior of the Target is not empty then + if exists(the behavior of the Target) then + try + put the num of lines in the script of the behavior of the Target into tProps["behavior_script_lines"] + catch pError + put "pwd" into tProps["behavior_script_lines"] + end try + else + put "object missing" into tProps["behavior_script_lines"] + end if + end if + else if tProp is "long id" then + put the long id of the target into tProps["long id"] + else if tProp is "owner" then + put the long id of the owner of the target into tProps["owner"] + else + try + put the tProp of the Target into tProps[tProp] + end try + end if + end repeat + + put the short name of the Target into tProps["name"] + return tProps +end ideProjectBrowserReadProperties + +function ideProjectBrowserReadStackProperties pList + local tProps + // Get the core properties + repeat for each line tProp in pList + if tProp is "type" then + if the mainStack of the target is the short name of the target then + put "mainstack" into tProps["type"] + else + put "substack" into tProps["type"] + end if + else if tProp is "script_lines" then + try + put the num of lines in the script of the target into tProps["script_lines"] + catch tError + put "pwd" into tProps["script_lines"] + end try + else if tProp is "behavior_script_lines" then + if the behavior of the target is not empty then + if there is a (the behavior of the target) then + try + put the num of lines in the script of the behavior of the target into tProps["behavior_script_lines"] + catch tError + put "pwd" into tProps["behavior_script_lines"] + end try + end if + end if + else if tProp is "behavior_control" then + if the behavior of the target is not empty then + if there is a (the behavior of the target) then + try + put the behavior of the target into tProps["behavior_control"] + catch tError + put "pwd" into tProps["behavior_control"] + end try + end if + end if + else + try + put the tProp of the Target into tProps[tProp] + end try + end if + end repeat + return tProps +end ideProjectBrowserReadStackProperties + +function ideProjectBrowserReadCardProperties pList + local tProps + // Get the core properties + repeat for each line tProp in pList + if tProp is "name" then + put the short name of the target into tProps["name"] + else if tProp is "number" then + put the number of the target into tProps["number"] + else if tProp is "script_lines" then + try + put the num of lines in the script of the target into tProps["script_lines"] + catch tError + put "pwd" into tProps["script_lines"] + end try + else if tProp is "behavior_script_lines" then + if the behavior of the target is not empty then + if there is a (the behavior of the target) then + try + put the num of lines in the script of the behavior of the target into tProps["behavior_script_lines"] + catch tError + put "pwd" into tProps["behavior_script_lines"] + end try + end if + end if + else if tProp is "behavior control" then + if the behavior of the target is not empty then + if there is a (the behavior of the target) then + try + put the behavior of the target into tProps["behavior_control"] + catch tError + put "pwd" into tProps["behavior_control"] + end try + end if + end if + else + try + put the tProp of the Target into tProps[tProp] + end try + end if + end repeat + return tProps +end ideProjectBrowserReadCardProperties + +################################################################ +# DEBUGGING AND PERFORMANCE LOGGING +################################################################ +global gRevDevelopment +local sLog +on ideTimingLogStart pSource + if gRevDevelopment is true then + if pSource is empty then + put ideTimingLogSourceStackNameGet() into pSource + end if + + put the milliseconds into sLog[pSource]["start"] + put empty into sLog[pSource]["log"] + put empty into sLog[pSource]["lasttime"] + put empty into sLog[pSource]["logtime"] + end if +end ideTimingLogStart + +on ideTimingLogClearAll + put empty into sLog +end ideTimingLogClearAll + +on ideTimingLog pMessage, pSource + if gRevDevelopment is true then + if pSource is empty then + put ideTimingLogSourceStackNameGet() into pSource + end if + + if sLog[pSource]["start"] is empty then ideTimingLogStart pSource + + put the milliseconds into sLog[pSource]["logtime"] + + local tTime + put sLog[pSource]["logtime"] - sLog[pSource]["start"] into tTime + put tTime && " ("&tTime-sLog[pSource]["lasttime"]&") |" && pMessage & return after sLog[pSource]["log"] + put tTime into sLog[pSource]["lasttime"] + end if +end ideTimingLog + +local sLastDisplayTime +on ideTimingLogDisplay + if gRevDevelopment is true then + local tDisplay + repeat for each key tKey in sLog + put "#############" && tKey && "##############" & return after tDisplay + put "Log shown at -" & the milliseconds && "milliseconds" & return after tDisplay + put "TOTAL TIME - " && sLog[tKey]["logtime"] - sLog[tKey]["start"] & return after tDisplay + put sLog[tKey]["log"] & return after tDisplay + end repeat + + put tDisplay into msg + end if +end ideTimingLogDisplay + +function ideTimingLogSourceStackNameGet + if gRevDevelopment is true then + local tLongName, tExecutionContexts + + put the long name of me into tLongName + put the executioncontexts into tExecutionContexts + + local tExecutionLine + repeat with x = the number of lines of tExecutionContexts down to 1 + put line x of tExecutionContexts into tExecutionLine + put item 1 of tExecutionLine into tExecutionLine + if tExecutionLine is not tLongName then + delete the last char of tExecutionLine + set the itemdel to "/" + put the last item of tExecutionLine into tExecutionLine + set the itemdel to "," + exit repeat + end if + end repeat + + return tExecutionLine + end if +end ideTimingLogSourceStackNameGet + +################################################################ +# GENERAL IDE COMMANDS AND FUNCTIONS +################################################################ + +// Returns the long ID of the card for a given long ID of an object +function ideCoreCardOfcontrol pLongID + local tCardWord + put wordOffset("card",pLongID) into tCardWord + return word tCardWord to -1 of pLongID +end ideCoreCardOfcontrol + +function ideCoreParentOfControl pLongID + local tCardWord + put wordOffset("card",pLongID) into tCardWord + return word tCardWord to -1 of pLongID +end ideCoreParentOfControl + +function ideCoreStackIsIDE pLongID + return revIDEStackNameIsIDEStack(the filename of pLongID) +end ideCoreStackIsIDE + +################################################################ +# CONTROL ALIGNMENT COMMANDS AND FUNCTIONS +################################################################ +command ideCoreAlignObjects pPosition, pObjectList + local tPositionValue, tInitialObject, tSetLine, tCurrentLoc + + if pObjectList is empty then put the selectedObjects into pObjectList + + put line 1 of pObjectList into tInitialObject + + lock screen + repeat with x = 1 to the number of lines in pObjectList + get line x of pObjectList + switch pPosition + case "alignLeft" + put value("the left of me",tInitialObject) into tPositionValue + set the left of it to tPositionValue + break + case "alignTop" + put value("the top of me",tInitialObject) into tPositionValue + set the top of it to tPositionValue + break + case "alignRight" + put value("the right of me",tInitialObject) into tPositionValue + set the right of it to tPositionValue + break + case "alignBottom" + put value("the bottom of me",tInitialObject) into tPositionValue + set the bottom of it to tPositionValue + break + case "alignHorizontalCenter" + put value("the loc of me",tInitialObject) into tPositionValue + delete item 2 of tPositionValue + put the loc of it into tCurrentLoc + set the loc of it to tPositionValue,item 2 of tCurrentLoc + break + case "alignVerticalCenter" + put value("the loc of me",tInitialObject) into tPositionValue + delete item 1 of tPositionValue + put the loc of it into tCurrentLoc + set the loc of it to item 1 of tCurrentLoc,tPositionValue + break + end switch + --put "set the" && pPosition && "of" && line x of pObjectList && "to" && tPositionValue into tSetLine + --do tSetLine + end repeat + unlock screen +end ideCoreAlignObjects + +command ideCoreEqualizeObjects pPosition, pObjectList + local tPositionValue, tInitialObject, tSetLine, tCurrentLoc + + if pObjectList is empty then put the selectedObjects into pObjectList + put line 1 of pObjectList into tInitialObject + + lock screen + repeat with x = 1 to the number of lines in pObjectList + get line x of pObjectList + switch pPosition + case "equalizeWidth" + put value("the width of me",tInitialObject) into tPositionValue + set the width of it to tPositionValue + break + case "equalizeHeight" + put value("the height of me",tInitialObject) into tPositionValue + set the height of it to tPositionValue + break + case "equalizeWidthHeight" + put value("the width of me",tInitialObject) into tPositionValue + set the width of it to tPositionValue + put value("the height of me",tInitialObject) into tPositionValue + set the height of it to tPositionValue + break + end switch + end repeat + unlock screen +end ideCoreEqualizeObjects + +command ideCoreDistributeObjects pDirection, pDistribution, pObjectList + local tStack, tLeft, tRight, tTop,tBottom, tTotalWidth, tTotalHeight, tSpacing + local tAvailableWidth, tAvailableHeight + local tOrderedObjectList + + if pObjectList is empty then put the selectedObjects into pObjectList + + put word -2 to -1 of line 1 of pObjectList into tStack + put the width of tStack into tLeft + put the height of tStack into tTop + put 0 into tRight + put 0 into tBottom + repeat with x = 1 to the number of lines in pObjectList + get line x of pObjectList + if the left of it < tLeft then put the left of it into tLeft + if the top of it < tTop then put the top of it into tTop + if the right of it > tRight then put the right of it into tRight + if the bottom of it > tBottom then put the bottom of it into tBottom + add the width of it to tTotalWidth + add the height of it to tTotalHeight + + put it & comma & the left of it & comma & the top of it & return after tOrderedObjectList + end repeat + + if pDirection is "distributeHorizontal" then + switch pDistribution + case "First To Last selected" + sort lines of tOrderedObjectList by item 2 of each + put tRight-tLeft into tAvailableWidth + put ((tAvailableWidth-tTotalWidth)/number of lines in pObjectList) div 1 into tSpacing + break + case "Edge To Edge" + sort lines of tOrderedObjectList by item 2 of each + put 0 into tSpacing + break + case "Across Card" + sort lines of tOrderedObjectList by item 2 of each + put the width of tStack into tAvailableWidth + put ((tAvailableWidth-tTotalWidth)/(the number of lines in pObjectList+1)) div 1 into tSpacing + put tSpacing into tLeft + break + end switch + repeat with x = 1 to the number of lines in tOrderedObjectList + get item 1 of line x of pObjectList + set the left of it to tLeft + add the width of it + tSpacing to tLeft + end repeat + else if pDirection is "distributeVertical" then + switch pDistribution + case "First To Last selected" + sort lines of tOrderedObjectList by item 3 of each + put tBottom-tTop into tAvailableHeight + put ((tAvailableHeight-tTotalHeight)/number of lines in pObjectList) div 1 into tSpacing + break + case "Edge To Edge" + sort lines of tOrderedObjectList by item 3 of each + put 0 into tSpacing + break + case "Across Card" + sort lines of tOrderedObjectList by item 3 of each + put the height of tStack into tAvailableHeight + put ((tAvailableHeight-tTotalHeight)/(the number of lines in pObjectList+1)) div 1 into tSpacing + put tSpacing into tTop + break + end switch + repeat with x = 1 to the number of lines in tOrderedObjectList + get item 1 of line x of pObjectList + set the top of it to tTop + add the height of it + tSpacing to tTop + end repeat + end if +end ideCoreDistributeObjects + +// Button display +command ideCoreSetHover pControl, pValue, pType + if not the disabled of pControl then + if pValue then + if pType is "foreground" then + set the colorOverlay["color"] of pControl to ideColorGet("state_hover") + else + set the opaque of pControl to true + set the backgroundColor of pControl to ideColorGet("state_hover") + end if + else + if pType is "foreground" then + set the colorOverlay of pControl to empty + else + set the opaque of pControl to false + set the backgroundColor of pControl to empty + end if + end if + end if +end ideCoreSetHover + +command ideCoreSetDisabled pControl, pValue + set the disabled of pControl to pValue + if pValue then + set the colorOverlay["opacity"] of pControl to 200 + set the colorOverlay["color"] of pControl to ideColorGet("state_disabled") + else + set the colorOverlay of pControl to empty + end if +end ideCoreSetDisabled + +function ideCoreButtonDefaultStateDataGet + return "normal,foreground" & return & "hover,background" & return & "pressed,background" & return & "disabled,foreground" & return & "selected,background" +end ideCoreButtonDefaultStateDataGet + +function ideCoreButtonForegroundStateDataGet + return "normal,foreground" & return & "hover,foreground" & return & "pressed,foreground" & return & "disabled,foreground" & return & "selected,foreground" & return & "booleanTrue,foreground" & return & "booleanFalse,foreground" +end ideCoreButtonForegroundStateDataGet + +// Comparison functions +function ideCoreCompareValues pValue1, pValue2 + local tValue1Array, tValue2Array + + if the keys of pValue1 is empty then + put false into tValue1Array + else + put true into tValue1Array + end if + + if the keys of pValue2 is empty then + put false into tValue2Array + else + put true into tValue2Array + end if + + if not tValue1Array and not tValue2Array then + if pValue1 is pValue2 then + return true + else + return false + end if + else if tValue1Array and tValue2Array then + // Compare the 2 arrays + return ideCoreCompareArrays(pValue1, pValue2) + else + // 1 array, 1 non array + return false + end if +end ideCoreCompareValues + +function ideCoreCompareArrays pArray1, pArray2 + if the keys of pArray1 is not the keys of pArray2 then + return false + else + repeat for each key tKey in pArray1 + if pArray1[tKey] is not pArray2[tKey] then + return false + end if + end repeat + return true + end if +end ideCoreCompareArrays + +// Preferences +on ideTextSizeSet pSize + if pSize is empty then + set the cIDETextSize of stack "revPreferences" to empty + else + set the cIDETextSize of stack "revPreferences" to pSize + end if + ideCoreUpdateTextFontSize +end ideTextSizeSet + +function ideTextSizeGet + local tTextSize + + put the cIDETextSize of stack "revPreferences" into tTextSize + if tTextSize is empty then + return empty + else + return the cIDETextSize of stack "revPreferences" + end if +end ideTextSizeGet + +on ideProjectBrowserThumbnailsHeightSet pSize + if pSize is empty then + set the cIDEThumbnailHeight of stack "revPreferences" to 50 + else + set the cIDEThumbnailHeight of stack "revPreferences" to pSize + end if + send "ideRefresh" to stack "revIDEProjectBrowser" +end ideProjectBrowserThumbnailsHeightSet + +function ideProjectBrowserThumbnailsHeightGet + local tSize + + put the cIDEThumbnailHeight of stack "revPreferences" into tSize + if tSize is empty then + return 50 + else + return tSize + end if +end ideProjectBrowserThumbnailsHeightGet + +on ideProjectBrowserThumbnailsWidthSet pSize + if pSize is empty then + set the cIDEThumbnailWidth of stack "revPreferences" to 50 + else + set the cIDEThumbnailWidth of stack "revPreferences" to pSize + end if + send "ideRefresh" to stack "revIDEProjectBrowser" +end ideProjectBrowserThumbnailsWidthSet + +function ideProjectBrowserThumbnailsWidthGet + local tSize + + put the cIDEThumbnailWidth of stack "revPreferences" into tSize + if tSize is empty then + return 50 + else + return tSize + end if +end ideProjectBrowserThumbnailsWidthGet + +on ideTextFontSet pFont + if pFont is empty then + set the cIDETextFont of stack "revPreferences" to empty + else + set the cIDETextFont of stack "revPreferences" to pFont + end if + ideCoreUpdateTextFontSize +end ideTextFontSet pFont + +function ideTextFontGet + local tTextFont + + put the cIDETextFont of stack "revPreferences" into tTextFont + if tTextFont is empty then + return empty + else + return the cIDETextFont of stack "revPreferences" + end if +end ideTextFontGet + +function ideTextFontOptions + local tFonts + put the fontNames into tFonts + sort lines of tFonts + put "empty" & return before tFonts + return tFonts +end ideTextFontOptions + +on ideCoreUpdateTextFontSize + // Temp + lock messages + lock screen + + set the textFont of stack "revIDEProjectBrowser" to ideTextFontGet() + set the textSize of stack "revIDEProjectBrowser" to ideTextSizeGet() + + unlock messages + unlock screen +end ideCoreUpdateTextFontSize + +function ideCoreTrim pText + local tTrimmedText + repeat with x = 1 to the number of characters of pText + if char x of pText is not space and char x of pText is not ":" then + put char x of pText after tTrimmedText + end if + end repeat + return tTrimmedText +end ideCoreTrim + +function ideColorGet pTag + switch pTag + case "state_disabled" + return "208,208,208" + break + case "palette_background" + case "toolbar_background" + return "236,236,236" + break + case "palette_background_muted" + case "state_normal_foreground" + case "state_hover_foreground" + case "state_pressed_foreground" + case "state_selected_foreground" + case "state_disabled_foreground" + case "state_booleanTrue_foreground" + case "state_booleanFalse_foreground" + case "border_muted_hilite" + case "pb_line_border_left_hilite" + case "pb_script_lines_text" + case "pb_script_lines_text_hover" + case "pb_behavior_script_lines_text" + case "pb_behavior_script_lines_text_hover" + case "pb_edit_field_bg" + case "border_hilite" + case "pb_line_background" + return "255,255,255" + break + case "state_normal" + case "pb_disclosure_arrow" + return "129,129,129" + break + case "state_hover" + case "hilite_above" + case "pb_script_lines_hover" + case "pb_behavior_script_lines_hover" + case "pb_drag_hilite_top" + return "0,72,204" + break + case "state_pressed" + case "hilite_below" + case "pb_drag_hilite_bottom" + return "192,0,204" + break + case "state_selected" + case "pb_script_lines" + case "pb_behavior_script_lines" + return "0,195,255" + break + case "pb_no_script_lines" + return "157,233,255" + break + case "state_booleanTrue" + return "100,100,100" + break + case "state_booleanFalse" + return "182,182,182" + break + case "state_muted_pressed" + return "231,22,255" + break + case "state_muted_selected" + case "pb_line_selected" + return revEnvironmentEditionProperty("pb_line_selected_color") + break + case "state_muted_disabled" + case "hilite_center" + case "pb_drag_hilite_center" + case "pb_line_selected_hover" + return "255,211,211" + break + case "state_muted_selected_secondary" + case "pb_line_selected_trail" + return "244,244,244" + break + case "border" + case "pb_list_bottom_border" + case "pb_edit_field_border" + case "pb_line_border_left" + return "225,225,225" + break + case "border_muted" + case "pb_line_border_bottom" + return "234,234,234" + break + case "text" + return "0,0,0" + break + case "text_muted" + return "95,95,95" + break + case "pb_palette_background" + case "pb_line_show_select_background" + return "236,236,236" + break + end switch +end ideColorGet + +## array printer +on revPutArray pArray + + if (the keys of pArray) is empty then + put "not an array" + exit revPutArray + end if + + local pLevel, pCounter, pList + + put 0 into pLevel + put 0 into pCounter + put empty into pList + + put dumpArrayRecurse(pArray, pLevel, pCounter, pList) into pList + + put pList +end revPutArray + +private function dumpArrayRecurse pArray, pLevel, @pCounter, @pList + local tOrderedKeys + put the keys of pArray into tOrderedKeys + sort lines of tOrderedKeys numeric + repeat for each line tKey in tOrderedKeys + + add 1 to pCounter + + repeat for pLevel + put tab after line pCounter of pList + end repeat + put (tKey && "= ") after line pCounter of pList + + if (the keys of pArray[tKey]) is empty then + put line 1 of pArray[tKey] after line pCounter of pList + else + put dumpArrayRecurse(pArray[tKey], (pLevel + 1), pCounter, pList) into pList + end if + + end repeat + + return pList + +end dumpArrayRecurse + + +function ideCoreFolderPath pFolder, pFileName + local tPath + put revEnvironmentEditionProperty("folder") & "/" & pFolder & "/" & pFileName into tPath + if there is a file tPath or there is a folder tPath then + return tPath + end if + + put revEnvironmentToolsetPath() & "/resources/" & pFolder & "/" & pFileName into tPath + if there is a file tPath or there is a folder tPath then + return tPath + end if +end ideCoreFolderPath + +function ideCoreEditionHoverColour + return "147,179,39" +end ideCoreEditionHoverColour + +on ideCoreShowTip pStack,pCard,pName,pRect,pMessage, pLink + //Copy the template group + if there is a group pName of card pCard of stack pStack then + delete group pName of card pCard of stack pStack + end if + copy group "tip_display_template" of card 1 of stack "revCore" to card pCard of stack pStack + + set the name of it to pName + set the lockLoc of it to true + set the rect of it to pRect + set the behavior of it to the long id of button "tip_display_behavior" of card 1 of stack "revCore" + put pMessage into field "tip_message" of it + set the cLink of it to pLink + send "layoutTip" to it +end ideCoreShowTip diff --git a/Toolset/palettes/behaviors/revinspectorbehavior.livecodescript b/Toolset/palettes/behaviors/revinspectorbehavior.livecodescript index 0176783f12..aa0388aa6c 100644 --- a/Toolset/palettes/behaviors/revinspectorbehavior.livecodescript +++ b/Toolset/palettes/behaviors/revinspectorbehavior.livecodescript @@ -4,6 +4,9 @@ constant kMaxLabelSize = 200 # The inspector data local sDataA +# used by manualHeight +local sStackIsInFront + on setAsBehavior pTarget dispatch "setAsBehavior" to revIDEFrameBehavior() with the long id of this me set the behavior of pTarget to the long id of this me @@ -36,6 +39,7 @@ before openStack end repeat set the stackfiles of me to tStackFiles revIDEPopDefaultFolder + put true into sStackIsInFront end openStack on resizeInspector @@ -52,20 +56,33 @@ on inspectorOpenEditor pEditor # Find the file for the editor local tEditorStackPath, tEditorBehaviorPath - put revIDEPaletteResourcePath("editors/" & pEditor & ".livecode") into tEditorStackPath - put revIDEPaletteResourcePath("editors/" & pEditor & ".behavior.livecodescript") into tEditorBehaviorPath + put revIDEPaletteResourcePath("editors/" & pEditor & ".livecode", \ + the long id of stack "revInspector") into tEditorStackPath + put revIDEPaletteResourcePath("editors/" & pEditor & ".behavior.livecodescript", \ + the long id of stack "revInspector") into tEditorBehaviorPath + # open editor stack if it exists - if there is a file tEditorStackPath then - go invisible stack tEditorStackPath + if there is not a file tEditorStackPath then + # check if an extension has provided its own editor + # it is named <id>.editor.editorName + local tId, tPath + set the itemdelimiter to "." + put item 1 to -3 of pEditor into tId + put revIDEExtensionProperty(tId, "install_path") into tPath + put tPath & "/editors/" & pEditor & ".livecode" into tEditorStackPath + put tPath & "/editors/" & pEditor & ".behavior.livecodescript" into tEditorBehaviorPath end if + if there is a file tEditorStackPath then + get the long id of stack tEditorStackPath + end if if there is a file tEditorBehaviorPath then - go invisible stack tEditorBehaviorPath + get the long id of stack tEditorBehaviorPath end if end inspectorOpenEditor # Layout inspector -on inspectorLayout +on inspectorLayout pForceHeight //put "layout inspector" & return after msg lock screen @@ -73,11 +90,110 @@ on inspectorLayout local tSelectedGroup put inspectorSectionGet() into tSelectedGroup - inspectorLayoutGroups sDataA[tSelectedGroup]["grouplist"] + inspectorLayoutGroups sDataA[tSelectedGroup]["grouplist"], pForceHeight + unlock screen end inspectorLayout -on inspectorLayoutGroups pGroupList +private function inspectorCalculateLayout pGroupList, pLeft, pTop, pRowWidth, pSubsections, pCurSection, pExpandableExtra, @rCanExpand + local tLeft, tTop + put pLeft into tLeft + put pTop into tTop + + local tMaxRowWidth, tInspectorHeight, tColumnNumber, tColumnTop, + local tCanExpand, tRowGroup, tThisCanExpand + put 1 into tColumnNumber + put 0 into tCanExpand + repeat for each element tElement in pGroupList + if pSubsections and tElement["subsection"] is not empty then + # If we have a new subsection, create the subsection header + if tElement["subsection"] is not pCurSection then + lock messages + set the width of group ("Subsection_" & tElement["subsection"]) of me to the formattedwidth of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me + set the width of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me to the formattedwidth of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me + set the topleft of group ("Subsection_" & tElement["subsection"]) of me to tLeft,tTop + unlock messages + add (the formattedheight of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me) to tTop + put tElement["subsection"] into pCurSection + end if + end if + + if there is not a group tElement["label"] of group "inspector" of me then next repeat + put the long id of group tElement["label"] of group "inspector" of me into tRowGroup + + # set the width and topleft of the editor + lock messages + set the topleft of tRowGroup to tLeft,tTop + set the lockloc of tRowGroup to true + set the width of tRowGroup to pRowWidth + unlock messages + + # Tell the row to resize + dispatch "rowResize" to tRowGroup + + local tEditorHeight + # If the editor does not report its own height, use the formatted height + # This tends to report slightly strange values, otherwise we could just use it + # all the time. + put the editorHeight of tRowGroup into tEditorHeight + if not tEditorHeight > 0 then + put the formattedheight of tRowGroup into tEditorHeight + end if + + dispatch function "canExpandVertically" to tRowGroup + put the result into tThisCanExpand + if tThisCanExpand then + add 1 to tCanExpand + if pExpandableExtra > 0 then + lock messages + set the height of tRowGroup to tEditorHeight + pExpandableExtra + unlock messages + dispatch "rowResize" to tRowGroup + end if + end if + + # Get the margin, padding + local tPadding, tMargin + put the palettePadding of me into tPadding + put the paletteMargin of me into tMargin + lock messages + add tEditorHeight + tPadding to tTop + + if pRowWidth > tMaxRowWidth then + put pRowWidth into tMaxRowWidth + end if + if tTop > tInspectorHeight then + put tTop into tInspectorHeight + end if + unlock messages + end repeat + + local tHeightDiff + put the height of me - 2* tMargin - tInspectorHeight into tHeightDiff + if pExpandableExtra is 0 and tCanExpand > 0 and tHeightDiff > 0 then + local tExpandableExtra, tDummy + put tHeightDiff / tCanExpand into tExpandableExtra + get inspectorCalculateLayout(pGroupList, pLeft, pTop, pRowWidth, pSubsections, pCurSection, tExpandableExtra, tDummy) + end if + + put tCanExpand > 0 into rCanExpand + return tInspectorHeight +end inspectorCalculateLayout + +local sManualHeightOfStack, sNewHeight, sOldHeight +on inspectorLayoutGroups pGroupList, pForceHeight + + # store height of stack when manually resizing + if pForceHeight is not true and the mouse is "down" \ + and sNewHeight is not sOldHeight and the mouseStack is empty and sStackIsInFront then + put the height of this stack into sManualHeightOfStack + end if + + # reset sManualHeightOfStack to empty if inspector was closed + if not the visible of me then + put empty into sManualHeightOfStack + end if + lock screen # Get the margin, padding local tMargin, tPadding @@ -88,16 +204,19 @@ on inspectorLayoutGroups pGroupList local tTop, tLeft, tContentRect put the contentRect of me into tContentRect put item 1 of tContentRect + tMargin into tLeft + put tLeft into item 1 of tContentRect put item 2 of tContentRect + tMargin into tTop + put tTop into item 2 of tContentRect # Loop through the editors and get the minimum width of the labels and editors # To work out an initial row width - local tMinRowWidth, tMinEditorsWidth, tRowWidth, tMinLabelWidth + local tMinRowWidth, tMinEditorsWidth, tRowWidth, tMinLabelWidth, tRowGroup repeat for each element tElement in pGroupList - if there is not a group tElement["label"] of me then next repeat + if there is not a group tElement["label"] of group "inspector" of me then next repeat + put the long id of group tElement["label"] of group "inspector" of me into tRowGroup local tEditorsReportedWidth, tLabelReportedWidth - put the rowMinWidth of group tElement["label"] of me into tEditorsReportedWidth - put the rowLabelWidth of group tElement["label"] of me into tLabelReportedWidth + put the rowMinWidth of tRowGroup into tEditorsReportedWidth + put the rowLabelWidth of tRowGroup into tLabelReportedWidth if tEditorsReportedWidth > tMinEditorsWidth then put tEditorsReportedWidth into tMinEditorsWidth @@ -125,64 +244,23 @@ on inspectorLayoutGroups pGroupList local tInspectorWidthWithMargins put tRowWidth + (tMargin * 2) into tInspectorWidthWithMargins + if there is a group "inspector" of me and \ + the vscrollbar of group "inspector" of me then + subtract the scrollbarwidth of group "inspector" of me from tRowWidth + end if + local tSubsections, tCurSection, tNewSubsection # Check if this inspector wants to show subsections put the showSubSections of me into tSubsections - local tMaxRowWidth, tInspectorHeight, tColumnNumber, tColumnTop - put 1 into tColumnNumber - repeat for each element tElement in pGroupList - if tSubsections and tElement["subsection"] is not empty then - # If we have a new subsection, create the subsection header - if tElement["subsection"] is not tCurSection then - lock messages - set the width of group ("Subsection_" & tElement["subsection"]) of me to the formattedwidth of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me - set the width of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me to the formattedwidth of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me - set the topleft of group ("Subsection_" & tElement["subsection"]) of me to tLeft,tTop - unlock messages - add (the formattedheight of field tElement["subsection"] of group ("Subsection_" & tElement["subsection"]) of me) to tTop - put tElement["subsection"] into tCurSection - end if - end if - - if there is a group tElement["label"] of me then - # set the width and topleft of the editor - lock messages - set the topleft of group tElement["label"] of me to tLeft,tTop - set the lockloc of group tElement["label"] of me to true - set the width of group tElement["label"] of me to tRowWidth - unlock messages - - # Tell the row to resize - dispatch "rowResize" to group tElement["label"] of me - - local tEditorHeight - # If the editor does not report its own height, use the formatted height - # This tends to report slightly strange values, otherwise we could just use it - # all the time. - put the editorHeight of group tElement["label"] of me into tEditorHeight - if not tEditorHeight > 0 then - put the formattedheight of group tElement["label"] of me into tEditorHeight - end if - - lock messages - add tEditorHeight + tPadding to tTop - - if tRowWidth > tMaxRowWidth then - put tRowWidth into tMaxRowWidth - end if - if tTop > tInspectorHeight then - put tTop into tInspectorHeight - end if - unlock messages - end if - end repeat + local tInspectorHeight, tCanExpand + put inspectorCalculateLayout(pGroupList, tLeft, tTop, tRowWidth, \ + tSubsections, tCurSection, 0, tCanExpand) into tInspectorHeight local tStackTop, tStackLeft put the top of me into tStackTop put the left of me into tStackLeft - if there is a field "noObjects" of me then set the width of field "noObjects" of me to 1000 put the formattedWidth of field "noObjects" of me into tMinRowWidth @@ -202,24 +280,88 @@ on inspectorLayoutGroups pGroupList layoutFrame end if - set the left of me to tStackLeft - local tStackHeight if tInspectorHeight is empty then - put kInspectorMinHeight into tStackHeight + if sManualHeightOfStack is not empty then + put sManualHeightOfStack into tStackHeight + else + put kInspectorMinHeight into tStackHeight + end if else put tInspectorHeight + tMargin into tStackHeight end if - set the minheight of me to tStackHeight - set the maxheight of me to tStackHeight - set the height of me to tStackHeight + if tCanExpand then + set the maxheight of me to 65535 + else + set the maxheight of me to tStackHeight + end if + + -- Make stack smaller rather than go offscreen + local tScreenRect, tNewStackHeight + put revIDEStackScreenRect(the long id of me, true) into tScreenRect + + if sManualHeightOfStack is not empty then + put min(sManualHeightOfStack, tStackHeight) into tNewStackHeight + set the height of this stack to min(tNewStackHeight, item 4 of tScreenRect - tStackTop) + else + set the height of this stack to min(tStackHeight, item 4 of tScreenRect - tStackTop) + end if + set the left of me to tStackLeft set the top of me to tStackTop + local tvScrollIsOn, tvScrollChanged + put false into tvScrollChanged + + if there is a group "inspector" of me then + put the vScrollbar of group "inspector" of me into tvScrollIsOn + if the height of me < tStackHeight - tMargin then + set the vscrollbar of group "inspector" of me to true + if not tvScrollIsOn then + put true into tvScrollChanged + end if + else + set the vscrollbar of group "inspector" of me to false + if tvScrollIsOn then + put true into tvScrollChanged + end if + end if + + set the rect of group "inspector" of me to \ + item 1 of tContentRect, \ + item 2 of tContentRect, \ + the right of this card of me, \ + the bottom of this card of me - tMargin + end if unlock messages + + # adapt right size of controls to vScrollbar on and off + if tvScrollChanged then resizeInspector + unlock screen end inspectorLayoutGroups +before resizeStack pNewWidth, pNewHeight, pOldWidth, pOldHeight + put pNewHeight into sNewHeight + put pOldHeight into sOldHeight + pass resizeStack +end resizeStack + +on resumeStack + put true into sStackIsInFront + pass resumeStack +end resumeStack + +on suspendStack + put false into sStackIsInFront + pass suspendStack +end suspendStack + +function getManualHeight + return sManualHeightOfStack +end getManualHeight + + local sSelectedSection, sSelectedSectionIndex private on inspectorSectionSet pSection if sDataA is empty then @@ -295,6 +437,18 @@ private on inspectorGenerate end if end inspectorGenerate +on tabKey + if the controlKey is down then + if sDataA[sSelectedSectionIndex+1] is an array then + inspectorSectionChanged sDataA[sSelectedSectionIndex+1]["label"] + else + inspectorSectionChanged sDataA[1]["label"] + end if + else + pass tabKey + end if +end tabKey + private command inspectorNoObject create group "noObjects" create field "noObjects" in group "noObjects" @@ -313,9 +467,6 @@ on inspectorGenerateGroups pGroupList set the margins of the templategroup to 0 set the visible of the templategroup to false - local tStackPath - set the behavior of the templategroup to the long ID of stack revIDEPaletteResourcePath("behaviors/revinspectorgroupbehavior.livecodescript", the long ID of stack "revInspector") - set the traversalon of the templatefield to false set the threed of the templatefield to false set the showborder of the templatefield to false @@ -328,10 +479,20 @@ on inspectorGenerateGroups pGroupList lock messages if there is not a group "template" then + local tBehavior + put the long ID of stack revIDEPaletteResourcePath( \ + "behaviors/revinspectorgroupbehavior.livecodescript", \ + the long ID of stack "revInspector") into tBehavior create group "template" + set the behavior of it to tBehavior create field "rowlabel" in group "template" set the topleft of field "rowlabel" of group "template" to the topleft of group "template" end if + + if there is not a group "inspector" then + create group "inspector" + set the rect of it to the rect of this card of me + end if unlock messages local tSubsections @@ -359,20 +520,22 @@ on inspectorGenerateGroups pGroupList end if lock messages - copy group "template" to me + local tRowGroup + copy group "template" to group "inspector" of me set the name of it to tElement["label"] - show group tElement["label"] of me + put the long id of group tElement["label"] of group "inspector" of me into tRowGroup + show tRowGroup unlock messages - set the rowShowLabel of group tElement["label"] of me to true + set the rowShowLabel of tRowGroup to true local tName - put the short name of group tElement["label"] of me into tName - if exists(group tElement["label"] of me) then + put the short name of tRowGroup into tName + if exists(tRowGroup) then local tPropList, tProperty repeat with y = 1 to the number of elements in tElement["proplist"] put tElement["proplist"][y] into tProperty if tProperty["user_visible"] is false then next repeat - dispatch "propertyRegister" to group tElement["label"] of me with tProperty + dispatch "propertyRegister" to tRowGroup with tProperty # Build the list of properties to display in the tooltip for the row if tPropList is empty then @@ -393,16 +556,16 @@ on inspectorGenerateGroups pGroupList put tElement["label"] into tLabel end if - set the rowTooltip of group tElement["label"] of me to tTooltip + set the rowTooltip of tRowGroup to tTooltip if tElement["label"] is not tElement["subsection"] then - set the rowLabel of group tElement["label"] of me to tLabel + set the rowLabel of tRowGroup to tLabel end if end if put empty into tPropList end repeat reset the templatefield reset the templategroup - + show group "inspector" unlock screen end inspectorGenerateGroups @@ -445,7 +608,7 @@ on inspectorChanged inspectorFill # Layout - inspectorLayout + inspectorLayout true unlock screen end inspectorChanged @@ -506,8 +669,8 @@ end inspectorFill on inspectorFillGroups pGroupData local tRow repeat for each key tRow in pGroupData - if there is a group tRow of me then - set the rowData of group tRow of me to pGroupData[tRow] + if there is a group tRow of group "inspector" of me then + set the rowData of group tRow of group "inspector" of me to pGroupData[tRow] end if end repeat end inspectorFillGroups @@ -566,10 +729,10 @@ private function rowLabelWidthCalculate local tMaxWidth, tLabelWidth, tChildren put 0 into tMaxWidth - put the childControlNames of this card of me into tChildren + put the childControlNames of group "inspector" of me into tChildren repeat for each line tControl in tChildren - if there is a field "rowlabel" of group tControl of me then - put the rowLabelWidth of group tControl of me into tLabelWidth + if there is a field "rowlabel" of group tControl of group "inspector" of me then + put the rowLabelWidth of group tControl of group "inspector" of me into tLabelWidth end if if tLabelWidth > tMaxWidth then put tLabelWidth into tMaxWidth diff --git a/Toolset/palettes/behaviors/revonlinestackbehavior.livecodescript b/Toolset/palettes/behaviors/revonlinestackbehavior.livecodescript new file mode 100644 index 0000000000..4353732039 --- /dev/null +++ b/Toolset/palettes/behaviors/revonlinestackbehavior.livecodescript @@ -0,0 +1,728 @@ +script "revOnlineStackBehavior" + +# Need to initialise stack +on preOpenStack + --global gRevUseTestServer + --put true into gRevUseTestServer + revOnlinePrefLoad + # Do this to prevent a resizeStack message being generated. We don't need this as we + # are already resizing. Remebers default size position of stack + lock messages + set the width of me to revOnlinePrefGet("width") + set the height of me to revOnlinePrefGet("height") + set the location of me to revOnlinePrefGet("location") + unlock messages + # Set the callback that will be sent if an internet connection is not available + # in this case will just display a message in the tooltip + revOnlineSetConnectionErrorCallback "rvoConnectionErrorDisplay", the long id of me + # Temporary measure + revOnlineSetAccountFailureCallback "rvoAccountFailureDisplay", the long id of me + # Load the saved cache data + revOnlineCacheLoad + login + send "initialize" to group "search filter" of me + send "initialize" to group "search order" of me + send "initialize" to group "paging" of me + send "initialize" to group "progressbar" of me + send "initialize" to group "search list" of me + send "initialize" to group "viewing pane" of me + updateBannerImage + updateView + rvoResize + --put "finished" after msg +end preOpenStack + +on closeStack + revOnlineCacheSave +end closeStack + + +# Wrapper needed to perform login attempt upon startup +private command login + if revOnlineSession() is not empty then + send "loggedInDisplay" to group "menubar" of me + else + if revOnlinePrefGet("rememberEmail") is true then + local tEmail, tPassword + put revOnlinePrefGet("Email") into tEmail + if revOnlinePrefGet("rememberPassword") is true then + put revOnlinePrefGet("passwordhash") into tPassword + revOnlineLogin tEmail, tPassword, "loginCallback", (the long id of me) + else + send "loggedOutDisplay" to group "menubar" of me + end if + else + send "loggedOutDisplay" to group "menubar" of me + end if + end if +end login + +command loginCallback pSuccess + if pSuccess then + send "loggedInDisplay" to group "menubar" of me + else + send "loggedOutDisplay" to group "menubar" of me + end if +end loginCallback + +# If no connection then need to reflect this in the gui +command rvoConnectionErrorDisplay + --revOnlineQueueClear + set the cTooltip of group "progressbar" of me to "Connection failure" + + rvoDrawProgressBar 0 + rvoHideProgressBar + --hide group "viewing pane" of me +end rvoConnectionErrorDisplay + +# The parameter is to distinguish an actual resize stack message from a scripted one +# If pUpdate is true the resize will potentially cause a new search request +command rvoResize pUpdate + # menubar + set the rect of group "menubar" of me to \ + (the left of this card of me, the top of this card of me, the right of this card of me,52) + send "resize" to group "Menubar" of me + + # progressbar + set the rect of group "progressbar" of me to \ + (the left of this card of me, the bottom of this card of me - 25, the right of this card of me, the bottom of this card of me) + local tDivider1, tDivider2 + put the left of button "resize bar" of me - 1 into tDivider1 + put the left of button "resize bar" of me + 300 into tDivider2 + send "resize tDivider1, tDivider2" to group "progressbar" of me + + # search filter + set the rect of group "search filter" of me to \ + (the left of this card of me, the bottom of group "menubar" of me, the left of button "resize bar" of me, the bottom of this card of me - 25) + send "resize" to group "Search Filter" of me + + # search order + set the rect of group "search order" of me to \ + (the right of group "search filter" of me, the bottom of group "menubar" of me, the right of group "search filter" of me + 284,the bottom of group "menubar" of me + 30) + send "resize" to group "search order" of me + + # pages + set the rect of group "paging" of me to \ + (the right of group "search filter" of me + 3, the bottom of group "search order" of me, the right of group "search filter" of me + 284, the bottom of group "search order" of me + 21) + send "resize" to group "paging" of me + + # resize bar + --set the rect of button "resize bar" of me to \ + --(the left of button "resize bar" of me, the bottom of group "paging" of me, the left of button "resize bar" of me + 2, the top of group "progressbar" of me) + + # editing controls + set the rect of group "edit controls" of me to \ + (the right of group "paging" of me, the bottom of group "search order" of me, the right of this card, the bottom of group "search order" of me + 21) + send "resize" to group "edit controls" of me + + # search list + if the cMode of group "search list" of me is "grid" then + set the rect of group "search list" of me to \ + (the right of button "resize bar" of me - 1, the bottom of group "paging" of me, the right of this card, the top of group "progressbar" of me) + else + set the rect of group "search list" of me to \ + (the right of button "resize bar" of me - 1, the bottom of group "paging" of me, the right of group "search filter" of me + 302, the top of group "progressbar" of me) + end if + send "resize pUpdate" to group "Search List" of me + + # Viewing Pane + set the rect of group "viewing pane" of me to \ + (the right of group "search list" of me, the bottom of group "paging" of me, the right of this card of me, the bottom of this card of me - 25) + send "resize" to group "Viewing pane" of me + + # resize bar + --set the height of button "resize bar" of me to (the top of group "progressbar" of me - the bottom of group "paging" of me) + --set the top of button "resize bar" of me to the bottom of group "paging" of me + + # Border + set the rect of graphic "border" of me to \ + (the right of button "resize bar" of me - 1, the top of group "paging" of me - 1, the right of this card + 40, the bottom of this card) +end rvoResize + +command rvoUpdateSearchFilter + send "intialize" to group "search filter" of me +end rvoUpdateSearchFilter + +command rvoDeleteStack pStackId pCallback + local tArray + put "deleteStack" into tArray["action"] + put pStackId into tArray["parameters"]["id"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "get", pCallback + return the result +end rvoDeleteStack + +# Returns an array containing all appropriate properties for the specified user. +command rvoFetchStackData pStackId, pCallback, pPrioritize + # Generate array request + local tArray + put "fetchStackData" into tArray["action"] + put pStackId into tArray["parameters"]["id"] + # Send the array to the CGI script, and call pCallback when done. + revOnlineQueryServer tArray, false, "get", pCallback, true, pPrioritize + + return the result +end rvoFetchStackData + +# Parameters +# pObjectType : one of the supported revOnline object types, e.g "stack", "external" etc +# pTag : the tag name to search for, could be empty if not searching by tag +# pQuery : the search query as specified by the search filter group +# pUserId : the user id to filter with. If empty, all users stacks are searched, otherwise only stacks where the user id matches are returned. +# pSearchType : one of the following: +# - "all" means all results are returned and if pQuery is empty, in a-z order, otherwise order of relevance to the search query +# - "top rated" means that a server specified number of results is returned, ordered by rating. +# - "latest" means that a server specified number of results is returned, ordered by date modified +# - "popular" means that a server specified number of results is returned, ordered by number of downloads +# pOffset : tells the server to start returning results at this offset in the search +# pMaxLength : the maximum number of results to return. +# pCallback : the callback to send when done. +# Description +# Returns an ordered array containing all the text data from the search results. pUserId will always be empty for now +# as the GUI is not going to initially support user filtering. +command rvoSearchStacks pParameters, pCallback, pPrioritize + local tRequest, tParameters + revOnlinePrefSet "lastSearch", pParameters + put pParameters into tParameters + put "searchStacks" into tRequest["action"] + put tParameters into tRequest["parameters"] + revOnlineQueryServer tRequest, "false", "get", pCallback, false, pPrioritize + return the result +end rvoSearchStacks + +# Parameters +# pObjectType : one of the supported revOnline object types, e.g "stack", "external" etc. +# pOrdering : server defined ordering, e.g "alphabetical", "popular". +# pOffset : tells the server to start returning tags at this offset in whatever the current ordering is. +# pLength : the number of tags we want returned. +# pCallback : the callback to send when done. +# Description +# When done, calls pCallback with an ordered return-delimited list of tags. +command rvoListTags pObjectType, pOrdering, pOffset, pLength, pCallback, pStackId, pUserId, pPrioritize + local tParameters + put pObjectType into tParameters["objectType"] + put pOrdering into tParameters["ordering"] + put pOffset into tParameters["offset"] + put pLength into tParameters["length"] + put pStackId into tParameters["stackid"] + put pUserId into tParameters["userid"] + + local tRequest + put "listTags" into tRequest["action"] + put tParameters into tRequest["parameters"] + + revOnlineQueryServer tRequest, "false", "get", pCallback, true, pPrioritize + return the result +end rvoListTags + +command rvoListTypes pCallback + local tRequest + put "listTypes" into tRequest["action"] + revOnlineQueryServer tRequest, "false", "get", pCallback + return the result +end rvoListTypes + +command rvoFetchStackProperty pStackId, pProperty, pCallback, pPrioritize + local tArray + put "fetchStackProperty" into tArray["action"] + put pStackId into tArray["parameters"]["id"] + put pProperty into tArray["parameters"]["propertyName"] + revOnlineQueryServer tArray, false, "get", pCallback, true, pPrioritize + return the result +end rvoFetchStackProperty + +command rvoLaunchStack pStackId + local tCallback + put revCallbackCreate(the long id of me, "rvoLaunchStackCallback") into tCallback + rvoUpdateTooltip "Downloading stack" + lock cursor + set the cursor to watch + revOnlineSetStatusCallback "rvoUpdateProgress", the long id of me + rvoFetchStackProperty pStackId, "data", tCallback +end rvoLaunchStack + +# Updates progressbar in response to uploading and downloading +command rvoUpdateProgress pUrl, pStatus + local tPercentage + put 0 into tPercentage + + if pStatus is among the words of "contacted requested" then + put 0 into tPercentage + end if + + if item 1 of pStatus is "loading" or item 1 of pStatus is "uploading" then + local tReceived + put item 2 of pStatus into tReceived + local tTotal + put item 3 of pStatus into tTotal + put round((tReceived / tTotal) * 100) into tPercentage + end if + + if pStatus is "uploaded" or pStatus is "downloaded" then + put 100 into tPercentage + end if + if pStatus is "error" or pStatus is "timeout" then + put 0 into tPercentage + end if + rvoDrawProgressBar tPercentage +end rvoUpdateProgress + +# Draws the progressbar and puts text into the tooltip field +command rvoDrawProgressBar pPercent, pMessage + + if pPercent < 100 then + send "update pPercent, rvoHiliteColor(), false" to group "loading progress" of group "progressBar" of me + if pMessage is not empty then + rvoUpdateTooltip pMessage + end if + --show group "loading progress" of group "progressBar" of stack "revonline" + else + send "update 100, rvoHiliteColor(), false" to group "loading progress" of group "progressBar" of me + if pMessage is not empty then + send "rvoClearTooltip pMessage" to me in 500 milliseconds + end if + --send "rvoDrawProgressBar 0" to me in 500 milliseconds + send "rvoHideProgressBar" to me in 500 milliseconds + end if + show group "loading progress" of group "progressBar" of me +end rvoDrawProgressBar + +command rvoHideProgressBar + hide group "loading progress" of group "progressBar" of me +end rvoHideProgressBar + + +# Hide progressbar +command hideProgress + hide group "loading progress" of group "progressBar" of me +end hideProgress + +# Returns the standard hilite color for revonline +function rvoHiliteColor + return revEnvironmentEditionProperty("revonline_hilite_color") +end rvoHiliteColor + +command rvoLaunchStackCallback pResult + unlock cursor + if pResult["result"]["data"] is not empty then + rvoUpdateTooltip "Stack downloaded", true + # Need to remove all searches that could potentially contain this stack + # as popular will now have changed + revOnlineCacheRemoveAction "searchStacks" + # stack has been updated so must clear cache of its details + local tArray, tKey + put "fetchStackData" into tArray["action"] + put pResult["stack_id"] into tArray["parameters"]["id"] + put revOnlineEncodeArray(tArray) into tKey + revOnlineCacheRemove tKey + else + rvoUpdateTooltip "error" + end if + # Prevents problem with users stacks throwing errors on startup + try + go stack pResult["result"]["data"] + catch tError + + end try +end rvoLaunchStackCallback + + + + +# Returns an array containing all appropriate properties for the specified user. +--command rvoFetchUserData pUserEmail, pCallback, pPrioritize +command rvoFetchUserData pUserId, pCallback, pPrioritize + # Generate array request + local tArray + put "fetchUserData" into tArray["action"] + put pUserId into tArray["parameters"]["id"] + # Send the array to the CGI script, and call pCallback when done. + revOnlineQueryServer tArray, false, "get", pCallback, true, pPrioritize + return the result +end rvoFetchUserData + +--command rvoFetchUserProperty pUserEmail, pProperty, pCallback, pPrioritize +command rvoFetchUserProperty pUserId, pProperty, pCallback, pPrioritize + local tArray + put "fetchUserProperty" into tArray["action"] + put pUserId into tArray["parameters"]["id"] + put pProperty into tArray["parameters"]["propertyName"] + # Send the array to the CGI script, and call pCallback when done. + revOnlineQueryServer tArray, false, "get", pCallback, true, pPrioritize + return the result +end rvoFetchUserProperty + +# Needs to be changed to a post instead of get +command rvoSetUserData pUserData, pCallBack + local tArray + put "setUserData" into tArray["action"] + ###put pUserEmail into tArray["parameters"]["email"] + --put revOnlineEmail() into tArray["parameters"]["email"] + put pUserData into tArray["parameters"]["userData"] + ##put the text of field "sessionId" into tArray["parameters"]["sessionId"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "post", pCallback + return the result +end rvoSetUserData + +# Needs to be changed to a post instead of get +command rvoSetStackData pStackData, pStackId, pCallBack + local tArray + put "setStackData" into tArray["action"] + put pStackData into tArray["parameters"]["stackData"] + put pStackId into tArray["parameters"]["stackid"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + + # Progressbar + revOnlineSetStatusCallback "rvoUpdateProgress", the long id of me + + revOnlineQueryServer tArray, false, "post", pCallback + return the result +end rvoSetStackData + +command rvoIsStackRateable pStackId, pRevision, pCallBack + local tArray + put "isStackRateable" into tArray["action"] + put pStackId into tArray["parameters"]["id"] + put pRevision into tArray["parameters"]["revision"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "get", pCallback + return the result +end rvoIsStackRateable + +command rvoRateStack pStackId, pRating, pRevision, pCallBack + rvoUpdateTooltip "Submitting rating ..." + local tArray + put "rateStack" into tArray["action"] + put pStackId into tArray["parameters"]["id"] + put pRevision into tArray["parameters"]["revision"] + put pRating into tArray["parameters"]["rating"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "get", pCallback + return the result +end rvoRateStack + +command rvoTagStack pStackId, pTag, pCallBack + local tArray + put "tagStack" into tArray["action"] + put pStackId into tArray["parameters"]["stackid"] + put pTag into tArray["parameters"]["name"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "get", pCallback +end rvoTagStack + +command rvoEditTags pStackId, pTags, pCallback + local tArray + put "editTags" into tArray["action"] + put pStackId into tArray["parameters"]["stackid"] + --put pTag into tArray["parameters"]["name"] + put pTags into tArray["parameters"]["tagList"] + put revOnlineSession() into tArray["parameters"]["sessionId"] + revOnlineQueryServer tArray, false, "get", pCallback +end rvoEditTags + +##################################################################### +# Utility Functions +###################################################################### + +local sCallbackLastHandle, sCallBacks, sLastCallback + +command log pMessage + put pMessage & return after msg +end log + +command logArray pArray + local tOutput + logArrayRecurse pArray, 0, tOutput + log tOutput +end logArray + +command logArrayRecurse pArray pIndent, @rOutput + local tOutput + local tIndent + put pIndent into tIndent + repeat for each key tKey in pArray + if the keys of pArray[tKey] is empty then + repeat with x = 1 to pIndent + put tab after rOutput + end repeat + put tKey && ":" && pArray[tKey] & return after rOutput + else + add 1 to tIndent + repeat with x = 1 to pIndent + put tab after rOutput + end repeat + put tKey && "-" && return after rOutput + logArrayRecurse pArray[tKey], tIndent, rOutput + end if + end repeat +end logArrayRecurse + +local sRequestQueue +local sPendingRequests +local sLastOffset + +command updateSearchList pOffset, pPrioritize + local tOffset + # Need to preserve the offset if the search is updated due to a resize + if pOffset is empty then + # need to make sure item 1 is somewhere on the newly created page + local tNewPage + put trunc(sLastOffset / (the cPageLimit of group "search list" of me)) into tNewPage + put (the cPageLimit of group "search list" of me) * tNewPage into tOffset + set the cPage of group "paging" of me to tNewPage + 1 + else + put pOffset into tOffset + end if + + if tOffset is 0 then + set the cPages of group "paging" of me to empty + set the cPage of group "paging" of me to 1 + end if + + local tParameters + put the cSelectedUser of group "search filter" of me into tParameters["userid"] + put the cSelectedType of group "search filter" of me into tParameters["objectType"] + if the cSelectedTag of group "search filter" of me is "all" then + put empty into tParameters["tag"] + else + put the cSelectedTag of group "search filter" of me into tParameters["tag"] + end if + put the cSearchString of group "search filter" of me into tParameters["query"] + put the cSelectedOrder of group "search order" of me into tParameters["searchType"] + put the cSelectedDirection of group "search order" of me into tParameters["direction"] + + put tOffset into tParameters["offset"] + put the cPageLimit of group "search list" of me into tParameters["maxlength"] + put tOffset into sLastOffset + + local tCallback + put revCallbackCreate(the long id of me, "updateSearchListCallback") into tCallback + + rvoCancelSearch + rvoRegisterSearchStart + rvoSearchStacks tParameters, tCallback, pPrioritize + rvoRegisterSearchRequest the result +end updateSearchLIst + + +# Now populate the list etc. +command updateSearchlistCallback pResult + local tResultCount + put pResult["resultCount"] into tResultCount + local tPages, tTruncPages, tPageLimit, tStacksOnCurrentPage, tTotalStacksOnline + put the cPageLimit of group "search list" of me into tPageLimit + put tResultCount / tPageLimit into tPages + put trunc(tPages) into tTruncPages + # prevent an extra blank page + if tPages - tTruncPages <> 0 then + put tTruncPages + 1 into tPages + end if + + ## New stuff + put the number of elements of pResult["results"] into tStacksOnCurrentPage + put pResult["totalStackCount"] into tTotalStacksOnline + send "updateNumberOfStacks tStacksOnCurrentPage, tResultCount, tTotalStacksOnline" to group "ProgressBar" of me + + set the cPages of group "paging" of me to tPages + set the cList of group "search list" of me to pResult["results"] +end updateSearchlistCallback + +command updateViewingPane pViewType, pObjectId + --put "stuff" after msg + # Check viewing pane pref + if pViewType is empty then + set the cViewType of group "viewing pane" of me to revOnlinePrefGet("view type") + else + revOnlinePrefSet "view type", pViewType + set the cViewType of group "viewing pane" of me to pViewType + end if + + # Set content of viewing pane + if the cViewType of group "viewing pane" of me is "stack" then + if pObjectId is not empty then + set the cStack of group "stack" of me to pObjectId + if pObjectId is not "new" then + --rvoUpdateTooltip "Retrieving stack details" + revOnlinePrefSet "stack Id", pObjectId + end if + else + set the cStack of group "stack" of me to revOnlinePrefGet("stack id") + end if + else if the cViewType of group "viewing pane" of me is "user" then + --rvoUpdateTooltip "Retrieving user details ..." + if pObjectId is not empty then + set the cUser of group "user" of me to pObjectId + revOnlinePrefSet "user Id", pObjectId + else + set the cUser of group "user" of me to revOnlinePrefGet("user id") + end if + end if +end updateViewingPane + +# Will adjust list and viewing pane groups appropriately +command updateView pMode, pView, pId + --put "id:" && pId && return after msg + lock screen + local tPreviousMode + put the cMode of group "search list" of me into tPreviousMode + + # Check mode prefs list/grid + if pMode is not empty then + set the cMode of group "search list" of me to pMode + revOnlinePrefSet "mode", pMode + else + set the cMode of group "search list" of me to revOnlinePrefGet("mode") + end if + + # Clear editing controls + send "hideAll" to group "edit controls" of me + + if the cMode of group "search list" of me is "list" then + set the cSelectedView of group "search order" of me to "list" + # Need to check what type of content will be displayed in viewing pane + local tViewType + if pView is empty then + put revOnlinePrefGet("view type") into tViewType + else + put pView into tViewType + end if + # Now update viewing pane accordingly + # If the content type is stack, no stacks have previously been viewed and pId is empty + # then need to choose a random stack + if tViewType is "stack" and pId is empty and revOnlinePrefGet("stack id") is empty then + local tCallback + put revCallbackCreate(the long id of me, "updateViewingPane") into tCallback + revCallbackAddParameter tCallback, pView + revOnlinePickRandomStack tCallback + else + updateViewingPane pView, pId + end if + else if the cMode of group "search list" of me is "grid" then + set the cSelectedView of group "search order" of me to "grid" + end if + + rvoResize + # Need to make sure the searchlist is updated when switching between grid/list + if (pMode is "list" and tPreviousMode is "grid") or (pMode is "grid" and tPreviousMode is "list") then + updateSearchList empty, true + end if + unlock screen +end updateView + +# Updates the tooltip field with a message, if pWithClear is true then the tooltip +# will be cleared after a set period of time. With wait ensures the message will +# display for a minimum time period +command rvoUpdateTooltip pMessage, pWithClear, pWithWait + if pMessage is "bad_login" or pMessage is "cgierror,not_logged_in" then + set the cTooltip of group "progressbar" of me to "You are not logged in" + send "loggedOutDisplay" to group "menubar" of me + else + set the cTooltip of group "progressbar" of me to pMessage + end if + if pWithWait then + set the cWait of group "progressbar" of me to "true" + end if + if pWithClear then + send "rvoClearTooltip pMessage" to me in 3 seconds + end if +end rvoUpdateTooltip + +command rvoClearTooltip pMessage + --put the cTooltip of group "progressbar" of me + if the cTooltip of group "progressbar" of me is pMessage then + set the cTooltip of group "progressbar" of me to empty + end if +end rvoClearTooltip + +on resizestack + revOnlinePrefSet "width", the width of me + revOnlinePrefSet "height", the height of me + revOnlinePrefSet "location", the location of me + if the short name of this card is "main" then + rvoresize "true" + end if +end resizestack + +# Handlers to remember default location/size +on moveStack + send "revOnlineUpdateOnStackMoved" to me in 0 milliseconds +end moveStack + +command revOnlineUpdateOnStackMoved + if the iconic of me then + exit revOnlineUpdateOnStackMoved + end if + revOnlinePrefSet "location", the location of me +end revOnlineUpdateOnStackMoved + + +function capitaliseChar1 pString + return ((toUpper(char 1 of pString)) & char 2 to - 1 of pString) +end capitaliseChar1 + + +local sSearchRequests + +# Description +# Registers the beginning of a new stack search. Clearing out any previous ones. This should be called +# In updateSearchList before the searchStacks query is sent out. +command rvoRegisterSearchStart + put empty into sSearchRequests +end rvoRegisterSearchStart + +# Parameters +# pId : a queue request id as returned by revOnlineQueryServer +# Description +# Registers the specified id as part of the current search. This means that this request will be cancelled +# when rvoCancelSearch is called. +command rvoRegisterSearchRequest pId + if sSearchRequests is empty then + put pId into sSearchRequests + else + put return & pId after sSearchRequests + end if +end rvoRegisterSearchRequest + +# Description +# Cancels the current search by cancelling all requests that have been registered as part of it. +command rvoCancelSearch + repeat for each line tRequest in sSearchRequests + --put tRequest & return after msg + revOnlineQueueCancel tRequest + end repeat + put empty into sSearchRequests +end rvoCancelSearch + +### Temporary +command rvoAccountFailureDisplay + set the cTooltip of group "progressbar" of me to "A valid license is required to create a RevOnline account" +end rvoAccountFailureDisplay + +# Used by "share this stack" item in file menu of revmenubar +command rvoShareThisStack pStackPath + --put "!!!" & return after msg + lock screen + updateView "list", "stack", "new" + send "newStackFile pStackPath" to group "stack" of group "viewing pane" of me + unlock screen + --put "finished Shre" & return after msg +end rvoShareThisStack + +on updateBannerImage + local tPath + + if char 1 of the version < 7 then + put ideCoreFolderPath("skin","revOnline-top_legacy.png") into tPath + else + put ideCoreFolderPath("skin","revOnline-top.png") into tPath + end if + set the filename of image "topBanner" of group "menubar" to tPath + set the width of image "topBanner" of group "menubar" to the formattedWidth of image "topBanner" + set the topLeft of image "topBanner" of group "menubar" to 0,0 +end updateBannerImage + + + + + diff --git a/Toolset/palettes/behaviors/revpalettebehavior.livecodescript b/Toolset/palettes/behaviors/revpalettebehavior.livecodescript index 407697eb48..7177a7adc5 100644 --- a/Toolset/palettes/behaviors/revpalettebehavior.livecodescript +++ b/Toolset/palettes/behaviors/revpalettebehavior.livecodescript @@ -88,6 +88,27 @@ on hideFrameItem pName generateFrame end hideFrameItem +on disableFrameItem pName + setEnabledOfFrameItem pName, false +end disableFrameItem + +on enableFrameItem pName + setEnabledOfFrameItem pName, true +end enableFrameItem + +command setEnabledOfFrameItem pName, pValue + local tIndex + put __frameItemNameToIndex(pName) into tIndex + if tIndex is not a number then exit setEnabledOfFrameItem + + lock screen + lock messages + put pValue into sData[tIndex]["enabled"] + generateFrame + unlock messages + unlock screen +end setEnabledOfFrameItem + on toggleFrameItem pName, pValue local tIndex put __frameItemNameToIndex(pName) into tIndex @@ -112,32 +133,6 @@ on hiliteFrameItem pName unlock screen end hiliteFrameItem -on disableFrameItem pName - local tIndex - put __frameItemNameToIndex(pName) into tIndex - if tIndex is not a number then exit disableFrameItem - - lock screen - lock messages - put false into sData[tIndex]["enabled"] - generateFrame - unlock messages - unlock screen -end disableFrameItem - -on enableFrameItem pName - local tIndex - put __frameItemNameToIndex(pName) into tIndex - if tIndex is not a number then exit enableFrameItem - - lock screen - lock messages - put true into sData[tIndex]["enabled"] - generateFrame - unlock messages - unlock screen -end enableFrameItem - on clearFrameData put empty into sData end clearFrameData @@ -193,9 +188,13 @@ private on appendMenuItem pNavItem, @xMenuArray if pNavItem["value_type"] is "enum" then put tValue is tPreferenceValue into tChecked else - put tValue is among the items of tPreferenceValue into tChecked + if the number of lines in tPreferenceValue > 1 then + put tValue is among the lines of tPreferenceValue into tChecked + else + put tValue is among the items of tPreferenceValue into tChecked + end if end if - + if tChecked then put true into tMenuItemA["menu"][tItemCount]["checked"] else @@ -480,11 +479,11 @@ on layoutFrame pForceRecalculate local tHeaderWidth, tFooterWidth if there is a widget "header_background" of group "background" of me then set the height of widget "header_background" of group "background" of me to BAR_HEIGHT - put the formattedWidth of widget "header_background" of group "background" of me into tHeaderWidth + put the minWidth of widget "header_background" of group "background" of me into tHeaderWidth end if if there is a widget "footer_background" of group "background" of me then set the height of widget "footer_background" of group "background" of me to BAR_HEIGHT - put the formattedWidth of widget "footer_background" of group "background" of me into tFooterWidth + put the minWidth of widget "footer_background" of group "background" of me into tFooterWidth end if local tMinWidth @@ -509,12 +508,18 @@ on layoutFrame pForceRecalculate end if unlock messages if pForceRecalculate then - dispatch "resizeStack" to this card of me + dispatch "resizeStack" to this card of me with \ + the width of this card of me, the height of this card of me end if unlock screen end layoutFrame +# Sent when the tab navigation is clicked +on navChanged + layoutFrame true +end navChanged + # Sent when the preference changes on displayPreferenceChanged pPreference, pValue local tName @@ -539,9 +544,9 @@ after resizeStack end if end resizeStack -on desktopChanged +on ideDesktopChanged revIDEEnsureOnScreen the short name of this stack -end desktopChanged +end ideDesktopChanged after openCard generateFrame @@ -554,6 +559,7 @@ before preOpenStack end preOpenStack after preOpenStack + revIDESubscribe "ideDesktopChanged" if sHideFrame is not true then put revIDEColor("edition_color") into TAB_SELECTED_TEXT_COLOR put revIDEColor("edition_color") into TAB_HOVER_TEXT_COLOR diff --git a/Toolset/palettes/dictionary/behaviors/revdictionarybehavior.livecodescript b/Toolset/palettes/dictionary/behaviors/revdictionarybehavior.livecodescript index 809730cffc..c690d515b4 100644 --- a/Toolset/palettes/dictionary/behaviors/revdictionarybehavior.livecodescript +++ b/Toolset/palettes/dictionary/behaviors/revdictionarybehavior.livecodescript @@ -1,4 +1,4 @@ -script "revDictionaryBehavior" +script "revDictionaryBehavior" with behavior "revPaletteBehavior" -- The dictionary starts to hide elements at lower than 992 pixels -- *TODO* Tweak the CSS to rearrange things appropriately constant kDictionaryMinWidth = 992 @@ -22,7 +22,7 @@ on openStack lock screen --Force the browser to actually resize set the rect of widget "Dictionary" of me to 0,0,0,0 - set the javascripthandlers of widget "Dictionary" of me to "linkClicked" + set the javascripthandlers of widget "Dictionary" of me to "linkClicked" & return & "showUpgradeOptions" set the width of me to tMinWidth set the minWidth of me to tMinWidth set the title of me to "Dictionary" @@ -82,3 +82,27 @@ end navigateToEntry on linkClicked pLink launch url pLink end linkClicked + +on showUpgradeOptions pEdition, pDisplayName + put urlEncode(pDisplayName) into pDisplayName + replace "+" with "%20" in pDisplayName + + launch url revEnvironmentEditionProperty("edition_external_url", pEdition) & \ + "?utm_source=ide&utm_medium=docs&utm_campaign="&pDisplayName +end showUpgradeOptions + +# bug 17819 enable cmd+c in dictionary +on commandKeyDown pWhich + switch pWhich + case "A" + -- trap Cmd + A for select all + case "C" + -- trap Cmd + C for copy + break + case "W" + close me + break + default + pass commandKeyDown + end switch +end commandKeyDown diff --git a/Toolset/palettes/extension builder/revextensionbuilder.livecode b/Toolset/palettes/extension builder/revextensionbuilder.livecode new file mode 100644 index 0000000000..c096dffe4a Binary files /dev/null and b/Toolset/palettes/extension builder/revextensionbuilder.livecode differ diff --git a/Toolset/palettes/extension builder/revextensionbuilderbehavior.livecodescript b/Toolset/palettes/extension builder/revextensionbuilderbehavior.livecodescript new file mode 100644 index 0000000000..43c97b81ed --- /dev/null +++ b/Toolset/palettes/extension builder/revextensionbuilderbehavior.livecodescript @@ -0,0 +1,522 @@ +script "revExtensionBuilderBehavior" +local sLoadedExtension + +on preOpenStack + dispatch "setAsBehavior" to revIDEFrameBehavior() with the long id of this me + + ### Header + generateExtensionFrame + + put "No API entries found" into field "message_api" of me + put "No user guide found" into field "message_guide" of me + + put revIDEGetPreference("extensionBuilderPlugin_lastSelected") into sLoadedExtension + + populateExtensionList + + clearExtension + + send "resizeStack" to me + + openExtension sLoadedExtension + + revIDESubscribe "ideExtensionLog" + revIDESubscribe "ideExtensionStatusChanged" + revIDESubscribe "ideExtensionsChanged" + revIDESubscribe "idePreferenceChanged:cDeveloperExtensionsFolders" + revIDESubscribe "idePreferenceChanged:cDeveloperExtensionsActiveFolders" +end preOpenStack + +private function FolderPathForMenu pFolder + local tFolder + put pFolder into tFolder + replace "!" with "\!" in pFolder + if the platform is "MacOS" then + replace "/" with "\/" in pFolder + replace "(" with "\(" in pFolder + else + replace "/" with "//" in pFolder + end if + return tFolder & ":" & pFolder +end FolderPathForMenu + +command generateExtensionFrame + clearFrameData + + local tFolders, tMenuItem, tOptions + put revIDEDeveloperExtensionsFolders() into tFolders + repeat for each line tLine in tFolders + put FolderPathForMenu(tLine) into tMenuItem + if tOptions is empty then + put tMenuItem into tOptions + else + put comma & tMenuItem after tOptions + end if + end repeat + + addFrameItem "cDeveloperExtensionsActiveFolders", "header", "preference", "Folders to search for extensions", "set", tOptions, "togglePreference", the long id of me + + --addFrameItem "add","header", "action", "Create a new extension", "plus sign", "plus sign","headerActionNewExtension", the long id of me + addFrameItem "open","header", "action", "Open an existing extension", "folder open", "folder open","headerActionOpenExtension", the long id of me + addFrameItem "edit source", "header", "action", "Edit extension source code", "lc-edit-script", "lc-edit-script", "headerActionEditSource", the long id of me + + addFrameItem "package","footer", "action", "Package", "archive", "archive","footerActionPackage", the long id of me + addFrameItem "uninstall","footer", "action", "Uninstall", "remove circle", "remove circle","footerActionUninstall", the long id of me + addFrameItem "install","footer", "action", "Install", "plus sign", "plus sign","footerActionInstall", the long id of me + addFrameItem "stop testing","footer", "action", "Stop testing extension", "stop circle", "stop circle","footerActionStopTesting", the long id of me + addFrameItem "test","footer", "action", "Test extension", "play circle", "play circle","footerActionTest", the long id of me + +end generateExtensionFrame + +on idePreferenceChanged pPref + switch pPref + case "cDeveloperExtensionsFolders" + case "cDeveloperExtensionsActiveFolders" + --Refresh the header list + generateExtensionFrame + populateExtensionList + break + end switch +end idePreferenceChanged + +on closeStackRequest + if there is folder sLoadedExtension then + revIDESetPreference "extensionBuilderPlugin_lastSelected", sLoadedExtension + end if + + clearExtension + + pass closeStackRequest +end closeStackRequest + +on closeStack + revIDEUnsubscribeAll +end closeStack + +########################## +### CALLBACKS ### +on ideExtensionLog pMessage + lock screen + lock messages + if field "console" of me is empty then + put the time & ":" && pMessage into field "console" of me + else + put return & the time & ":" && pMessage after field "console" of me + end if + + // BN-2016-08-11: [[Bug 18169]] Scrollbar not visible when console_content > field_height + consoleScrollbarUpdate + + set the vscroll of field "console" of me to the formattedheight field "console" of me + unlock messages + unlock screen +end ideExtensionLog + +private on consoleScrollbarUpdate + if the formattedheight of field "console" of me > the height of field "console" of me then + set the vscrollbar of field "console" to true + else + set the vscrollbar of field "console" to false + end if +end consoleScrollbarUpdate + +on togglePreference pPreference, pValue + switch pPreference + case "cDeveloperExtensionsActiveFolders" + local tCurrentPreferenceValue, tPreferencePosition, tLineOffset + put revIDEGetPreference("cDeveloperExtensionsActiveFolders") into tCurrentPreferenceValue + put lineOffset(pValue, tCurrentPreferenceValue) into tLineOffset + if tLineOffset is not 0 then + delete line tLineOffset of tCurrentPreferenceValue + else + if tCurrentPreferenceValue is empty then + put pValue into tCurrentPreferenceValue + else + put return & pValue after tCurrentPreferenceValue + end if + end if + revIDESetPreference "cDeveloperExtensionsActiveFolders", tCurrentPreferenceValue + break + end switch +end togglePreference + +on headerActionNewExtension +end headerActionNewExtension + +on headerActionEditSource + revIDEDeveloperExtensionEditScript loadedExtensionGet() +end headerActionEditSource + +on headerActionOpenExtension + answer file "Please select a valid extension file" \ + with type "LiveCode Builder|lcb" \ + or type "LiveCode Script|livecode,livecodescript" + + if the result is "cancel" then exit headerActionOpenExtension + if there is not a file it then exit headerActionOpenExtension + + # User has chose a valid file so load it. The load command returns the data array + # for the given extenion + set the itemdelimiter to slash + openExtension item 1 to -2 of it +end headerActionOpenExtension + +on footerActionPackage + revIDEDeveloperExtensionBuildPackage loadedExtensionGet() +end footerActionPackage + +on footerActionInstall + revIDEDeveloperExtensionInstall loadedExtensionGet() +end footerActionInstall + +on footerActionUninstall + revIDEDeveloperExtensionUninstall loadedExtensionGet() +end footerActionUninstall + +on footerActionTest + revIDEDeveloperExtensionTest loadedExtensionGet() +end footerActionTest + +on footerActionStopTesting + revIDEDeveloperExtensionStopTesting +end footerActionStopTesting + +on footerActionEditSource + revIDEDeveloperExtensionEditScript loadedExtensionGet() +end footerActionEditSource + +on openExtension pPath + if there is not a folder pPath then exit openExtension + + clearExtension + + lock screen + revIDEDeveloperExtensionOpen pPath + + lock messages + local tExtensionData + put the result into tExtensionData + + # Store the loaded extension path + put pPath into sLoadedExtension + + # Update the extension list box selected + populateExtensionList + + # Clear the console window + put empty into field "console" of me + + # Display the data for the given extenion + displayExtensionData tExtensionData + + # Update actions depending on status + ideExtensionStatusChanged + unlock messages + unlock screen +end openExtension + +on updateExtension + local tExtensionData + revIDEDeveloperExtensionOpen sLoadedExtension + put the result into tExtensionData + displayExtensionData tExtensionData +end updateExtension + +########################## +### Standard libraries ### + +function loadedExtensionGet + return sLoadedExtension +end loadedExtensionGet + +function getDisplayName pData + if pData["display name"] is not empty then + return pData["display name"] + end if + + if pData["title"] is not empty then + return pData["title"] + end if + + return pData["name"] +end getDisplayName + +on populateExtensionList + # Get a list of all the available extenions + local tExtensionData + put revIDEDeveloperExtensions() into tExtensionData + + # Prepare a label for the chooser. In the loop, if we find the loaded + # extension we'll overwrite with the name of the loaded extension + local tSelectedLabel + put "Please Select..." into tSelectedLabel + + # Loop through the array data and build a list of: + # path | label + local tExtensions, tDisplayName, tNameList + repeat for each key tFolder in tExtensionData + + # Build the display name. Use path if no name is available + put getDisplayName(tExtensionData[tFolder]) into tDisplayName + if tDisplayName is empty then + put tFolder into tDisplayName + end if + get the number of elements in tNameList[tDisplayName] + put tFolder into tNameList[tDisplayName][it + 1] + end repeat + + local tKeys + put the keys of tNameList into tKeys + sort tKeys + repeat for each line tDisplayName in tKeys + local tNumDuplicated, tToDisplay + put the number of elements in tNameList[tDisplayName] into tNumDuplicated + repeat with x = 1 to tNumDuplicated + put tNameList[tDisplayName][x] into tFolder + if tNumDuplicated > 1 then + -- disambiguate dupes with path + put tDisplayName && "(" & tFolder & ")" into tToDisplay + else + put tDisplayName into tToDisplay + end if + replace "/" with "\/" in tToDisplay + + # Construct the list path / label + if tExtensions is empty then + put tToDisplay & "/|" & tFolder into tExtensions + else + put return & tToDisplay & "/|" & tFolder after tExtensions + end if + + # Check if this is the loaded extension + if tFolder is sLoadedExtension then + put tToDisplay into tSelectedLabel + end if + end repeat + end repeat + + # Set the list on the extension chooser button + set the text of button "extensions2" of me to tExtensions + + # If the loaded extension is in the last, set the label of + set the label of button "extensions2" of me to tSelectedLabel +end populateExtensionList + +private on displayExtensionData pData + if pData["file"] is empty then + disableFrameItem "edit source" + else + enableFrameItem "edit source" + end if + + # Exntensions label + local tLabel + put getDisplayName(pData) into tLabel + if tLabel is empty then + put sLoadedExtension & slash & pData["file"] into tLabel + end if + set the label of button "extensions2" of me to tLabel + + # Load icons + # AL-2015-05-22: [[ Bug 14729 ]] Display default widget and library icons if none are provided + if there is a file pData["icon"] then + put URL ("binfile:" & pData["icon"]) into image "icon" of me + else + put URL ("binfile:" & revIDEDefaultExtensionIcon(pData["type"], false)) into image "icon" of me + end if + + if there is a file pData["retina_icon"] then + put URL ("binfile:" & pData["retina_icon"]) into image "icon_retina" of me + else + put URL ("binfile:" & revIDEDefaultExtensionIcon(pData["type"], true)) into image "icon_retina" of me + end if + + local tHaveSvgIcon + put (pData["svgicon"] is not empty) into tHaveSvgIcon + set the visible of widget "svgicon" of me to tHaveSvgIcon + set the visible of widget "svgicon_retina" of me to tHaveSvgIcon + set the visible of field "label_svgicon_absent" of me to not tHaveSvgIcon + if tHaveSvgIcon then + set the iconPath of widget "svgicon" of me to pData["svgicon"] + set the iconPath of widget "svgicon_retina" of me to pData["svgicon"] + end if + + # Load resources + # AL-2015-03-18: [[ Bug 14998 ]] Resources not displaying in plugin + if pData["resources"] is not empty then put pData["resources"] into field "resources" of me + else put "No resources found in extension" into field "resources" of me + + # API + if pData["api"] is not empty or pData["api_file"] is not empty then + put "Yes" into field "message_api" of me + else + put "No API data found" into field "message_api" of me + end if + + # Userguide + if pData["guide_file"] is not empty then put "Yes" into field "message_guide" of me + else put "No user guide found" into field "message_guide" of me + + # Default script + if pData["defaultscript_file"] is not empty then put pData["defaultscript_file"] into field "defaultscript" of me + else put "No default script found" into field "defaultscript" of me + + # Clear the console + put empty into field "console" of me +end displayExtensionData + +on clearExtension + lock screen + lock messages + + set the text of image "icon_retina" of me to empty + set the text of image "icon" of me to empty + set the iconPath of widget "svgicon_retina" of me to empty + set the visible of widget "svgicon_retina" of me to false + set the iconPath of widget "svgicon" of me to empty + set the visible of widget "svgicon" of me to false + set the visible of field "label_svgicon_absent" of me to true + + put empty into field "resources" of me + put empty into field "message_api" of me + put empty into field "message_guide" of me + put empty into field "console" of me + put empty into field "defaultscript" of me + unlock messages + unlock screen +end clearExtension + +on resizeStack + local tRect, tMargin, tPadding + put the contentrect of me into tRect + put the paletteMargin of me * 2 into tMargin + put the palettePadding of me * 2 into tPadding + + lock messages + lock screen + + + local tLeft, tTop, tRight, tBottom + put item 4 of tRect - tMargin into tBottom + put item 3 of tRect - tMargin into tRight + + # Extensions + local tLabelWidth + put the width of me * 0.25 into tLabelWidth + put item 1 of tRect + tMargin into tLeft + put item 2 of tRect + tMargin into tTop + set the width of field "label_extensions" of me to tLabelWidth + set the topleft of field "label_extensions" of me to tLeft,tTop + put the right of field "label_extensions" of me + tPadding into tLeft + set the rect of button "extensions" of me to tLeft, tTop, item 3 of tRect-tMargin, tTop + 22 + set the rect of button "extensions2" of me to tLeft, tTop, item 3 of tRect-tMargin, tTop + 22 + put the bottom of button "extensions" of me+tPadding into tTop + + # Icons + put item 1 of tRect + tMargin into tLeft + set the width of field "label_icons" of me to tLabelWidth + set the topleft of field "label_icons" of me to tLeft,tTop + put the right of field "label_icons" of me + tPadding into tLeft + set the topleft of image "icon_retina" of me to tLeft,tTop + put the right of image "icon_retina" of me + tPadding into tLeft + set the topleft of image "icon" of me to tLeft,tTop + + # Resources + put item 1 of tRect + tMargin into tLeft + put item 3 of tRect - tMargin into tRight + put the bottom of image "icon_retina" of me + tPadding into tTop + set the width of field "label_resources" of me to tLabelWidth + set the topleft of field "label_resources" of me to tLeft,tTop + put the right of field "label_icons" of me + tPadding into tLeft + set the rect of field "resources" of me to tLeft,tTop,tRight, tTop+(the height of this card * 0.1) + + # Default script + put item 1 of tRect + tMargin into tLeft + put item 3 of tRect - tMargin into tRight + put the bottom of field "resources" of me + tPadding into tTop + set the width of field "label_defaultscript" of me to tLabelWidth + set the topleft of field "label_defaultscript" of me to tLeft,tTop + put the right of field "label_defaultscript" of me + tPadding into tLeft + set the rect of field "defaultscript" of me to tLeft,tTop,tRight, tTop+(the height of this card * 0.15) + set the topright of button "defaultscript_edit" of me to tRight, the bottom of field "defaultscript" of me + tPadding + + # API + put item 1 of tRect + tMargin into tLeft + put the bottom of button "defaultscript_edit" of me + tPadding into tTop + set the width of field "label_api" of me to tLabelWidth + set the topleft of field "label_api" of me to tLeft,tTop + put the right of field "label_api" of me + tPadding into tLeft + set the rect of field "message_api" of me to tLeft, tTop, tRight, tTop+the formattedheight of field "message_api" of me - the margins of field "message_api" of me + + # Guide + put item 1 of tRect + tMargin into tLeft + put the bottom of field "message_api" of me + tPadding into tTop + set the width of field "label_guide" of me to tLabelWidth + set the topleft of field "label_guide" of me to tLeft,tTop + put the right of field "label_guide" of me + tPadding into tLeft + set the rect of field "message_guide" of me to tLeft, tTop, tRight, tTop+the formattedheight of field "message_guide" of me - the margins of field "message_guide" of me + + # Console + put item 1 of tRect + tMargin into tLeft + put the bottom of field "message_guide" of me + 2 * tPadding into tTop + put item 3 of tRect - tMargin into tRight + set the topleft of field "label_console" of me to tLeft, tTop + + put the bottom of field "label_console" of me + tPadding into tTop + set the rect of field "console" of me to tLeft, tTop, tRight, tBottom + consoleScrollbarUpdate + + unlock screen + unlock messages + + pass resizeStack +end resizeStack + +on editDefaultScript + local tTargetStack + revIDEDeveloperExtensionEditDefaultScript sLoadedExtension + put the result into tTargetStack + + revIDESubscribe "idePropertyChanged", tTargetStack +end editDefaultScript + +on idePropertyChanged + local tNewScript + put revIDEDeveloperExtensionFetchDefaultScript(sLoadedExtension) into tNewScript + if tNewScript is not field "defaultscript" of me then + put tNewScript into field "defaultscript" of me + end if +end idePropertyChanged + +on ideExtensionsChanged + ideExtensionStatusChanged +end ideExtensionsChanged + +on ideExtensionStatusChanged + local tExtensionDataA + put revIDEDeveloperExtensionNoCompile(loadedExtensionGet()) \ + into tExtensionDataA + + local tStatus + put revIDEExtensionProperty(tExtensionDataA["name"], "status") into tStatus + + if tStatus is "installed" then + if revIDEDeveloperExtensionCurrentlyTesting() then + enableFrameItem "test" + disableFrameItem "uninstall" + enableFrameItem "stop testing" + disableFrameItem "install" + else + disableFrameItem "test" + enableFrameItem "uninstall" + disableFrameItem "stop testing" + disableFrameItem "install" + end if + else + enableFrameItem "test" + disableFrameItem "uninstall" + disableFrameItem "stop testing" + enableFrameItem "install" + end if + +end ideExtensionStatusChanged diff --git a/Toolset/palettes/extension manager/revideextensionmanager.livecode b/Toolset/palettes/extension manager/revideextensionmanager.livecode new file mode 100644 index 0000000000..508ceb258c Binary files /dev/null and b/Toolset/palettes/extension manager/revideextensionmanager.livecode differ diff --git a/Toolset/palettes/extension manager/revideextensionmanagerbehavior.livecodescript b/Toolset/palettes/extension manager/revideextensionmanagerbehavior.livecodescript new file mode 100644 index 0000000000..944416e778 --- /dev/null +++ b/Toolset/palettes/extension manager/revideextensionmanagerbehavior.livecodescript @@ -0,0 +1,65 @@ +script "revIDEExtensionManagerBehavior" +on preOpenStack + lock screen + dispatch "setAsBehavior" to revIDEFrameBehavior() with the long id of this me + + set the behavior of card "search" of me to the long id of stack "revIDEExtensionManagerStoreBehavior" + set the behavior of card "list" of me to the long id of stack "revIDEExtensionManagerListBehavior" + set the zoomBox of this stack to false + + clearFrameData + + # Navigation + addFrameItem "widget","header", "navigation", "Widgets", "", "","showList", the long id of me,"widget" + addFrameItem "library","header", "navigation", "Libraries", "", "","showList", the long id of me,"library" + addFrameItem "sample","header", "navigation", "Sample Stacks", "", "","showList", the long id of me,"sample" + addFrameItem "snippet","header", "navigation", "Snippets", "", "","showList", the long id of me,"snippet" + addFrameItem "store","header", "navigation", "Store", "", "","showExtensionStore", the long id of me,"store" + addFrameItem "install", "header", "action", "Install extension", "plus", "","installNew", the long id of me + + set the hilitedTabColor of me to "255,255,255" + set the navigationDisplayStyle of me to "names" + unlock screen +end preOpenStack + +on showList pSection + lock screen + send "showList pSection" to card "list" of this stack + unlock screen +end showList + +command refreshList + lock screen + send "refreshList" to card "list" of this stack + unlock screen +end refreshList + +on showExtensionStore + lock screen + go to card "search" of this stack + unlock screen +end showExtensionStore + +on preferenceChanged pPreference, pValue + revIDESetPreference pPreference, pValue +end preferenceChanged + +on installNew + answer file "Choose an extension to install:" with type "LiveCode Extension|lce|" + if it is not empty then + installExtension it, "", "widget" + end if +end installNew + +on installExtension pExtensionURL, pTypeID, pType + lock screen + showList pType + if pExtensionURL begins with "http" then + // get from extensions store + revIDEExtensionDownloadAndInstall pExtensionURL + else + // get from local .lce file + revIDEExtensionInstall pExtensionURL, pType + end if + unlock screen +end installExtension \ No newline at end of file diff --git a/Toolset/palettes/extension manager/revideextensionmanagerlistbehavior.livecodescript b/Toolset/palettes/extension manager/revideextensionmanagerlistbehavior.livecodescript new file mode 100644 index 0000000000..79a0c3a396 --- /dev/null +++ b/Toolset/palettes/extension manager/revideextensionmanagerlistbehavior.livecodescript @@ -0,0 +1,216 @@ +script "revIDEExtensionManagerListBehavior" +local sSection, sDisplayArray +command setSection pSection + if pSection is empty then + if sSection is empty then + put "widget" into sSection + end if + else + put pSection into sSection + end if +end setSection + +on showList pSection + if the short name of this card of this stack is not "list" then + go card "list" + end if + setSection pSection + refreshList +end showList + +on resizeStack + set the rect of group "extensionList" of me to the contentRect of this stack of me + pass resizeStack +end resizeStack + +on preOpenCard + revIDESubscribe "ideExtensionsChanged" + revIDESubscribe "ideExtensionStatusChanged" + revIDESubscribe "idePreferenceChanged:ideExtensionManager_showInactiveExtensions" + + lock screen + setSection + setUpExtensionList + set the rect of group "extensionList" of me to the contentRect of this stack of me + send "resetView" to group "extensionList" of me + unlock screen +end preOpenCard + +on openCard + lock screen + refreshList + unlock screen +end openCard + +on refreshList + hiliteFrameItem sSection + refreshExtensionList sSection +end refreshList + +on idePreferenceChanged pPreference, pValue + local tValue + + put revIDEGetPreference(pPreference) into tValue + switch pPreference + case "ideExtensionManager_showInactiveExtensions" + refreshExtensionList + break + end switch +end idePreferenceChanged + +on ideExtensionsChanged + refreshExtensionList +end ideExtensionsChanged + +on setUpExtensionList + local theStylesA + + set the behavior of group "extensionList" of card "list" of this stack to revIDEDataViewBehavior() + send "ResetView" to group "extensionList" of card "list" of this stack + + put the long id of group "extensionRow" of card "templates" of this stack into theStylesA["extension"] + + set the viewProp["row style templates"] of group "extensionList" of card "list" of this stack to theStylesA + set the viewProp["hilite color"] of group "extensionList" of card "list" of this stack to ideColorGet("pb_line_selected") + set the viewProp["background color"] of group "extensionList" of card "list" of this stack to empty + + set the viewProp["row color"] of group "extensionList" of card "list" of this stack to revIDEColor("dataView_rowColor") + set the viewProp["alternate row color"] of group "extensionList" of card "list" of this stack to revIDEColor("dataView_rowAlternateColor") + + set the viewProp["fixed row height"] of group "extensionList" of card "list" of this stack to "true" + set the viewProp["row height"] of group "extensionList" of card "list" of this stack to 41 + set the viewProp["cache"] of group "extensionList" of card "list" of this stack to "none" +end setUpExtensionList + +function NumberOfRows + # return the number of rows in the data view + -- return the number of lines in the keys of sDisplayArray + return the number of items in sDisplayArray["visible object keys"] +end NumberOfRows + +command DataForRow pRow, @pDataA, @pTemplateStyle + local theID + # Fill in pDataA with the values for this pRow and specify the row style. + put item pRow of sDisplayArray["visible object keys"] into theId + put sDisplayArray["objects"][theId] into pDataA + put "extension" into pTemplateStyle +end DataForRow + +function CacheKeyForRow pRow + # [OPTIONAL unless data is a tree] Specify a unique key for pRow. + # Only define if you will be reordering rows in the dataview + # By default the row number is used to cache the control for a row. + # If you will be reordering rows in your dataview then you need to provide + # a unique value for the cache key by defining this function and returning a value. + # A database id can work nicely. + local theID + put item pRow of sDisplayArray["visible object keys"] into theId + return sDisplayArray["objects"][theId]["name"] +end CacheKeyForRow + +on refreshExtensionList + local tExtensionArray, tVisibleRows, tShowInactive + local tIndex, tFilteredArray + + ## Check preference for showing inactive + put revIDEGetPreference("ideExtensionManager_showInactiveExtensions") into tShowInactive + if tShowInactive is empty or tShowInactive is not among the items of "true,false" then + put "true" into tShowInactive + revIDESetPreference "ideExtensionManager_showInactiveExtensions",true + end if + + if sSection is empty then + setSection + end if + + # AL-2015-03-20: [[ Bug 15048 ]] Pass type to revIDEExtensions + put revIDEExtensions(sSection) into tExtensionArray + + # AL-2015-05-26: [[ Bug 14561 ]] Order extensions alphabetically + local tExtensionList + put the keys of tExtensionArray into tExtensionList + sort tExtensionList by tExtensionArray[each]["title"] + + ## Filter the list + repeat for each line tExtension in tExtensionList + if tExtensionArray[tExtension]["type"] = sSection then + add 1 to tIndex + put tExtensionArray[tExtension] into tFilteredArray[tIndex] + end if + end repeat + + put the keys of tFilteredArray into tVisibleRows + replace return with comma in tVisibleRows + sort items of tVisibleRows ascending numeric + + ## Filter based on type + put tFilteredArray into sDisplayArray["objects"] + put tVisibleRows into sDisplayArray["visible object keys"] + + send "renderView" to group "extensionList" of me +end refreshExtensionList + +on refreshExtensionListStatus + send "renderView" to group "extensionList" of me +end refreshExtensionListStatus + +command uninstallExtension pTypeID + revIDEExtensionUninstall pTypeID +end uninstallExtension + +command unloadExtension pTypeID + revIDEExtensionUnload pTypeID +end unloadExtension + +command loadExtension pTypeID + revIDEExtensionReload pTypeID +end loadExtension + +command toggleUserVisibility pTypeID + revIDEExtensionToggleUserVisibility pTypeID + refreshList +end toggleUserVisibility + +command toggleLoadOnStartup pTypeID + revIDEExtensionToggleLoadOnStartup pTypeID + refreshList +end toggleLoadOnStartup + +on updateExtension pExtensionIdentifier, pLatestVersion + ## Don't do anything for now becuase renaming a zip doesn't work + ## manifest/enumerated files don't get updated when you do this + revIDEUpdateExtension pExtensionIdentifier, pLatestVersion +end updateExtension + +on cancelExtensionInstall pExtensionIdentifier + revIDECancelInstallExtension pExtensionIdentifier +end cancelExtensionInstall + +on launchExtensionSampleStack pExtensionId + local tSourceFolder, tSourceFile + put revIDEExtensionProperty(pExtensionId, "install_path") into tSourceFolder + put revIDEExtensionProperty(pExtensionId, "source_file") into tSourceFile + revIDEExtensionLaunchSampleStack tSourceFolder & slash & tSourceFile +end launchExtensionSampleStack + +on showExtensionSnippet pExtensionId + local tSourceFolder, tSourceFile + put revIDEExtensionProperty(pExtensionId, "install_path") into tSourceFolder + put revIDEExtensionProperty(pExtensionId, "source_file") into tSourceFile + revIDEExtensionShowSnippet tSourceFolder & slash & tSourceFile +end showExtensionSnippet + +on ideExtensionStatusChanged pStatus + local tElement, tRow, tIdentifier, tStatus, tProgress + put item 1 of pStatus into tIdentifier + put item 2 of pStatus into tStatus + put item 3 of pStatus into tProgress + + dispatch function "TreeFindElement" to group "extensionList" of me with sDisplayArray,"name",tIdentifier + put the result into tElement + + put tElement["row"] into tRow + put tStatus into sDisplayArray["objects"][tRow]["status"] + put tProgress into sDisplayArray["objects"][tRow]["progress"] + refreshExtensionListStatus +end ideExtensionStatusChanged diff --git a/Toolset/palettes/extension manager/revideextensionmanagerrowbehavior.livecodescript b/Toolset/palettes/extension manager/revideextensionmanagerrowbehavior.livecodescript new file mode 100644 index 0000000000..f0a385137f --- /dev/null +++ b/Toolset/palettes/extension manager/revideextensionmanagerrowbehavior.livecodescript @@ -0,0 +1,326 @@ +script "revIDEExtensionManagerRowBehavior" +on FillInData pDataA, pRow + # Map pDataA values to physical controls... + local tVersion + + set the cTypeID of me to pDataA["name"] + + local tLabel, tAuthor + if pDataA["title"] is not empty then put pDataA["title"] into tLabel + else if pDataA["label"] is not empty then put pDataA["label"] into tLabel + else if pDataA["display name"] is not empty then put pDataA["display name"] into tLabel + else put pDataA["name"] into tLabel + + if pDataA["author"] is not empty then put pDataA["author"] into tAuthor + if tAuthor is empty then put "Unknown Author" into tAuthor + + put tLabel & return & tAuthor into field "description" of me + + local tShowSVGIcon, tSVGIcon, tDefaultName + put true into tShowSVGIcon + revIDEExtensionIconFromType pDataA["type"], pDataA["name"], tDefaultName, tSVGIcon + if tSVGIcon is not empty then + set the iconPath of widget "svgicon" of me to pDataA["svgicon"] + else if pDataA["icon"] is not empty then + put false into tShowSVGIcon + set the filename of image "icon" of me to pDataA["icon"] + else + set the iconPresetName of widget "svgicon" of me to tDefaultName + end if + + if tShowSVGIcon then + show widget "svgicon" of me + hide image "icon" of me + else + hide widget "svgicon" of me + show image "icon" of me + end if + + ## Is an update available + hide button "uninstall" of me + hide button "update" of me + + put char -5 to -1 of pDataA["identifier"] into tVersion + if pDataA["status"] is not "uninstalled" then + if pDataA["latest"] is not tVersion then + set the cLatestVersion of me to pDataA["latest"] + end if + end if + + set the cIDE of me to (pDataA["ide"] is true) + + switch pDataA["status"] + case "installed" + hide button "cancel" of me + hide group "installProgress" of me + hide image "Error" of me + hide field "Error Message" of me + break + case "error" + hide button "cancel" of me + hide group "installProgress" of me + show image "Error" of me + put pDataA["name"] && "error" into field "Error Message" of me + set the tooltip of field "Error Message" of me to pDataA["error"] + set the tooltip of image "Error" of me to pDataA["error"] + show field "Error Message" of me + break + case "unloaded" + hide button "cancel" of me + hide group "installProgress" of me + hide image "Error" of me + hide field "Error Message" of me + break + case "uninstalled" + hide button "cancel" of me + hide group "installProgress" of me + hide image "Error" of me + put "Restart required" into field "Error Message" of me + show field "Error Message" of me + break + default + show group "installProgress" of me + put pDataA["status"] into field "installProgressStatus" of me + set the thumbposition of scrollbar "installProgressBar" of me to pDataA["progress"] + hide image "Error" of me + hide field "Error Message" of me + break + end switch + + local tActions + put __MenuActionsForRow(pDataA) into tActions + + set the text of button "extensionActions" of me to tActions + enable widget "actionIcon" of me +end FillInData + +private function __MenuActionsForRow pDataA + local tActions + + if pDataA["status"] is "unloaded" then + put "Load" & return after tActions + if not pDataA["ide"] then + put "Uninstall" & return after tActions + end if + else if pDataA["status"] is "installed" then + if _canLoad(pDataA) then + put "Unload" & return after tActions + end if + if not pDataA["_ide"] and not pDataA["ide"] then + put "Uninstall" & return after tActions + end if + else if pDataA["status"] is "error" then + if not pDataA["ide"] then + put "Remove" & return after tActions + end if + end if + + if pDataA["type"] is "widget" then + local tShow + put "Show in tools palette/|Toggle Visible" & return into tShow + if pDataA["uservisible"] then + put "!c" before tShow + end if + put tShow after tActions + else if pDataA["type"] is "sample" then + put "Open stack" & return after tActions + else if pDataA["type"] is "snippet" then + put "Show snippet" & return after tActions + end if + + if _canLoad(pDataA) then + local tLoadOnStartup + put "Load on startup/|Toggle Load" & return into tLoadOnStartup + if revIDEExtensionGetLoadOnStartup(pDataA["name"]) is not false then + put "!c" before tLoadOnStartup + end if + put tLoadOnStartup after tActions + end if + + put "Show documentation" & return after tActions + + local tSampleList + if pDataA["samples"] is not empty then + put "Sample stacks" & return after tActions + put pDataA["samples"] into tSampleList + repeat for each line tSample in the keys of tSampleList + put tab & tSample & return after tActions + end repeat + if the last char of tActions is return then delete the last char of tActions + set the cSampleStacks of me to pDataA["samples"] + else + put "(Sample stacks" & return after tActions + end if + return tActions +end __MenuActionsForRow + +private function _canLoad pDataA + if pDataA["_ide"] then + return false + end if + switch pDataA["type"] + case "snippet" + case "sample" + return false + end switch + return true +end _canLoad + +on LayoutControl pControlRect + + local tMargin, tPadding, tIconLoc + + # Resize controls/row + put the paletteMargin of me into tMargin + put the palettePadding of me into tPadding + + set the rect of graphic "background" of me to pControlRect + set the width of graphic "border" of me to (item 3 of pControlRect - item 1 of pControlRect) + set the bottomLeft of graphic "border" of me to item 1 of pControlRect, item 4 of pControlRect + put the loc of me into tIconLoc + + set the loc of widget "svgicon" of me to tIconLoc + set the left of widget "svgicon" of me to item 1 of pControlRect + tMargin + set the loc of image "icon" of me to the loc of widget "svgicon" of me + + set the width of field "description" of me to the formattedWidth of field "description" of me + set the height of field "description" of me to the formattedHeight of field "description" of me + set the loc of field "description" of me to the loc of me + set the left of field "description" of me to the right of widget "svgicon" of me + tPadding + + set the textColor of line 1 of field "description" of me to revIDEColor("text_1") + set the textColor of line 2 of field "description" of me to revIDEColor("text_2") + + ## Action Icon + set the loc of widget "ActionIcon" of me to the loc of me + set the right of widget "ActionIcon" of me to item 3 of pControlRect - tMargin + + ## Cancel button + set the loc of button "cancel" of me to the loc of me + set the right of button "cancel" of me to the left of widget "actionIcon" of me - tMargin + + ## Progress Bar + set the width of group "installProgress" of me to (item 3 of pControlRect - the right of field "description" of me - the width of widget "actionIcon" of me - the width of button "cancel" of me - tMargin) + set the loc of group "installProgress" of me to the loc of me + set the right of group "installProgress" of me to the left of widget "ActionIcon" of me - tPadding + + hide button "cancel" of me + + ## Error data + set the loc of image "Error" of me to the loc of me + set the right of image "Error" of me to the left of widget "actionIcon" of me - tPadding + set the width of field "Error Message" of me to (item 3 of pControlRect - the width of widget "ActionIcon" of me) + set the loc of field "Error Message" of me to the loc of me + + if the visible of image "Error" of me then + set the right of field "Error Message" of me to the left of image "Error" of me + else + set the right of field "Error Message" of me to item 3 of pControlRect - tMargin + end if + + -- Don't allow the error field to overspill the description + -- or go past a third of the width + local tLeft + put max(the right of field "description" of me + tPadding, \ + the width of me / 3) into tLeft + if the left of field "Error Message" of me < tLeft then + set the dontWrap of field "Error Message" of me to false + local tWidth + put the right of field "Error Message" of me into tWidth + subtract tLeft from tWidth + set the width of field "Error Message" of me to tWidth + set the height of field "Error Message" of me to the formattedHeight of field "Error Message" of me + set the loc of field "Error Message" of me to the loc of me + set the left of field "Error Message" of me to tLeft + end if + +end LayoutControl + +on mouseUp pMouseButton + if pMouseButton is 1 then + switch the short name of the target + case "cancel" + answer "Are you sure you want to cancel the installation of extension" && the cTypeID of me & "?" with "Cancel" and "Yes" + if it is "Yes" then + cancelExtensionInstall the cTypeID of me + end if + break + case "actionIcon" + popup button "extensionActions" of me + break + end switch + else if pMouseButton is 3 then + popup button "extensionActions" of me + end if +end mouseUp + +on menuPick pAction + local tSample, tSampleStacks + + set the itemDel to "|" + if item 1 of pAction is "Sample Stacks" then + put item 2 of pAction into tSample + delete item 2 of pAction + end if + + local tKind + put the cTypeID of me into tKind + switch pAction + case "Toggle Visible" + toggleUserVisibility tKind + break + case "Toggle Load" + toggleLoadOnStartup tKind + break + case "uninstall" + answer "Are you sure you want to uninstall extension" \ + && tKind & "?" with "Cancel" and "Yes" + if it is "Yes" then + uninstallExtension tKind + end if + break + case "remove" + uninstallExtension tKind + break + case "unload" + unloadExtension tKind + break + case "load" + loadExtension tKind + break + case "update" + answer "Are you sure you want to update extension" \ + && tKind & "?" with "Cancel" and "Yes" + if it is "Yes" then + updateExtension tKind, the cLatestVersion of me + end if + break + case "Sample Stacks" + put the cSampleStacks of me into tSampleStacks + launchExtensionSampleStack tSampleStacks[tSample] + break + case "Show Documentation" + revIDEGoToExtensionAPI tKind + break + case "Open stack" + launchExtensionSampleStack tKind + break + case "Show snippet" + showExtensionSnippet tKind + break + end switch +end menuPick + +on mouseDoubleUp + if not the cIDE of me then + dispatch "browserGoToExtensionPage" to card 2 of this stack with the cTypeID of me + end if +end mouseDoubleUp + +getProp dvRowControl + return the long id of me +end dvRowControl + +setProp dvHilite[pHiliteColor] pBoolean + # Override basic hilite feature... +end dvHilite diff --git a/Toolset/palettes/extension manager/revideextensionmanagerstorebehavior.livecodescript b/Toolset/palettes/extension manager/revideextensionmanagerstorebehavior.livecodescript new file mode 100644 index 0000000000..a6abb96cce --- /dev/null +++ b/Toolset/palettes/extension manager/revideextensionmanagerstorebehavior.livecodescript @@ -0,0 +1,85 @@ +script "revIDEExtensionManagerStoreBehavior" +on preOpenCard + send "resizeStack" to me + browserHide + setStatus "Loading LiveCode extensions store" + set the repeatcount of image "loading" of me to -1 +end preOpenCard + +constant kLoadTimeout = 2 +on openCard + hiliteFrameItem "store" + if the url of widget "browser" of me is empty then + set the userAgent of widget "browser" of me to "LiveCode" + browserGoToExtensionStore + else + nudgeBrowser + end if +end openCard + +on nudgeBrowser + -- Hack to get round bug 18946 + send "browserNavigateComplete" to me in kLoadTimeout seconds +end nudgeBrowser + +on setStatus pStatus + put pStatus into field "status" of me +end setStatus + +on resizeStack + lock screen + local tContentRect, tPadding + put the contentrect of me into tContentRect + put the palettePadding of me into tPadding + set the width of field "status" of me to the width of me + set the loc of field "status" of me to the loc of me + set the loc of image "loading" of me to the loc of me + set the bottom of image "loading" of me to the top of field "status" of me - tPadding + + set the rect of graphic "browser_background" of me to tContentRect + set the rect of widget "browser" of me to tContentRect + + unlock screen + pass resizeStack +end resizeStack + +on browserHide + hide widget "browser" of me +end browserHide + +on browserShow + show widget "browser" of me +end browserShow + +on browserSetURL pURL + lock screen + set the url of widget "browser" of me to pURL + nudgeBrowser + unlock screen +end browserSetURL + +on browserGoToExtensionPage pExtensionTypeID + lock screen + browserSetURL revIDEWebPageURL("extensions") & pExtensionTypeID & slash + go card 2 of this stack + unlock screen +end browserGoToExtensionPage + +on browserGoToExtensionStore + lock screen + browserSetURL revIDEWebPageURL("extensions") + unlock screen +end browserGoToExtensionStore + +on browserDocumentLoadComplete pURL + browserShow +end browserDocumentLoadComplete + +on browserDocumentLoadFailed pURL + browserGoToExtensionStore +end browserDocumentLoadFailed + +on browserNavigateComplete + set the javaScriptHandlers of widget "browser" of me to "installExtension" + browserShow +end browserNavigateComplete diff --git a/Toolset/palettes/inspector/behaviors/revinspectoreditorbehavior.livecodescript b/Toolset/palettes/inspector/behaviors/revinspectoreditorbehavior.livecodescript index 1fd9baa7f0..7e568aea9f 100644 --- a/Toolset/palettes/inspector/behaviors/revinspectoreditorbehavior.livecodescript +++ b/Toolset/palettes/inspector/behaviors/revinspectoreditorbehavior.livecodescript @@ -97,12 +97,10 @@ getProp editorEnabled end editorEnabled local sAllowUpdate -local sLastValue local sValue setProp editorValue[pKey] pValue set the casesensitive to true - if sLastValue is empty or pValue is not sLastValue or sEditorEffective then - put sValue into sLastValue + if sValue is empty or pValue is not sValue or sEditorEffective then if pKey is not empty then put pValue into sValue[pKey] else @@ -121,9 +119,17 @@ getProp editorValue[pKey] end editorValue on updateProperty pForce - if pForce or (sAllowUpdate is true and not sPropertyInfo["read_only"]) then - dispatch "editorValueChanged" with sPropertyInfo["property_name"], sValue, false - put false into sAllowUpdate + if pForce or (sAllowUpdate is true and not sPropertyInfo["read_only"]) then + set the itemdelimiter to ";" + -- Single editors can control multiple properties delimited by ; + if the number of items in sPropertyInfo["property_name"] > 1 then + repeat for each item tProp in sPropertyInfo["property_name"] + dispatch "editorValueChanged" with tProp, sValue[tProp], false + end repeat + else + dispatch "editorValueChanged" with sPropertyInfo["property_name"], sValue, false + end if + put false into sAllowUpdate end if end updateProperty @@ -188,16 +194,29 @@ getProp editorWidth end editorWidth local sPopupData +on editorPopup pClickLoc + +end editorPopup + after editorPopup pClickLoc local tStackName put popupStackName() into tStackName + if tStackName is in the openstacks then + exit editorPopup + end if create invisible stack tStackName - dispatch "setAsBehavior" to stack revIDEPaletteResourcePath("behaviors/revinspectorpopupstackbehavior.livecodescript", the long id of stack "revInspector") with the long id of stack tStackName + dispatch "setAsBehavior" to stack \ + revIDEPaletteResourcePath("behaviors/revinspectorpopupstackbehavior.livecodescript", \ + the long id of stack "revInspector") with the long id of stack tStackName set the frameHidden of stack tStackName to true dispatch "inspectorGenerateGroups" to stack tStackName with sPropertyInfo["popup"] dispatch "inspectorLayoutGroups" to stack tStackName with sPropertyInfo["popup"] dispatch "inspectorFillGroups" to stack tStackName with sPopupData set the editorTarget of stack tStackName to the long id of me + // In LC 9.0 DP-7 you can resize the inspector window, by putting all the contents in a group "inspector" and adding a vScrollbar to the group + // but 'modeless stack X' breaks the vScrollbar of groups, so ensure the popup stack has the correct height before going 'modeless' + set the height of stack tStackName to \ + the formattedHeight of group "inspector" of stack tStackName set the title of stack tStackName to the rowLabel of the owner of me modeless stack tStackName end editorPopup @@ -274,3 +293,52 @@ on editorFinalize dispatch "popupDismissed" to me end if end editorFinalize + +local sExpandVertical +setProp editorExpandVertical pValue + put pValue into sExpandVertical +end editorExpandVertical + +getProp editorExpandVertical + return sExpandVertical +end editorExpandVertical + +on rawKeyDown pKeyNum + -- allow scroll wheel, pgup, & pgdn to scroll the text field + -- bubble up to the parent if at either limit + if the target contains "field" then + local tScrollPosition, tScrollAmount, tScrollMax + put the vScroll of the target into tScrollPosition + put 0 into tScrollAmount + switch pKeyNum + case "65365" + put 45 into tScrollAmount + -- fall through + case "65309" + if tScrollPosition is 0 then pass rawKeyDown + add 5 to tScrollAmount + put max(0, tScrollPosition - tScrollAmount) into tScrollPosition + break + case "65366" + put 45 into tScrollAmount + -- fall through + case "65308" + add 5 to tScrollAmount + put the formattedHeight of the target - \ + the height of the target into tScrollMax + if tScrollPosition is tScrollMax then pass rawKeyDown + put min(tScrollMax, tScrollPosition + tScrollAmount) \ + into tScrollPosition + break + default + pass rawKeyDown + end switch + set the vScroll of the target to tScrollPosition + else + pass rawKeyDown + end if +end rawKeyDown + +after openField + select the text of the target +end openField diff --git a/Toolset/palettes/inspector/behaviors/revinspectorgroupbehavior.livecodescript b/Toolset/palettes/inspector/behaviors/revinspectorgroupbehavior.livecodescript index 90a8ca1e1e..4431b22179 100644 --- a/Toolset/palettes/inspector/behaviors/revinspectorgroupbehavior.livecodescript +++ b/Toolset/palettes/inspector/behaviors/revinspectorgroupbehavior.livecodescript @@ -28,11 +28,15 @@ on propertyRegister pPropertyInfo break end switch + inspectorOpenEditor tEditor + # Create the editor (need to decide if it's a classic editor (clone a group) # or a new widget editor, in which case it's create control. if there is not a stack tEditor then put "com.livecode.pi.string" into tEditor + inspectorOpenEditor tEditor end if + local tEditorBehavior put tEditor & ".behavior" into tEditorBehavior @@ -301,7 +305,7 @@ function expandedToFit pMinMaxA, pSpace return tFixedA end expandedToFit -on rowResize +on rowResize pExpandableExtra lock screen set the lockloc of me to true @@ -342,8 +346,9 @@ on rowResize put the showSubSections of this stack into tSubsections local tGroupLongID, tLastGroupLongID, tHeightOfRow, tCount, tGroupHeight - local tElement, tPropNumber, tLineNumber + local tElement, tPropNumber, tLineNumber, tCanExpand put 1 into tLineNumber + put 0 into tCanExpand repeat for each line tProperty in sOrder add 1 to tPropNumber put sProperties[tProperty] into tElement @@ -397,13 +402,33 @@ on rowResize if tEditorHeight > tHeightOfRow then put tEditorHeight into tHeightOfRow end if + unlock messages + + local tThisCanExpand + put the editorExpandVertical of tGroupLongID into tThisCanExpand + if tThisCanExpand then + add 1 to tCanExpand + if pExpandableExtra > 0 then + lock messages + set the height of tGroupLongID to tEditorHeight + pExpandableExtra + unlock messages + dispatch "editorResize" to tGroupLongID + end if + end if add tWidthsA[tLineNumber][tPropNumber] + tPadding to tLeft add tHeightOfRow to tGroupHeight put tGroupLongID into tLastGroupLongID - unlock messages end repeat + local tHeightDiff + put the height of me - tGroupHeight into tHeightDiff + if pExpandableExtra is empty and tCanExpand > 0 and tHeightDiff > 0 then + local tExpandableExtra, tDummy + put tHeightDiff / tCanExpand into tExpandableExtra + rowResize tExpandableExtra + end if + set the height of me to tGroupHeight set the lockloc of me to false unlock screen @@ -443,3 +468,15 @@ setProp rowEnabled pValue end repeat set the enabled of field "rowlabel" of me to pValue end rowEnabled + +// The group can expand vertically if any of the editors can +function canExpandVertically + local tElement + repeat for each line tProperty in sOrder + put sProperties[tProperty] into tElement + if the editorExpandVertical of group tElement["property"] of me then + return true + end if + end repeat + return false +end canExpandVertically diff --git a/Toolset/palettes/inspector/behaviors/revinspectorpopupstackbehavior.livecodescript b/Toolset/palettes/inspector/behaviors/revinspectorpopupstackbehavior.livecodescript index e01ae4e868..a758fb3d45 100644 --- a/Toolset/palettes/inspector/behaviors/revinspectorpopupstackbehavior.livecodescript +++ b/Toolset/palettes/inspector/behaviors/revinspectorpopupstackbehavior.livecodescript @@ -17,7 +17,12 @@ on preOpenStack set the default of the templatebutton to true create button "OK" - set the topright of button "OK" to the width of me - tMargin, the height of me + // In LC 9.0 DP-7 you can resize the inspector window, by putting all the contents in a group "inspector" + // and adding a vScrollbar to the group + // but 'modeless stack X' breaks the vScrollbar of groups, so ensure the popup stack has the correct + // height before going 'modeless' + set the height of me to the formattedHeight of group "inspector" of me + 2 * tMargin + set the topright of button "OK" to the width of me - tMargin, the height of me set the resizable of me to false set the height of me to the height of me + the height of button "OK" of me + tMargin @@ -28,12 +33,24 @@ end preOpenStack on openStack lock screen lock messages - set the left of me to the right of revIDEStackOfObject(sTarget) + 5 + ensureOnScreen show me unlock messages unlock screen end openStack +on ensureOnScreen + if (the right of revIDEStackOfObject(sTarget) + 5 + the width of me) < item 3 of the screenrect then + set the left of me to the right of revIDEStackOfObject(sTarget) + 5 + else + set the right of me to the left of revIDEStackOfObject(sTarget) - 5 + end if +end ensureOnScreen + +on closeStack + send "popupDismissed" to sTarget in 0 millisecs +end closeStack + on editorValueChanged pProperty, pValue, pLockUpdates try dispatch "valueChanged" to sTarget with pProperty, pValue diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.action.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.action.livecode index 1a501d6ebc..6ed5893eaf 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.action.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.action.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.array.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.array.behavior.livecodescript index 17cff836d9..9512c49f5c 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.array.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.array.behavior.livecodescript @@ -17,11 +17,15 @@ on editorUpdate local tPath put the hilitedElement of widget 1 of me into tPath set the arrayData of widget 1 of me to tValue + set the pathDelimiter of widget 1 of me to numToCodepoint(0) unlock messages updateEditorFields tPath lock messages - set the enabled of field "value" of me to tEnabled - set the enabled of field "key" of me to tEnabled + set the visible of field "value" of me to tEnabled + set the visible of field "key" of me to tEnabled + set the visible of field "value label" of me to tEnabled + set the visible of field "key label" of me to tEnabled + set the readOnly of widget "array" of me to not tEnabled if tEffective is true then set the textcolor of field "value" of me to "150,150,150" set the textcolor of field "key" of me to "150,150,150" @@ -35,6 +39,7 @@ end editorUpdate on updateEditorFields pPath local tValue + set the itemdelimiter to the pathDelimiter of widget 1 of me put the editorValue of me into tValue if pPath is empty then put empty into field "key" of me @@ -96,6 +101,7 @@ end setValue on setArrayDataOnPath pValue, pPath, @xArray local tKey + set the itemdelimiter to the pathDelimiter of widget 1 of me put item 1 of pPath into tKey if the number of items in pPath is 1 then put pValue into xArray[tKey] @@ -107,6 +113,7 @@ end setArrayDataOnPath on setArrayKeyOnPath pKey, pPath, @xArray local tKey + set the itemdelimiter to the pathDelimiter of widget 1 of me put item 1 of pPath into tKey if the number of items in pPath is 1 then local tSubArray @@ -121,6 +128,7 @@ end setArrayKeyOnPath on deleteArrayKeyOnPath pPath, @xArray local tKey + set the itemdelimiter to the pathDelimiter of widget 1 of me put item 1 of pPath into tKey if the number of items in pPath is 1 then delete variable xArray[item 1 of pPath] @@ -132,6 +140,7 @@ end deleteArrayKeyOnPath on addArrayKeyOnPath pPath, @xArray local tKey + set the itemdelimiter to the pathDelimiter of widget 1 of me put item 1 of pPath into tKey if the number of items in pPath is 1 then put "" into xArray[item 1 of pPath] @@ -143,6 +152,7 @@ end addArrayKeyOnPath on fetchArrayDataOnPath pPath, pArray, @rData local tKey + set the itemdelimiter to the pathDelimiter of widget 1 of me put item 1 of pPath into tKey if the number of items in pPath is 1 then if tKey is not among the keys of pArray then @@ -163,6 +173,7 @@ end dataChanged on valueChanged local tPath + set the itemdelimiter to the pathDelimiter of widget 1 of me put the hilitedElement of widget 1 of me into tPath if tPath is empty then # Don't update anthing @@ -177,6 +188,7 @@ end valueChanged on keyChanged lock screen local tPath + set the itemdelimiter to the pathDelimiter of widget 1 of me put the hilitedElement of widget 1 of me into tPath local tArray, tNewKey @@ -210,6 +222,7 @@ end hiliteChanged on updateHIlite local tPath + set the itemdelimiter to the pathDelimiter of widget 1 of me put the hilitedElement of widget 1 of me into tPath # Hilite a newly created key diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.color.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.color.behavior.livecodescript index d91ac682ec..3a635da1a1 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.color.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.color.behavior.livecodescript @@ -15,7 +15,8 @@ on editorUpdate put the editorEffective of me into tEffective lock messages - if the number of items in tValue < 3 then + if tValue is not empty and \ + the number of items in tValue < 3 then put true into sNamedColor put revIDENamedColorToRGB(tValue) into tValue else diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.customprops.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.customprops.behavior.livecodescript index 1a1fa6afe6..499c3b0dc0 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.customprops.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.customprops.behavior.livecodescript @@ -1,16 +1,22 @@ script "com.livecode.pi.customprops.behavior" -local sPropSet, sHilitePath +local sPropSet, sHilitePath, sReselect on editorInitialize put empty into sPropSet + put false into sReselect put the editorLabel of me into field "rowlabel" of me set the rowShowLabel of me to false set the label of button "customPropertySet" of group "Set buttons" of me to "customKeys" set the editorMinWidth of me to 250 set the editorMaxWidth of me to 0 + checkRehilite + set the editorExpandVertical of me to true end editorInitialize -local sDontUpdate +on updateHilitePath pPath + set the hilitedElement of widget 1 of me to pPath +end updateHilitePath + on editorUpdate lock screen local tValue, tEffective, tEnabled @@ -37,16 +43,19 @@ on editorUpdate set the label of button "customPropertySet" of group "Set buttons" of me to sPropSet end if + if arrayKeysAreNumeric(tValue[sPropSet]) then + set the sorttype of widget 1 of me to "numeric" + else + set the sorttype of widget 1 of me to "text" + end if set the arrayData of widget 1 of me to tValue[sPropSet] local tPath put the hilitedElement of widget 1 of me into tPath # Hilite a newly created key if sHilitePath is not empty and sHilitePath is not tPath then # Signals are posted from the widget after the handler has - # executed, so lock messages here doesn't prevent hiliteChanged - - # use a script local to prevent second update. - put true into sDontUpdate - set the hilitedElement of widget 1 of me to sHilitePath + # executed, so we need to delay rehiliting the old path + send "updateHilitePath sHilitePath" to me in 10 millisecs put sHilitePath into tPath end if put empty into sHilitePath @@ -54,12 +63,17 @@ on editorUpdate if tPath is empty then put empty into field "key" of me put empty into field "value" of me + put false into tEnabled else local tKey fetchArrayDataOnPath tPath, tValue[sPropSet], tKey if the result is empty then put tKey into field "value" of me put item -1 of tPath into field "key" of me + if sReselect then + select the text of field "key" of me + put false into sReselect + end if else put empty into field "key" of me put empty into field "value" of me @@ -81,9 +95,10 @@ end editorUpdate constant kControlGap = 5 constant kKeyFieldHeight = 21 constant kLabelFieldHeight = 21 -constant kValueFieldHeight = 63 +constant kValueFieldHeight = 126 constant kLabelSize = 50 constant kSetButtonsHeight = 30 +constant kWidgetHeight = 150 on editorResize lock screen @@ -102,9 +117,16 @@ on editorResize set the lockLoc of group "Set buttons" of me to true send "groupResize kLabelSize, kControlGap" to group "Set buttons" of me + local tTopGroupHeight + put the bottom of group "background" into tTopGroupHeight + # Use all space not taken by other elements for main array display - local tWidgetHeight - put the height of me - (4 * kControlGap + kLabelFieldHeight + kKeyFieldHeight + kValueFieldHeight + kSetButtonsHeight) into tWidgetHeight + local tWidgetHeight, tValueHeight + put kWidgetHeight into tWidgetHeight + put max(the height of this card - ( 6 * kControlGap + kLabelFieldHeight \ + + kKeyFieldHeight + kValueFieldHeight + kSetButtonsHeight \ + + tWidgetHeight + tTopGroupHeight), 0) into tValueHeight + set the height of widget 1 of me to tWidgetHeight set the width of widget 1 of me to the width of me set the left of widget 1 of me to the left of me @@ -126,7 +148,7 @@ on editorResize set the left of field "value label" of me to the left of me set the width of field "value" of me to the width of me - kLabelSize - kControlGap - set the height of field "value" of me to kValueFieldHeight + set the height of field "value" of me to kValueFieldHeight + tValueHeight set the top of field "value" of me to the bottom of field "key" of me + kControlGap set the left of field "value" of me to the right of field "value label" of me + kControlGap @@ -206,34 +228,69 @@ on fetchArrayDataOnPath pPath, pArray, @rData end fetchArrayDataOnPath on dataChanged + checkRehilite setPropSet the arrayData of widget 1 of me end dataChanged on valueChanged local tPath put the hilitedElement of widget 1 of me into tPath - if tPath is empty then + valueChangedOnPath tPath +end valueChanged + +private command valueChangedOnPath pPath + if pPath is empty then # Don't update anthing + exit valueChangedOnPath + end if + local tArray + put the arrayData of widget 1 of me into tArray + + local tValue, tExisting + put field "value" of me into tValue + fetchArrayDataOnPath pPath, tArray, tExisting + + local tChanged + set the caseSensitive to true + if tExisting is an array then + put tValue is not empty into tChanged else - local tArray - put the arrayData of widget 1 of me into tArray - setArrayDataOnPath field "value" of me, tPath, tArray - setPropSet tArray + put tExisting is not tValue into tChanged end if -end valueChanged + + if not tChanged then + exit valueChangedOnPath + end if + setArrayDataOnPath field "value" of me, pPath, tArray + setPropSet tArray +end valueChangedOnPath on keyChanged - lock screen local tPath put the hilitedElement of widget 1 of me into tPath + keyChangedOnPath tPath +end keyChanged + +local sLastHilite +private command keyChangedOnPath pPath + if pPath is empty then + # Don't update anthing + exit keyChangedOnPath + end if - local tArray, tNewKey + local tNewKey put field "key" of me into tNewKey + if tNewKey is item -1 of pPath then + exit keyChangedOnPath + end if + + local tArray put the arrayData of widget 1 of me into tArray - if tPath is not empty then + lock screen + if pPath is not empty then # If there is a hilited element then change it - setArrayKeyOnPath tNewKey, tPath, tArray + setArrayKeyOnPath tNewKey, pPath, tArray else # otherwise add a new key to the current set addArrayKeyOnPath tNewKey, tArray @@ -241,10 +298,14 @@ on keyChanged # Set the new property and hilite the new/changed key setPropSet tArray - put tNewKey into item -1 of tPath - put tPath into sHilitePath + + # Since the key changed, invalidate the last hilite path + put empty into sLastHilite + + put tNewKey into item -1 of pPath + put pPath into sHilitePath unlock screen -end keyChanged +end keyChangedOnPath on propSetRenamed pFrom, pTo local tArray @@ -314,10 +375,34 @@ function revValidSetName pWhich end revValidSetName on hiliteChanged + put true into sReselect + checkRehilite + editorUpdate put empty into sHilitePath - # Prevent setting hilite in update causing additional call to editorUpdate - if not sDontUpdate then - editorUpdate - end if - put false into sDontUpdate end hiliteChanged + +on checkRehilite + # Check to see if the key or value has changed + keyChangedOnPath sLastHilite + valueChangedOnPath sLastHilite + + # Store the existing hilited path + put the hilitedElement of widget "array" of me into sLastHilite + if sLastHilite is not empty then + # If a click caused a new path to be hilited, don't trigger + # a rehilite of the old path + put empty into sHilitePath + end if + + set the disabled of field "value" of me to sLastHilite is empty + set the disabled of field "key" of me to sLastHilite is empty +end checkRehilite + +function arrayKeysAreNumeric pArrayA + local tKey + + repeat for each key tKey in pArrayA + if tKey is not an integer then return false + end repeat + return true +end arrayKeysAreNumeric diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.behavior.livecodescript new file mode 100644 index 0000000000..a3755db103 --- /dev/null +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.behavior.livecodescript @@ -0,0 +1,159 @@ +script "com.livecode.pi.dimension.behavior" +local sMax, sMin + +constant kFieldWidth = 100 +constant CONTROL_PADDING = 5 +constant kEffectiveTextColor = "100,100,100" +constant kConflictedFieldColor = "193,201,215" + +on editorInitialize + lock screen + lock messages + local tStep + put editorPropertyGet("max") into sMax + put editorPropertyGet("min") into sMin + put editorPropertyGet("step") into tStep + + set the lineinc of scrollbar "twiddle" of me to tStep + set the visible of scrollbar "twiddle" of me to true + + unlock messages + unlock screen + set the editorMaxWidth of me to 0 +end editorInitialize + +getProp editorMinWidth + local tWidth + add kFieldWidth to tWidth + add the width of scrollbar "twiddle" of me to tWidth + add CONTROL_PADDING to tWidth + return tWidth +end editorMinWidth + +on editorUpdate + lock screen + local tValue, tEffective, tEnabled, tConflicted + put the editorValue of me into tValue + put the editorEnabled of me into tEnabled + put the editorEffective of me into tEffective + put the editorConflicted of me into tConflicted + + if tValue is "fit" then + exit editorUpdate + end if + + lock messages + set the thumbposition of scrollbar "twiddle" of me to tValue + 0 + set the enabled of field 1 of me to tEnabled + if tEffective is true then + if the focusedobject is not the long ID of field 1 of me then + put tValue + 0 into field 1 of me + end if + set the textstyle["italic"] of field 1 of me to true + set the textcolor of field 1 of me to kEffectiveTextColor + else + set the textstyle of field 1 of me to empty + set the textcolor of field 1 of me to empty + put tValue + 0 into field 1 of me + end if + if tConflicted then + set the backcolor of field 1 of me to kConflictedFieldColor + put empty into field 1 of me + else + set the backcolor of field 1 of me to empty + end if + unlock messages + unlock screen +end editorUpdate + +on editorResize + lock screen + lock messages + + local tLeft, tTop, tBottom + put the left of me into tLeft + put the top of me into tTop + put tTop + the formattedheight of field 1 of me into tBottom + + local tFieldWidth + put max(the formattedWidth of field 1 of me, kFieldWidth) into tFieldWidth + set the rect of field 1 of me to tLeft,tTop,tLeft+tFieldWidth,tBottom + add tFieldWidth to tLeft + + add CONTROL_PADDING to tLeft + # The twiddle control is visible + set the rect of scrollbar "twiddle" of me to tLeft,tTop,tLeft + the width of scrollbar "twiddle" of me, tBottom + add the width of scrollbar "twiddle" of me to tLeft + + add CONTROL_PADDING to tLeft + set the topleft of button "fit" of me to tLeft, tTop + unlock messages + unlock screen +end editorResize + +on openField + if the editorEffective of me is true then + lock messages + put empty into field 1 of me + # Ensure that when the user types the text is the default color rather than the effective grey + set the textcolor of field 1 of me to empty + unlock messages + end if +end openField + +on exitField + editorUpdate +end exitField + +on returnInField + valueChanged +end returnInField + +on enterInField + valueChanged +end enterInField + +on closeField + valueChanged +end closeField + +on scrollbarLineInc + if the visible of scrollbar "twiddle" of me is false then + exit scrollbarLineInc + end if + scrollbarValueChanged field 1 of me - the lineInc of scrollbar "twiddle" of me +end scrollbarLineInc + +on scrollbarLineDec + if the visible of scrollbar "twiddle" of me is false then + exit scrollbarLineDec + end if + scrollbarValueChanged field 1 of me + the lineInc of scrollbar "twiddle" of me +end scrollbarLineDec + +on scrollbarValueChanged pValue + if pValue is field 1 of me then + exit scrollbarValueChanged + end if + + if sMin is a number and pValue < sMin then + put sMin into field 1 of me + else if sMax is a number and pValue > sMax then + put sMax into field 1 of me + else + put pValue into field 1 of me + end if + valueChanged +end scrollbarValueChanged + +on mouseUp + if the short name of the target is "fit" then + set the editorValue of me to "fit" + updateProperty + end if +end mouseUp + +on valueChanged + set the editorValue of me to field 1 of me + updateProperty +end valueChanged diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.livecode new file mode 100644 index 0000000000..fee0fe8dc1 Binary files /dev/null and b/Toolset/palettes/inspector/editors/com.livecode.pi.dimension.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.editorlist.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.editorlist.behavior.livecodescript index e489dfe822..e4718bda8c 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.editorlist.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.editorlist.behavior.livecodescript @@ -1,4 +1,4 @@ -script "com.livecode.pi.editorList.behavior" +script "com.livecode.pi.editorList.behavior" with behavior "revInspectorEditorBehavior" local sNumChildren constant kComponentSpacing = 6 @@ -117,7 +117,15 @@ on editorValueChanged repeat with x =1 to sNumChildren put the editorValue of group ("editor" & x) of me into tValueArray[x] end repeat - combine tValueArray with tDelimiter - set the editorValue of me to tValueArray + + // TODO: Use 'combine tValueArray with tDelimiter' once we add sorting option to combine + // See bug 9344 + local tList + repeat for each element tElement in tValueArray + put tElement & tDelimiter after tList + end repeat + delete char -1 of tList + set the editorValue of me to tList + dispatch "updateProperty" end editorValueChanged diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.geometry.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.geometry.behavior.livecodescript index aedb7564c3..a1582ae783 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.geometry.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.geometry.behavior.livecodescript @@ -135,16 +135,6 @@ on editorUpdate set the hilite of button "horizontal scrollbar" of group "Clipping" of group "Geometry Options" of me to (tValue["showHScroll"] is true) set the hilite of button "vertical scrollbar" of group "Clipping" of group "Geometry Options" of me to (tValue["showVScroll"] is true) - repeat for each item tItem in "minWidth,maxWidth,minHeight,maxHeight" - if fld tItem of group "minmax" of group "Geometry Options" of me is not empty then - put true into tValue["limit"] - exit repeat - end if - end repeat - - set the hilite of button "limitsize" of group "Geometry Options" of me to (tValue["limit"] is true) - set the enabled of grp "minMax" of group "Geometry Options" of me to (tValue["limit"] is true) - if sMode is "scaling" then put tValue["minWidth"] into fld "minWidth" of group "minmax" of group "Geometry Options" of me put tValue["maxWidth"] into fld "maxWidth" of group "minmax" of group "Geometry Options" of me @@ -156,6 +146,16 @@ on editorUpdate put tValue["minTop"] into fld "minHeight" of group "minmax" of group "Geometry Options" of me put tValue["maxBottom"] into fld "maxHeight" of group "minmax" of group "Geometry Options" of me end if + + repeat for each item tItem in "minWidth,maxWidth,minHeight,maxHeight" + if fld tItem of group "minmax" of group "Geometry Options" of me is not empty then + put true into tValue["limit"] + exit repeat + end if + end repeat + + set the hilite of button "limitsize" of group "Geometry Options" of me to (tValue["limit"] is true) + set the enabled of grp "minMax" of group "Geometry Options" of me to (tValue["limit"] is true) unlock messages unlock screen end editorUpdate @@ -220,7 +220,7 @@ on mouseUp pButton answer warning "Really remove all Geometry from the selected object?" with "No" or "Yes" if it is "Yes" then put empty into tValue - setValue tValue + setValue tValue, "all" end if break default @@ -334,7 +334,7 @@ on mouseDown pButton default break end switch - setValue tValue + setValue tValue, tKey end if end if end mouseDown @@ -402,8 +402,8 @@ on menuPick pWhich --proportional scaling put false into tValue[tKey & "Absolute"] end if - put tSide into tValue[tKey & "ObjectSide"] - put pWhich into tValue[tKey & "ObjectRef"] + put oppositeSide(tSide) into tValue[tKey & "ObjectSide"] + put pWhich into tValue[tKey & "ObjectRef"] # Adjust menu text local tMenuText @@ -419,7 +419,7 @@ on menuPick pWhich put the cCurrentButton of me into tButtonTemp set the cObjectList of tButtonTemp to tMenuText - setValue tValue + setValue tValue, tKey else if the short name of the target is "Squiggle Type" then lock screen local tScale @@ -440,7 +440,33 @@ on menuPick pWhich end if end menuPick -on setValue pValue +on setValue pValue, pKey + --if move is set, it takes precidence over scale + --need to be sure opposite set is not enabled + local tTurnOffGeometries + switch pKey + case "scaleLeft" + case "scaleRight" + put "moveH" into tTurnOffGeometries + break + case "scaleTop" + case "scaleBottom" + put "moveV" into tTurnOffGeometries + break + case "moveH" + put "scaleLeft,scaleRight" into tTurnOffGeometries + break + case "moveV" + put "scaleTop,scaleBottom" into tTurnOffGeometries + break + case "all" + put "moveH,moveV,scaleLeft,scaleRight,scaleTop,scaleBottom" into tTurnOffGeometries + break + end switch + repeat for each item tItem in tTurnOffGeometries + put false into pValue[tItem] + end repeat + local tValue put the editorValue["geometry"] of me into tValue union pValue with tValue recursively @@ -488,3 +514,21 @@ on closeField setValue tValue end closeField + +function oppositeSide pSide + switch pSide + case "Top" + return "Bottom" + break + case "Bottom" + return "Top" + break + case "Right" + return "Left" + break + case "Left" + default + return "Right" + break + end switch +end oppositeSide diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.behavior.livecodescript index 11d1dc9f4e..c468944088 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.behavior.livecodescript @@ -119,7 +119,9 @@ on editorResize local tRect put the rect of me into tRect - set the rect of graphic 1 of me to the right of button 1 of me, item 2 of tRect + 2, item 3 of tRect - 5, item 4 of tRect - 5 + set the rect of graphic 1 of me to the right of button 1 of me, \ + the top of button 1 of me + 3, item 3 of tRect - 5, \ + the bottom of button 1 of me - 3 unlock messages unlock screen end editorResize diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.livecode index 806dc1ca70..11dfcc41dd 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.graphiceffect.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.number.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.number.livecode index e54f5f6b4a..d1ebe27caf 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.number.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.number.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.pattern.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.pattern.livecode index 77b1c64a10..9ca37f62d7 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.pattern.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.pattern.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.point.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.point.livecode index 2b8c53cb82..d73fe9bb9f 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.point.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.point.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.script.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.script.behavior.livecodescript index 4cae6421ea..4aad7ceeb4 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.script.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.script.behavior.livecodescript @@ -2,8 +2,8 @@ on editorInitialize set the editorMinWidth of me to 230 set the editorMaxWidth of me to 0 - disable button "edit script" of me - disable button "inspect object" of me + disable button "edit script" of me + disable button "inspect object" of me end editorInitialize on editorUpdate @@ -127,12 +127,91 @@ on editorGoToObject end editorGoToObject on popupMenu - set the text of button "Menu" of me to "Select Behavior" & return & revIDEObjectSelectionMenu("", "button,stack") + local tMenu, tObject + + put the cSelectedObjects of this stack into tObject + + put "Select Behavior" & return & revIDEObjectSelectionMenu("", "button,stack") into tMenu + put return & "Create behavior from script only stack/|create behavior" after tMenu + put return & tab & "Create stack with empty script/|create empty behavior" & return after tMenu + if word 1 to -1 of the script of tObject is empty then + put "(" after tMenu + end if + put tab & "Create stack using existing control script/|create behavior from script" after tMenu + set the text of button "Menu" of me to tMenu popup button "Menu" of me at the mouseLoc end popupMenu on menuPick pObject - set the itemdelimiter to "|" - put the last item of pObject into field 1 of me - valueChanged + local tAction + + set the itemdelimiter to "|" + put item -1 of pObject into tAction + + switch tAction + case "create empty behavior" + case "create behavior from script" + local tError, tSuggestedName, tStackName + local tTargetObject, tFilename, tStack + + put the cSelectedObjects of this stack into tTargetObject + put revIDEStackOfObject(tTargetObject) into tStack + put the effective filename of tStack into tDefaultFilename + + ask revIDELocalise("Please enter a name for the script only stack") with the short name of tTargetObject && "Behavior" + if it is empty then exit menuPick + put it into tStackName + put word 1 to -1 of line 1 of tStackName into tStackName + replace quote with "'" in tStackName + + if tDefaultFilename is not empty then + set the itemDelimiter to "/" + put tStackName & ".livecodescript" into the last item of tDefaultFilename + else + put tStackName & ".livecodescript" into tDefaultFilename + end if + + ask file revIDELocalise("Please specify a location for the script only stack") with tDefaultFilename + if it is empty then exit menuPick + put it into tFilename + + lock messages + create invisible stack tStackName + close stack tStackName + set the filename of stack tStackName to tFilename + set the scriptOnly of stack tStackName to true + + if tAction is "create behavior from script" then + set the script of stack tStackName to the script of tTargetObject + end if + + save stack tStackName + put the result into tError + unlock messages + + if tError is empty then + local tStackFiles + + set the behavior of tTargetObject to the long id of stack tStackName + put the stackFiles of tStack into tStackFiles + put tStackName & "," & tFilename into line (the number of lines of tStackFiles + 1) of tStackFiles + revIDESetStackFilesProperty tStack, empty, tStackFiles + + if tAction is "create behavior from script" then + set the script of tTargetObject to empty + else + edit script of stack tStackName + end if + end if + + if tError is not empty then + answer error tError + end if + break + + default + set the itemdelimiter to "|" + put the last item of pObject into field 1 of me + valueChanged + end switch end menuPick diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.script.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.script.livecode index 9f3e2aea41..95326b1c98 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.script.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.script.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.set.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.set.behavior.livecodescript index 0785dd4d4a..8182811e77 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.set.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.set.behavior.livecodescript @@ -51,7 +51,10 @@ on editorResize lock screen lock messages set the lockLoc of me to true - set the rect of field 1 of me to the rect of me + local tRect + put the rect of me into tRect + put item 2 of tRect + the formattedHeight of field 1 of me into item 4 of tRect + set the rect of field 1 of me to tRect unlock messages unlock screen end editorResize diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.stackfiles.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.stackfiles.behavior.livecodescript index d2ce442ad8..b5d21743ab 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.stackfiles.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.stackfiles.behavior.livecodescript @@ -10,6 +10,15 @@ on editorInitialize put "stack" into sSort put the editorLabel of me into field "label" of me set the rowShowLabel of me to false + + if the editorEnabled of me then + show button "Remove key" of me + show button "New key" of me + else + hide button "Remove key" of me + hide button "New key" of me + end if + set the editorExpandVertical of me to true end editorInitialize on editorUpdate @@ -32,6 +41,14 @@ on editorResize local tRect, tFieldRect put the rect of me into tRect + local tManualHeight, tManualGroupHeight + put getManualHeight() into tManualHeight + if tManualHeight is not empty then + put tManualHeight - the height of group "background" - kControlGap - 2 into tManualGroupHeight + set the height of me to tManualGroupHeight + set the height of the owner of me to tManualGroupHeight + end if + put tRect into tFieldRect put item 2 of tFieldRect + kButtonHeight + kColumnHeaderHeight + kControlGap into item 2 of tFieldRect set the effective rect of field "stackFilesField" of me to tFieldRect @@ -72,25 +89,75 @@ on mouseUp revIDEAnswerFile "stack" # Get the path of to the file - local tStackFilePath - put the result into tStackFilePath + local tStackFilePaths + put the result into tStackFilePaths - if tStackFilePath is not empty then - local tEditorValue, tNewLine - put the short name of stack tStackFilePath & comma & tStackFilePath into tNewLine - put the editorValue of me into tEditorValue - if tEditorValue is empty then - put tNewLine into tEditorValue - else - put return & tNewLine after tEditorValue - end if - set the editorValue of me to tEditorValue - updateProperty + if tStackFilePaths is not empty AND tStackFilePaths is not "cancel" then + addStacks tStackFilePaths end if break end switch end mouseUp + +on dragEnter + if the short name of the target is "stackFilesField" then + if the dragData["files"] is not empty then + local tExtensions, tFile + + set the wholematches to true + put revIDEAcceptedTypes("stack") into tExtensions + repeat for each line tFile in the dragData["files"] + if fileExtension(tFile) is among the items of tExtensions then + set the dragAction to "copy" + exit repeat + end if + end repeat + end if + else + pass dragEnter + end if +end dragEnter + + +on dragDrop + if the short name of the target is "stackFilesField" then + addStacks the dragData["files"] + else + pass dragDrop + end if +end dragDrop + + +private command addStacks pStackFilePaths + local tEditorValue, tNewLine + + put the editorValue of me into tEditorValue + + repeat for each line tStackFilePath in pStackFilePaths + put the short name of stack tStackFilePath & comma & tStackFilePath into tNewLine + if tEditorValue is empty then + put tNewLine into tEditorValue + else + put return & tNewLine after tEditorValue + end if + end repeat + set the editorValue of me to tEditorValue + updateProperty +end addStacks + +private function fileExtension pFilename + set the itemDelimiter to "/" + put the last item of pFilename into pFilename + set the itemDelimiter to "." + if the number of items of pFilename > 1 then + return the last item of pFilename + else + return empty + end if +end fileExtension + + on valueChanged local tValue put field "stackFilesField" into tValue diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.string.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.string.livecode index a79efa70ca..96916f1734 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.string.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.string.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.svgicon.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.svgicon.behavior.livecodescript index 20f3dddb27..1421a0f6d6 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.svgicon.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.svgicon.behavior.livecodescript @@ -1,4 +1,4 @@ -script "com.livecode.pi.svgicon.behavior" +script "com.livecode.pi.svgicon.behavior" with behavior "revInspectorEditorBehavior" on editorInitialize set the editorMinWidth of me to 0 set the editorMaxWidth of me to 0 @@ -30,11 +30,13 @@ end editorResize on mouseUp local tValue put the editorValue of me into tValue - local tProperties - put tValue into tProperties["selectedIcon"] - popup widget "com.livecode.widget.iconpicker" at the clickLoc with properties tProperties - if the result is empty and it is not tValue then - set the iconPresetName of widget 1 of me to it + set the dialogData to tValue + + set the behavior of stack "com.livecode.pi.svgiconfilter" to the long id of stack "com.livecode.pi.svgiconfilter.behavior" + modal stack "com.livecode.pi.svgiconfilter" at the clickLoc + + if the dialogData is not tValue then + set the iconPresetName of widget 1 of me to the dialogData end if valueChanged end mouseUp diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.behavior.livecodescript new file mode 100755 index 0000000000..dcb1c808cf --- /dev/null +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.behavior.livecodescript @@ -0,0 +1,70 @@ +script "com.livecode.pi.svgiconfilter.behavior" +on preOpenStack + set the text of field "FilterText" to "Search" + set the filterString of widget "iconList" of me to empty + set the showSelectedElement of widget "iconList" of me to false + set the iconSize of widget "iconList" of me to 55 + set the showNames of widget "iconList" of me to true + set the selectedIcon of widget "iconList" of me to the dialogData + + set the behavior of me to the long id of stack "com.livecode.pi.svgiconfilter.behavior" + focus on nothing +end preOpenStack + +on mouseUp + if the short name of the target is "iconList" then + if the selectedIcon of widget "iconList" of me is not empty then + set the dialogData to the selectedIcon of widget "iconList" of me + end if + close this stack + end if +end mouseUp + +on openField + if the short name of the target is "FilterText" then + if field "FilterText" is "Search" then + set the text of field "FilterText" to empty + end if + end if +end openField + +on enterField + if the short name of the target is "FilterText" then + if field "FilterText" is "Search" then + set the text of field "FilterText" to empty + end if + end if +end enterField + +on closeField + if the short name of the target is "FilterText" then + if field "FilterText" is empty then + set the text of field "FilterText" to "Search" + end if + end if +end closeField + +on exitField + if the short name of the target is "FilterText" then + if field "FilterText" is empty then + set the text of field "FilterText" to "Search" + end if + end if +end exitField + +on textChanged + local tFilterText + + if the short name of the target is "FilterText" then + put field "FilterText" into tFilterText + set the filterString of widget "iconList" of me to tFilterText + end if +end textChanged + +on returnInField + // Do nothing +end returnInField + +on escapeKey + close this stack +end escapeKey diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.livecode new file mode 100755 index 0000000000..739fae06da Binary files /dev/null and b/Toolset/palettes/inspector/editors/com.livecode.pi.svgiconfilter.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.text.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.text.behavior.livecodescript index 08e24b45f7..c60b2b70ad 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.text.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.text.behavior.livecodescript @@ -6,6 +6,16 @@ on editorInitialize set the itemdelimiter to "." put item -1 of the editorProperty["editor"] of me into sTextType + + local tText, tOptions + put the editorOptions of me into tOptions + set the itemdelimiter to "|" + repeat for each line tLine in tOptions + local tProperty,tValue + put item 1 of tLine into tProperty + put item 2 of tLine into tValue + set the tProperty of field 1 of me to tValue + end repeat end editorInitialize on editorUpdate diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.behavior.livecodescript index 5e5c695935..b2576f42e6 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.behavior.livecodescript @@ -4,19 +4,16 @@ on editorInitialize set the editorMaxWidth of me to 90 end editorInitialize -local sConflictLock on editorUpdate lock screen local tValue, tEffective, tEnabled, tConflicted put the editorValue of me into tValue put the editorEnabled of me into tEnabled put the editorEffective of me into tEffective - put the editorConflicted of me into sConflictLock + put the editorConflicted of me into tConflicted lock messages - if sConflictLock then + if tConflicted then set the hilitedItemNames of widget 1 of me to empty - wait 0 millisecs with messages - put false into sConflictLock else set the hilitedItemNames of widget 1 of me to tValue end if @@ -36,14 +33,14 @@ on editorResize end editorResize on hiliteChanged - if not sConflictLock then - valueChanged - end if + valueChanged end hiliteChanged on valueChanged - local tNames + local tNames, tValue put the hilitedItemNames of widget 1 of me into tNames - set the editorValue of me to tNames + if the editorValue of me is not tNames then + set the editorValue of me to tNames + end if updateProperty end valueChanged diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.livecode b/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.livecode index 6ecf4ffdb9..270a2b6e85 100644 Binary files a/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.livecode and b/Toolset/palettes/inspector/editors/com.livecode.pi.textalign.livecode differ diff --git a/Toolset/palettes/inspector/editors/com.livecode.pi.textcontents.behavior.livecodescript b/Toolset/palettes/inspector/editors/com.livecode.pi.textcontents.behavior.livecodescript index 2c5d91fc83..0e2c8190f0 100644 --- a/Toolset/palettes/inspector/editors/com.livecode.pi.textcontents.behavior.livecodescript +++ b/Toolset/palettes/inspector/editors/com.livecode.pi.textcontents.behavior.livecodescript @@ -9,6 +9,12 @@ on editorInitialize set the itemdelimiter to "." put item -1 of the editorProperty["editor"] of me into sTextType + + set the toolTip of button "wrap text" of me to "wrap text" + set the toolTip of button "show grid" of me to "show grid" + set the toolTip of button "import" of me to "import file" + + set the editorExpandVertical of me to true end editorInitialize on editorUpdate @@ -35,10 +41,18 @@ on editorUpdate end editorUpdate constant kControlGap = 6 -constant kMaxHeight = 500 +constant kMaxHeight = 800 on editorResize lock screen lock messages + local tManualHeight, tManualGroupHeight + put getManualHeight() into tManualHeight + if tManualHeight is not empty then + put tManualHeight - the height of group "controls" of me - kControlGap - 1 - the height of group "background" into tManualGroupHeight + set the height of me to tManualGroupHeight + set the height of the owner of me to tManualGroupHeight + end if + set the topleft of field "rowlabel" of me to the topleft of me set the topright of group "controls" of me to the topright of me local tRect @@ -46,14 +60,21 @@ on editorResize put item 2 of tRect + the height of group "controls" of me + kControlGap into item 2 of tRect local tHeight - put the formattedHeight of field "htmltext" of me into tHeight - put max(tHeight, item 4 of tRect - item 2 of tRect) into tHeight + if tManualHeight is not empty then + put tManualGroupHeight - kControlGap into tHeight + else + put the formattedHeight of field "htmltext" of me into tHeight + put max(tHeight, item 4 of tRect - item 2 of tRect) into tHeight + end if + put min(tHeight, kMaxHeight) into tHeight put item 2 of tRect + tHeight into item 4 of tRect set the rect of field "htmltext" of me to tRect unlock messages set the editorHeight of me to tHeight + kControlGap + the height of group "controls" of me + + set the editorExpandVertical of me to (the height of me < kMaxHeight) unlock screen end editorResize @@ -95,11 +116,18 @@ on mouseUp case "show grid" local tGrid put not the hilite of the target into tGrid + set the hilite of the target to tGrid set the hGrid of fld "HtmlText" to tGrid set the vGrid of fld "HtmlText" to tGrid - set the tabStops of fld "HtmlText" to 150 - set the dontWrap of fld "HtmlText" to tGrid - set the hScrollbar of fld "HtmlText" to tGrid + if tGrid then + set the tabStops of fld "HtmlText" to 150 + set the dontWrap of fld "HtmlText" to tGrid + set the hScrollbar of fld "HtmlText" to tGrid + else + set the tabStops of fld "HtmlText" to 75 + set the dontWrap of fld "HtmlText" to not the hilite of button "wrap text" + set the hScrollbar of fld "HtmlText" to not the hilite of button "wrap text" + end if break case "import" local tFile diff --git a/Toolset/palettes/inspector/revinspector.livecodescript b/Toolset/palettes/inspector/revinspector.livecodescript index d04eb25062..9d8ea9d34e 100644 --- a/Toolset/palettes/inspector/revinspector.livecodescript +++ b/Toolset/palettes/inspector/revinspector.livecodescript @@ -11,6 +11,7 @@ on inspectorMessagesRegister revIDESubscribe "ideInspectObjects" revIDESubscribe "ideCloseStack" revIDESubscribe "ideNameChanged" + revIDESubscribe "ideMainstackChanged" end inspectorMessagesRegister on inspectorMessagesDeRegister @@ -20,6 +21,7 @@ on inspectorMessagesDeRegister revIDEUnsubscribe "ideNewStack" revIDEUnsubscribe "ideCloseStack" revIDEUnsubscribe "ideNameChanged" + revIDEUnsubscribe "ideMainstackChanged" end inspectorMessagesDeRegister on inspectorCloseAll @@ -85,10 +87,7 @@ on ideInspectObjects pObjects local tNewInspectorName put sInspectorMax + 1 into tIndex put inspectorStackName(tIndex) into tNewInspectorName - set the _ideoverride of stack "revInspectorTemplate" to true - clone invisible stack "revInspectorTemplate" - set the name of it to tNewInspectorName - + inspectorCloneTemplate tNewInspectorName put tNewInspectorName into tTargetInspector addInspectorToList tIndex end if @@ -103,6 +102,13 @@ on ideInspectObjects pObjects unlock screen end ideInspectObjects +private command inspectorCloneTemplate pNewName + set the _ideoverride of stack "revInspectorTemplate" to true + clone invisible stack "revInspectorTemplate" + set the cIDETransient of it to true + set the name of it to pNewName +end inspectorCloneTemplate + function inspectorStackName pIndex return kPropertyInspectorPrefix && pIndex end inspectorStackName @@ -158,10 +164,39 @@ on ideCloseStack ideSelectedObjectChanged end ideCloseStack -on ideNameChanged +on stackNameChanged pOldName, pNewLongID + lock screen + local tStackName + repeat for each key tKey in inspectorList() + put kPropertyInspectorPrefix && tKey into tStackName + if the cLocked of stack tStackName is true and the mode of stack tStackName is not 0 then + local tCurObj + put the cSelectedObjects of stack tStackName into tCurObj + if tCurObj contains ("stack" && quote & pOldName & quote) then + replace ("stack" && quote & pOldName & quote) with pNewLongID in tCurObj + set the cLocked of stack tStackName to false + set the cSelectedObjects of stack tStackName to tCurObj + set the cLocked of stack tStackName to true + end if + end if + end repeat + unlock screen +end stackNameChanged + +on ideNameChanged pOldName, pNewName, pNewLongID + # If a stack name changed, we need to check locked inspectors for + # long id changes + if word 1 of pNewLongID is "stack" then + stackNameChanged pOldName, pNewLongID + end if + ideSelectedObjectChanged end ideNameChanged +on ideMainstackChanged + ideSelectedObjectChanged +end ideMainstackChanged + # Sent by the IDE when the selection changed on ideSelectedObjectChanged local tObjects diff --git a/Toolset/palettes/inspector/revinspectortemplate.livecodescript b/Toolset/palettes/inspector/revinspectortemplate.livecodescript index 435575fc3f..84d8bfc882 100644 --- a/Toolset/palettes/inspector/revinspectortemplate.livecodescript +++ b/Toolset/palettes/inspector/revinspectortemplate.livecodescript @@ -8,6 +8,7 @@ on preOpenStack put ideObjectTypesFromObjectList(sSelectedObjects) into sObjectTypes revIDESubscribe "idePropertyChanged",sSelectedObjects inspectorTitleUpdate + inspectorSetLabelsPreference # Set the inspector behaviour dispatch "setAsBehavior" to revIDEInspectorBehavior() with the long id of me @@ -30,6 +31,8 @@ on closeStack ## Unsubscribe from all messages revIDEUnsubscribe "idePreferenceChanged:idePropertyInspector_labels" + set the cSelectedObjects of me to empty + # Unlock put false into sInspectorLock end closeStack @@ -119,7 +122,15 @@ on lockInspector end if end lockInspector +local sPropertyChangedMsg + on idePropertyChanged + cancel sPropertyChangedMsg + send "__IdePropertyChanged" to me in 200 milliseconds + put the result into sPropertyChangedMsg +end idePropertyChanged + +on __IdePropertyChanged lock screen # Check if the object 'types' have been changed via PI local tNewTypes @@ -132,7 +143,7 @@ on idePropertyChanged inspectorTitleUpdate end if unlock screen -end idePropertyChanged +end __IdePropertyChanged on inspectorTreeMenuDisplay local tObjects, tStack, tDefaultStack @@ -236,18 +247,21 @@ on editorStoreValue pProperty, pValue end editorStoreValue on idePreferenceChanged pPreference - local tValue - put revIDEGetPreference(pPreference) into tValue switch pPreference case "idePropertyInspector_labels" - global gRevLanguageNames - put tValue into gRevLanguageNames - set the cLanguageNames of cd 1 of stack "revPreferences" to tValue + inspectorSetLabelsPreference inspectorChanged break end switch end idePreferenceChanged +command inspectorSetLabelsPreference + local tValue + put revIDEGetPreference("idePropertyInspector_labels") into tValue + global gRevLanguageNames + put tValue into gRevLanguageNames + set the cLanguageNames of cd 1 of stack "revPreferences" to tValue +end inspectorSetLabelsPreference # Sent by the IDE when a property has changed on revIDEPropertyChanged @@ -291,3 +305,40 @@ end inspectorPropLabelsPrefChanged getProp showMultiPropLabels return false end showMultiPropLabels + +on rawKeyDown pKeyNum + switch pKeyNum + case "65360" + ## home + if the target contains "field" then pass rawKeyDown + set the vScroll of group "inspector" of me to 0 + break + case "65367" + ## end + if the target contains "field" then pass rawKeyDown + set the vScroll of group "inspector" of me to \ + the formattedHeight of group "inspector" of me - the height of group "inspector" of me + break + case "65365" + set the vScroll of group "inspector" of me to \ + max(0, the vScroll of group "inspector" of me - 50) + break + case "65366" + set the vScroll of group "inspector" of me to \ + min(the formattedHeight of group "inspector" of me - the height of group "inspector" of me, \ + the vScroll of group "inspector" of me + 50) + break + case "65309" + set the vScroll of group "inspector" of me to \ + max(0, the vScroll of group "inspector" of me - 5) + break + case "65308" + set the vScroll of group "inspector" of me to \ + min(the formattedHeight of group "inspector" of me - the height of group "inspector" of me, \ + the vScroll of group "inspector" of me + 5) + break + default + pass rawKeyDown + end switch +end rawKeyDown + diff --git a/Toolset/palettes/menubar/revmenubar.livecodescript b/Toolset/palettes/menubar/revmenubar.livecodescript index dffe19ade1..a4119e211a 100644 --- a/Toolset/palettes/menubar/revmenubar.livecodescript +++ b/Toolset/palettes/menubar/revmenubar.livecodescript @@ -15,6 +15,7 @@ on preOpenStack revMenubarBuildMenus updateMenubarPreference layoutMenu + revIDEPositionPalette the short name of me # Since the menubar is topleveled on Linux and Windows, set the cantModify to true # to prevent users being able to alter the menubar stack. set the cantModify of me to true @@ -144,6 +145,7 @@ end setupTextMenu # need to be added here. private function revMenubarEscapeStackNameForMenu pName replace "!" with "\!" in pName + replace "&" with "\&" in pName if the platform is "MacOS" then replace "/" with "\/" in pName replace "(" with "\(" in pName @@ -171,7 +173,7 @@ private on setupWindowMenu repeat for each line tStack in tWindows if there is not a stack tStack then next repeat put the short name of tStack into tStackName - if tStackName begins with "revNewScriptEditor" or tStackName is "revDictionary" or tStackName is "revResourceCenter" then + if revIDEStackIsIDEWindow(tStackName) then put the title of tStack into tStackName end if @@ -192,6 +194,7 @@ end setupWindowMenu /* Generates the menu for the recent files */ +constant kClearRecentFiles = "ClearTheRecentFileList" function revMenuBarRecentFiles # Get the recent file data local tRecentFiles @@ -206,7 +209,12 @@ function revMenuBarRecentFiles put return & tab & revMenubarEscapeStackNameForMenu(tRecentFiles[x]["label"]) & "/|" & tRecentFiles[x]["filename"] after tMenu end if end repeat - + + if tMenu is not empty then + put return & tab & "-" after tMenu + put return & tab & "Clear Recent Files" & "/|" & kClearRecentFiles after tMenu + end if + return tMenu end revMenuBarRecentFiles @@ -216,6 +224,9 @@ on moveStack put revIDEStackScreenRect(the short name of this stack, true) into tScreenRect set the topLeft of this stack to item 1 to 2 of tScreenRect end if + revIDESetPaletteRectPreference the short name of me + ideSetWindowBoundingRect + pass moveStack end moveStack @@ -225,10 +236,7 @@ on setMenuProperties local tTitle set the itemDelimiter to "-" - put "LiveCode" into tTitle - if revLicenseType() is "community" then - put space & "Community" after tTitle - end if + put "LiveCode" && revEnvironmentEditionProperty("name") into tTitle if item 1 of the version ends with ".0" then put space & char 1 to -3 of item 1 of the version after tTitle else @@ -263,11 +271,11 @@ on setMenuProperties end setMenuProperties on ideSelectedObjectChanged - layoutMenu + updateButtonState end ideSelectedObjectChanged on ideActiveStacksChanged - layoutMenu + updateButtonState end ideActiveStacksChanged on ideTutorialProgressChanged @@ -282,15 +290,9 @@ on idePreferenceChanged pPreference case "cToolbarIcons" lock screen show me - local tAlterBounding - if abs(item 2 of the windowBoundingRect - the bottom of me) < 10 then - put true into tAlterBounding - end if updateMenubarPreference layoutMenu - if tAlterBounding then - set the windowBoundingRect to item 1 of the windowBoundingRect,the bottom of me + 25, item 3 to 4 of the windowBoundingRect - end if + ideSetWindowBoundingRect unlock screen break end switch @@ -410,6 +412,18 @@ on generateMenubarUI set the hilitedIcon of the templatebutton to 0 set the disabledIcon of the templatebutton to 0 + generateTutorialGroup + generateUpgradeGroup + + reset the templategraphic + reset the templatebutton + reset the templateimage + reset the templatefield + + unlock messages +end generateMenubarUI + +private command generateTutorialGroup if there is a group "tutorial" of me then delete group "tutorial" of me end if @@ -445,14 +459,35 @@ on generateMenubarUI set the traversalOn of it to false hide group "tutorial" of me +end generateTutorialGroup + +private command generateUpgradeGroup + if there is a group "upgrade" of me then + delete group "upgrade" of me + end if - reset the templategraphic - reset the templatebutton - reset the templateimage - reset the templatefield + create group "upgrade" + set the margins of it to 0 - unlock messages -end generateMenubarUI + create graphic "bg" in group "upgrade" of me + set the opaque of it to true + set the style of it to "roundRect" + set the lineSize of it to 0 + + local tUpgradeEdition + put revEnvironmentEditionProperty("upgrade_edition") into tUpgradeEdition + set the backcolor of it to revEnvironmentEditionProperty("color", tUpgradeEdition) + set the roundRadius of it to 8 + + create field "label" in group "upgrade" of me + set the margins of it to 4 + set the traversalOn of it to false + set the text of it to "Upgrade Options" + set the textStyle["bold"] of it to true + set the textColor of it to "white" + + hide group "upgrade" of me +end generateUpgradeGroup on generateMenuGroup lock messages @@ -533,6 +568,8 @@ constant kDividerWidth = 2 constant kDividerHeight = 41 constant kMenuBarHeight = 26 constant kMenuBarTop = 3 +constant kUpgradeButtonMarginVertical = 8 +constant kUpgradeButtonMarginHorizontal = 15 on layoutMenu lock screen lock messages @@ -571,16 +608,18 @@ on layoutMenu end if end repeat - local tTutorial + local tTutorial, tLabelWidth put revIDETutorialInProgress() into tTutorial if tTutorial is not empty then + hide group "upgrade" of me + add kPadding/2 to tLeft show group "tutorial" of me show tLastDivide set the text of field "label" of group "tutorial" of me to tTutorial["lesson"] set the width of field "label" of group "tutorial" of me to 1000 set the height of field "label" of group "tutorial" of me to the formattedHeight of field "label" of group "tutorial" of me - local tLabelWidth + put the formattedwidth of field "label" of group "tutorial" of me into tLabelWidth set the width of field "label" of group "tutorial" of me to tLabelWidth set the topleft of field "label" of group "tutorial" of me to 0, 0 @@ -604,9 +643,30 @@ on layoutMenu set the left of group "tutorial" of me to tLeft add the width of group "tutorial" of me + kPadding to tLeft + else if ideShouldShowUpgradeOptions() then + hide group "tutorial" of me + + add kPadding/2 to tLeft + show group "upgrade" of me + show tLastDivide + + put the height of me into tHeight + + local tMenuBarHeight = 0 + if the platform is not "MacOS" then + subtract kMenuBarHeight from tHeight + put kMenuBarHeight into tMenuBarHeight + end if + + set the topLeft of group "upgrade" of me to \ + tLeft, \ + tMenuBarHeight + (tHeight - the height of group "upgrade" of me) / 2 + + add the width of group "upgrade" of me + kPadding to tLeft else hide tLastDivide hide group "tutorial" of me + hide group "upgrade" of me end if set the width of me to tLeft @@ -688,6 +748,38 @@ on updateMenubarPreference end if end if + set the width of field "label" of group "upgrade" of me to 1000 + set the height of field "label" of group "upgrade" of me to the formattedHeight of field "label" of group "upgrade" of me + local tLabelWidth + put the formattedwidth of field "label" of group "upgrade" of me into tLabelWidth + set the width of field "label" of group "upgrade" of me to tLabelWidth + set the loc of field "label" of group "upgrade" of me to 0,0 + + if tShowIcons is false then + set the visible of graphic "bg" of group "upgrade" of me to false + set the textColor of field "label" of group "upgrade" of me to "black" + else + set the visible of graphic "bg" of group "upgrade" of me to true + set the textColor of field "label" of group "upgrade" of me to "white" + + local tHeight + put the height of me - kPadding into tHeight + + if the platform is not "MacOS" then + subtract kMenuBarHeight from tHeight + end if + + local tRect + put the rect of field "label" of group "upgrade" of me into tRect + put item 1 of tRect - kUpgradeButtonMarginHorizontal, \ + -tHeight div 2, \ + item 3 of tRect + kUpgradeButtonMarginHorizontal, \ + tHeight div 2 into tRect + + set the rect of graphic "bg" of group "upgrade" of me to tRect + end if + set the rect of group "upgrade" of me to the formattedRect of group "upgrade" of me + set the topleft of me to tTopLeft unlock messages unlock screen @@ -932,6 +1024,12 @@ on mouseUp else if tTarget is "skip" then revIDETutorialSkipToNextSkipPoint end if + else if the short name of the owner of the target is "upgrade" then + local tStartCenterClassic + put revIDEGetPreference("StartCenterClassic") into tStartCenterClassic + revIDESetPreference "StartCenterClassic", true + ideShowUpgradeOptions + revIDESetPreference "StartCenterClassic", tStartCenterClassic else if the short name of the owner of the target is "toolbar" and the target begins with "button" then revMenubarMenuButtonClicked the short name of the target setButtonReleased the long id of the target @@ -1019,7 +1117,7 @@ on highlightObject pObject else if pObject is "tutorial" then // HIghlight tutorial progress group end if - layoutMenu + updateButtonState end highlightObject on revMenubarMenuButtonClicked pWhich @@ -1288,13 +1386,13 @@ private function revMenubarFileMenu pContext put "&Open Stack.../O" & return after tFile if revMenuBarRecentFiles() is not empty then - put "Open Recent File" & return after tFile + put "Open Recent File" & return after tFile put revMenuBarRecentFiles() & return after tFile else - put "(Open Recent File" & return after tFile + put "(Open Recent File" & return after tFile end if - put enableMenuItem("&Close/W", the mode of the topStack <= 3) & return after tFile + put enableMenuItem("&Close/W", the mode of the topStack <= 3 and the short name of the topstack is not "revMenubar") & return after tFile put enableMenuItem("Close and Remove From Memor&y", tCanSaveStack) & return after tFile put "-" & return after tFile @@ -1640,11 +1738,44 @@ private function revMenubarObjectMenu pContext put "-" & return after tObject + local tCanRelayer = true + local tCanMoveBack = true + local tCanMoveForward = true + if pContext["objectsSelected"] then + local tSelectedObjects + put the selectedObjects into tSelectedObjects + + local tOwner + put the long owner of (line 1 of tSelectedObjects) into tOwner + + local tNumSelected + put the number of lines of (tSelectedObjects) into tNumSelected + if tNumSelected is the number of controls of tOwner then + put false into tCanRelayer + end if + + if tCanRelayer then + local tID + repeat for each line tID in tSelectedObjects + if the long owner of tID is not tOwner then + put false into tCanRelayer + exit repeat + end if + if the layer of tID is the layer of tOwner + 1 then + put false into tCanMoveBack + end if + if the layer of tID is the layer of tOwner + the number of controls of tOwner then + put false into tCanMoveForward + end if + end repeat + end if + end if + ### Send to back, Move Backward, Move Forward and Bring to Front - put enableMenuItem("&Send to Back", pContext["objectsSelected"]) & return after tObject - put enableMenuItem("Move Backward/[", pContext["objectsSelected"]) & return after tObject - put enableMenuItem("Move For&ward/]", pContext["objectsSelected"]) & return after tObject - put enableMenuItem("Bring to &Front", pContext["objectsSelected"]) & return after tObject + put enableMenuItem("&Send to Back", pContext["objectsSelected"] and tCanRelayer and tCanMoveBack) & return after tObject + put enableMenuItem("Move Backward/[", pContext["objectsSelected"] and tCanRelayer and tCanMoveBack) & return after tObject + put enableMenuItem("Move For&ward/]", pContext["objectsSelected"] and tCanRelayer and tCanMoveForward) & return after tObject + put enableMenuItem("Bring to &Front", pContext["objectsSelected"] and tCanRelayer and tCanMoveForward) & return after tObject return modifyMenu("Object", tObject) end revMenubarObjectMenu @@ -1763,6 +1894,7 @@ private function revMenubarHelpMenu pContext # AL-2015-07-10: Temporarily remove welcome screen option from help menu //put "Welcome Screen/|Welcome" & return after tHelp put "Start Center/|Start Center" & return after tHelp + put "User Guide" & return after tHelp put "Dictionary (API)/|Dictionary" & return after tHelp put "-" & return after tHelp @@ -1773,7 +1905,6 @@ private function revMenubarHelpMenu pContext put "Beginners Guide" & return after tHelp put "All Guides" & return after tHelp put "Tutorials" & return after tHelp - put "User Guide" & return after tHelp put "-" & return after tHelp put "Forums" & return after tHelp put "Technical Questions" & return after tHelp @@ -1826,7 +1957,13 @@ end revMenubarViewMenu private function revMenubarDevelopmentMenu pContext global gREVSuppressErrors, gREVSuppressMessages + + local tIsUserTarget + put not revIDEStackIsIDEStack(the topstack) into tIsUserTarget + local tDevelopment + put "Object Library" & return after tDevelopment + put "Image Library" & return after tDevelopment put "Plugins" & return after tDevelopment if sPluginMenuText is not empty then put sPluginMenuText & return after tDevelopment @@ -1836,6 +1973,18 @@ private function revMenubarDevelopmentMenu pContext put "-" & return after tDevelopment put revMenubarSimulatorSubmenu() after tDevelopment put "-" & return after tDevelopment + + if revEnvironmentEditionProperty("script_profiler") then + local tProfiler + put the long id of stack "com.livecode.library.scriptprofiler" into tProfiler + if tProfiler is among the lines of the backScripts then + put enableMenuItem("Start Profiling Scripts", tIsUserTarget) & return after tDevelopment + else + put enableMenuItem("Stop Profiling Scripts...", tIsUserTarget) & return after tDevelopment + end if + put "-" & return after tDevelopment + end if + put toggleMenuItem("Script Debug Mode", revDebuggerEnabled()) & return after tDevelopment put"Clear All Breakpoints" & return after tDevelopment put "Message Watcher" & return after tDevelopment @@ -1932,6 +2081,8 @@ function revMenubarStackContextMenu pStack, pIndent local tText put tIndent & "Edit Script" & return after tText + put tIndent & enableMenuItem("Edit Behavior Script", \ + exists(the behavior of stack pStack)) & return after tText put tIndent & "Property Inspector" & return after tText put tIndent & "-" & return after tText put tIndent & "Stack Mode" & return after tText @@ -1961,6 +2112,18 @@ function revMenubarStackContextMenu pStack, pIndent put tIndent & "Standalone Application Settings..." & return after tText put tIndent & "Save As Standalone Application..." & return after tText put tIndent & "-" & return after tText + + if there is a stack "com.livecode.library.scriptprofiler" then + local tProfiler + put the long id of stack "com.livecode.library.scriptprofiler" into tProfiler + if tProfiler is among the lines of the backScripts then + put tIndent & "Start Profiling Scripts" & return after tText + else + put tIndent & "Stop Profiling Scripts..." & return after tText + end if + put tIndent & "-" & return after tText + end if + put revMenubarSendContextMenu(pStack, pIndent) after tText put revMenubarAdditionalContextMenu(pIndent) after tText @@ -1977,7 +2140,7 @@ function revMenuBarCardContextMenu pCard, pIndent put revIDEStackOfObject(pCard) into tTargetStack local tText - put revMenuBarStandardContextMenu(pIndent) & return into tText + put revMenuBarStandardContextMenu(pCard, pIndent) & return into tText put tIndent & "-" & return after tText put tIndent & enableMenuItem("Paste Objects", the clipboard is "objects" and the mode of stack tTargetStack is 1) & return after tText put tIndent & "-" & return after tText @@ -1996,7 +2159,7 @@ function revMenuBarObjectContextMenu pExtraText, pObject, pIndent, pSelectable end repeat local tText - put revMenuBarStandardContextMenu(pIndent, pSelectable) & return into tText + put revMenuBarStandardContextMenu(pObject, pIndent, pSelectable) & return into tText repeat for each line tLine in pExtraText put tIndent & tLine & return after tText end repeat @@ -2006,7 +2169,7 @@ function revMenuBarObjectContextMenu pExtraText, pObject, pIndent, pSelectable return tText end revMenuBarObjectContextMenu -function revMenuBarStandardContextMenu pIndent, pSelectable +function revMenuBarStandardContextMenu pObject, pIndent, pSelectable local tIndent repeat pIndent put tab after tIndent @@ -2014,6 +2177,8 @@ function revMenuBarStandardContextMenu pIndent, pSelectable local tText put tIndent & "Edit Script" & return after tText + put tIndent & enableMenuItem("Edit Behavior Script", \ + exists(the behavior of pObject)) & return after tText put tIndent & "Property Inspector" & return after tText put tIndent & "-" & return after tText put tIndent & enableMenuItem("Cut", pSelectable) & return after tText @@ -2209,27 +2374,6 @@ end markMenuItem ################################################################################ -command revMenuBarUpdateRecentPaths - revIDECleanRecentPaths - - local tRecentPathsMenu - put revIDEGetRecentPathsAsMenu() into tRecentPathsMenu - - local tFileButtonText - put the text of button "File" of group "revMenuBar" of me into tFileButtonText - - local tStart - set the wholeMatches to true - put lineOffset("Open Recent File", tFileButtonText) + 1 into tStart - set the wholeMatches to false - - local tEnd - put lineOffset("&Close/W", tFileButtonText) - 1 into tEnd - put tRecentPathsMenu into line tStart to tEnd of tFileButtonText - set the text of button "File" of group "revMenuBar" of me to tFileButtonText - -end revMenuBarUpdateRecentPaths - # OK-2007-05-03: Bug 4833. # Parameters # pObject : reference to the object to list handlers for @@ -2306,7 +2450,6 @@ end revListMenuHandlers on unIconifyStack global gREVBackDropRestore, gREVRestore - if gREVRestore["windowBoundingRect"] is empty then pass unIconifyStack set cursor to watch lock messages set the iconic of stack "revMenubar" to false @@ -2410,6 +2553,9 @@ on revMenubarContextMenuPickTarget pWhich, pTarget case "Edit Script" revIDEEditScriptOfObjects pTarget break + case "Edit Behavior Script" + revIDEEditScriptOfObjects the behavior of pTarget + break case "Property Inspector" revIDEOpenInspectorForObjects pTarget break @@ -2466,6 +2612,9 @@ on revMenubarContextMenuPickTarget pWhich, pTarget case "Paste Text" revIDEActionPasteTextIntoField pTarget break + case "Lock Text" + revIDEToggleLockTextOfField pTarget + break case "Can Receive Keyboard Focus" revIDEToggleTraversalOnOfField pTarget break @@ -2519,6 +2668,12 @@ on revMenubarContextMenuPickTarget pWhich, pTarget case "Save As Standalone Application..." revIDESaveAsStandalone tTargetStack break + case "Start Profiling Scripts" + scriptprofilerStartProfiler the short name of tTargetStack + break + case "Stop Profiling Scripts..." + scriptprofilerStopProfiler + break ######## MULTI OBJECT SPECIFIC ######### case "Align" revIDEAlignControls pTarget, item 2 of pWhich @@ -2609,7 +2764,14 @@ on revMenubarFileMenuPick pWhich end if break case "Open Recent File" - revIDEOpenStack item 2 of pWhich + local tRecentStack + put item 2 of pWhich into tRecentStack + if tRecentStack is kClearRecentFiles then + revIDESetPreference "cRecentStackPaths", empty + ideMessageSend "ideRecentFilesChanged" + else + revIDEOpenStack tRecentStack + end if break case "Import As Control" put item 2 of pWhich into tType @@ -2921,6 +3083,18 @@ on revMenubarDevelopmentMenuPick pWhich case "Simulator Version" revIDESetTestTarget item 2 of pWhich break + case "Object Library" + go cd 1 of stack "revImageLibrary" as modeless + lock messages + set the menuHistory of btn "tabs" of stack "RevImageLibrary" to 1 + unlock messages + break + case "Image Library" + go cd 2 of stack "revImageLibrary" as modeless + lock messages + set the menuHistory of btn "tabs" of stack "RevImageLibrary" to 2 + unlock messages + break case "Plugins" local tPicked set the itemDel to "|" @@ -2935,6 +3109,12 @@ on revMenubarDevelopmentMenuPick pWhich break end switch break + case "Start Profiling Scripts" + scriptprofilerStartProfiler the short name of the topStack + break + case "Stop Profiling Scripts..." + scriptprofilerStopProfiler + break end switch end revMenubarDevelopmentMenuPick diff --git a/Toolset/palettes/message box/behaviors/revmessageboxbehavior.livecodescript b/Toolset/palettes/message box/behaviors/revmessageboxbehavior.livecodescript index f108e38486..53fbcdfc4b 100644 --- a/Toolset/palettes/message box/behaviors/revmessageboxbehavior.livecodescript +++ b/Toolset/palettes/message box/behaviors/revmessageboxbehavior.livecodescript @@ -7,6 +7,8 @@ constant kHistoryMax = 200 constant kHalfMessageFieldHeight = 12.5 constant kExternalErrorCode = 0 +local sLastMsg + on setAsBehavior pTarget set the behavior of pTarget to the long id of this me setBehaviors @@ -66,16 +68,17 @@ on openStack hiliteFrameItem "single line" showCard "Single Line" - lock messages - set the revMessageBoxRedirect to the long id of me - unlock messages - --if there is a stack currently being debugged then the debug mode is true, if no stack is currently being debugged then the debug mode is false - if the traceStack is not empty - then revIDESetPreference "IDEDebugMode",true - else revIDESetPreference "IDEDebugMode",false revIDESetActiveStack + local tIntelligence + put revIDEGetPreference("ideMessageBox_intelligenceobject") into tIntelligence + if tIntelligence is empty then + put "selectedObject" into tIntelligence + end if + revIDESetPreference "ideMessageBox_intelligenceobject", "selectedObject" + revIDEUpdateIntelligenceObject + revIDESubscribe "idePreferenceChanged:cShowRevolutionStacks" revIDESubscribe "idePreferenceChanged:revPaletteFrameSize" revIDESubscribe "idePreferenceChanged:cScriptEditor,editor,backgroundcolor" @@ -86,8 +89,6 @@ on openStack if revIDEGetPreference("revPaletteFrameSize") is empty then revIDESetPreference "revPaletteFrameSize", "small" - revIDEUpdateIntelligenceObject - local tMinHeight put 4*kHalfMessageFieldHeight + the headerHeight of me + the footerHeight of me into tMinHeight @@ -101,6 +102,38 @@ on openStack unlock screen end openStack +on ideMsgChanged pTarget, pHandler, pLine, pMsg + lock messages + lock screen + + if the mode of me is 0 then + go stack (the short name of me) + end if + + local tField + if the short name of this card of me is "Multiple Lines" then + put the long id of field "results" of card "Multiple Lines" of me into tField + else + put the long id of field "results" of card "Single Line" of me into tField + end if + + set the text of tField to pMsg + + -- PM-2015-06-26: [[ Bug 15478 ]] Make msg box to auto scroll + local tLines, tHeight + put the number of lines of the text of tField into tLines + put the effective textHeight of tField into tHeight + set the vScroll of tField to tLines * tHeight + + put pTarget into sLastMsg["target"] + put pHandler into sLastMsg["handler"] + put pLine into sLastMsg["line"] + + unlock screen + unlock messages +end ideMsgChanged + + --PM-2016-04-29: [[ Bug 17534 ]] Make sure the correct handler is called on moveMsgBoxStack --set the position of the stack as a custom property so when it is reopened/different card is selected it remains in the same location @@ -182,21 +215,13 @@ end unlockDefaultStack command showOutputSource --opens the script at the line that has put something into the message box - local tLastMessageSource, tEditorStack, tObject, tLineNumber - - put the revmessageboxlastobject into tLastMessageSource - if tLastMessageSource is empty then exit showOutputSource - - set the itemdel to comma - if item 4 of tLastMessageSource is not empty - then put item 4 of tLastMessageSource into tObject - else put item 1 of tLastMessageSource into tObject - - edit script of tObject - put revScriptEditor(tObject) into tEditorStack - put (item 3 of tLastMessageSource) into tLineNumber + global gRevDevelopment + if not exists(sLastMsg["target"]) or \ + revIDEObjectIsOnIDEStack(sLastMsg["target"]) and not gRevDevelopment then + exit showOutputSource + end if - send "revSEGoExecutionPoint tObject, tLineNumber, true" to stack tEditorStack in 0 millisecs + edit script of sLastMsg["target"] at sLastMsg["line"] end showOutputSource on removeSelected @@ -272,7 +297,11 @@ end removeAll on revIDEFocusOnMessageBox pChar if lSelectedCard is among the items of "Single Line,Multiple Lines" then - focus on field "message" of card lSelectedCard + if there is a field "message" of card lSelectedCard then + focus on field "message" of card lSelectedCard + else + focus on field "script" of card lSelectedCard + end if put pChar into the selectedChunk end if end revIDEFocusOnMessageBox @@ -441,6 +470,8 @@ on idePreferenceChanged pPreference, pValue case "cScriptEditor,editor,fontSize" __UpdateMessageFont break + default + break end switch unlock screen end idePreferenceChanged @@ -450,10 +481,10 @@ private command __UpdateMessageFont put revIDEGetPreference("cScriptEditor,editor,font") into tFont put revIDEGetPreference("cScriptEditor,editor,fontSize") into tSize - set the textFont of field "message" of card "Multiple Lines" of me to tFont + set the textFont of field "script" of card "Multiple Lines" of me to tFont set the textFont of field "message" of card "Single Line" of me to tFont set the textFont of field "auto complete" of card "Single Line" of me to tFont - set the textSize of field "message" of card "Multiple Lines" of me to tSize + set the textSize of field "script" of card "Multiple Lines" of me to tSize set the textSize of field "message" of card "Single Line" of me to tSize set the textSize of field "auto complete" of card "Single Line" of me to tSize @@ -464,7 +495,7 @@ private command __UpdateMessageColors local tColor put revIDEGetPreference("cScriptEditor,editor,backgroundcolor") into tColor set the backgroundColor of field "auto complete" of card "Single Line" of me to tColor - set the backgroundColor of field "message" of card "Multiple Lines" of me to tColor + set the backgroundColor of field "script" of card "Multiple Lines" of me to tColor end __UpdateMessageColors command positionOpenStacksButton @@ -584,40 +615,31 @@ command ideMessageBoxExecuteScript pScript try do "put the long id of the" && tIntelligencePref && "into tIntelligenceObject" catch tError - put empty into tIntelligenceObject + put the long id of stack tDefaultStack into tIntelligenceObject end try - local tDebugMode - put revIDEGetPreference("IDEDebugMode") into tDebugMode local tValidScript - ideExecuteScript pScript, tDefaultStack, tIntelligenceObject, tDebugMode, tValidScript + ideExecuteScript pScript, tIntelligenceObject, ideIsDebugging(), tValidScript if the result is not empty then - put ideMessageBoxFormatErrorForDisplay(the result) into field "results" of card lSelectedCard of me + put ideMessageBoxFormatErrorForDisplay(the result, "compile error") into field "results" of card lSelectedCard of me + else if it is not empty then + put ideMessageBoxFormatErrorForDisplay(it, "execution error") into field "results" of card lSelectedCard of me end if return tValidScript end ideMessageBoxExecuteScript -function ideMessageBoxFormatErrorForDisplay pErrorTrace +function ideMessageBoxFormatErrorForDisplay pErrorTrace, pErrorType --if there is an error, then this will be formatted and then displayed in the results field ##GH : will need localising - local tError, tErrorDisplay, tLineNum, tErrorType - put line 1 of pErrorTrace into tErrorType - put line 2 of pErrorTrace into tError + local tError, tErrorDisplay, tLineNum + put line 1 of pErrorTrace into tError if item 1 of tError is a number and item 1 of tError >= 0 then - if tErrorType is "compile error" then - put item 1 of line 1 of tError into tLineNum - --put revIDELocalisedConstructedString("Script compile error:" & cr & "Error description: [error]",revIDELookupError("compilation",tLineNum)) into tErrorDisplay - put "Script compile error:" & cr & "Error description:" && revIDELookupError("compilation", tLineNum) into tErrorDisplay + if pErrorType is "compile error" then + put "Script compile error:" & cr & "Error description:" && revIDELookupError("compilation", pErrorTrace) into tErrorDisplay else - if item 1 of tError is kExternalErrorCode then - --put revIDELocalisedConstructedString("External execution error:" & cr & "Error description: [error]",item 4 to -1 of line 1 of tError) into tErrorDisplay - put "External execution error:" & cr & "Error description:" && item 4 to -1 of line 1 of tError into tErrorDisplay - else - --put revIDELocalisedConstructedString("Message execution error:" & cr & "Error description: [error]" & cr & "Hint: [hint]",revIDELookupError("execution", (item 1 of line 1 of tError)),item 4 to -1 of line 1 of tError) into tErrorDisplay - put "Message execution error:" & cr & "Error description:" && revIDELookupError("execution", (item 1 of line 1 of tError)) & cr & \ - "Hint:" && item 4 to -1 of line 1 of tError into tErrorDisplay - end if + put "Message execution error:" & cr & "Error description:" && revIDELookupError("execution", pErrorTrace) & cr & \ + "Hint:" && item 4 to -1 of line 1 of tError into tErrorDisplay end if else put tError into tErrorDisplay @@ -625,23 +647,60 @@ function ideMessageBoxFormatErrorForDisplay pErrorTrace return tErrorDisplay end ideMessageBoxFormatErrorForDisplay +private command __UpdateIntelligenceDisplay + lock screen + local tIntelligence + put revIDEGetPreference("ideMessageBox_intelligenceobject") into tIntelligence + lock messages + try + do "get the long id of the" && tIntelligence + catch tError + end try + global gRevDevelopment + if it is empty or it begins with "stack" or \ + (not gRevDevelopment and revIDEObjectIsOnIDEStack(it)) then + local tCard + put the short name of this card of me into tCard + if tCard is "Single Line" or tCard is "Multiple Lines" then + revIDESetActiveStack + end if + else + local tControl + put the name of it into tControl + set the label of button "Open Stacks" of group "Stacks" of card "Single Line" of me to tIntelligence & ": " & tControl + enable button "Open Stacks" of group "Stacks" of card "Single Line" of me + end if + positionOpenStacksButton + unlock messages + unlock screen +end __UpdateIntelligenceDisplay + +on ideSelectedObjectChanged + __UpdateIntelligenceDisplay +end ideSelectedObjectChanged + +on ideMouseMove + __UpdateIntelligenceDisplay +end ideMouseMove + command revIDEUpdateIntelligenceObject - set the cREVIntelligenceObject of me to revIDEGetPreference("ideMessageBox_intelligenceobject") + local tIntelligence + put revIDEGetPreference("ideMessageBox_intelligenceobject") into tIntelligence + + if tIntelligence is "selectedObject" then + revIDESubscribe "ideSelectedObjectChanged" + revIDEUnsubscribe "ideMouseMove" + else if tIntelligence is "mouseControl" then + revIDESubscribe "ideMouseMove" + revIDEUnsubscribe "ideSelectedObjectChanged" + end if + + set the cREVIntelligenceObject of me to tIntelligence + __UpdateIntelligenceDisplay end revIDEUpdateIntelligenceObject -# Updates the message box mode to reflect whether or not we are debugging something. -command revMessageBoxUpdateMode - if the traceStack is not empty - then revIDESetPreference "IDEDebugMode", true - else revIDESetPreference "IDEDebugMode", false -end revMessageBoxUpdateMode - on ideActiveStacksChanged - local tCard - put the short name of this card of me into tCard - if tCard is "Single Line" or tCard is "Multiple Lines" then - revIDESetActiveStack - end if + __UpdateIntelligenceDisplay end ideActiveStacksChanged command revIDESetActiveStack diff --git a/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinescardbehavior.livecodescript b/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinescardbehavior.livecodescript index 26266998fb..822d514836 100644 --- a/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinescardbehavior.livecodescript +++ b/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinescardbehavior.livecodescript @@ -9,25 +9,26 @@ on preOpenCard if revIDEGetPreference("IDELockedToStack") is true then showFrameItem "unlockDefaultStack" else showFrameItem "lockDefaultStack" - - send "revInitialise" to field "message" of me + + send "revInitialise" to field "script" of me if revIDEGetPreference("IDEMultipleLinesMessageHistory") is not empty then put line 1 of revIDEGetPreference("IDEMultipleLinesMessageHistory") into tMessage replace "\n" with return in tMessage - put tMessage into field "message" + put tMessage into field "script" else - put empty into field "message" + put empty into field "script" end if - focus field "message" - select the text of field "message" + focus field "script" + select the text of field "script" + dispatch "scriptFormat" to the owner of field "script" with "script" put revIDEGetPreference("IDEActiveStack") into tActiveStack revUpdateActiveStack tActiveStack, tActiveStack set the label of button "Open Stacks" to tActiveStack - set the cREVMinHeight of field "message" of this card to 50 + set the cREVMinHeight of field "script" of this card to 50 set the cREVMinHeight of field "results" of this card to 50 set the loc of graphic "line" to the cREVLineLoc of this card send "resizeStack" to me @@ -88,11 +89,11 @@ command dragLine put item 2 of the mouseLoc into tMouseYLoc put the rect of field "results" into tResultsRect - put the rect of field "message" into tMessageRect + put the rect of field "script" into tMessageRect if lMoving is true then - if tMouseYLoc < (the cREVMinHeight of field "message" + the top of field "message") - then put (the cREVMinHeight of field "message" + the top of field "message") into tMouseYLoc + if tMouseYLoc < (the cREVMinHeight of field "script" + the top of field "script") + then put (the cREVMinHeight of field "script" + the top of field "script") into tMouseYLoc if tMouseYLoc > (the bottom of field "results" - the cREVMinHeight of field "results") then put (the bottom of field "results" - the cREVMinHeight of field "results") into tMouseYLoc @@ -105,7 +106,7 @@ command dragLine lock screen set the loc of graphic "line" to tLineXLoc,tMouseYLoc set the rect of field "results" to tResultsRect - set the rect of field "message" to tMessageRect + set the rect of field "script" to tMessageRect unlock screen end if end dragLine diff --git a/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinesmessagebehavior.livecodescript b/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinesmessagebehavior.livecodescript index 8640241b6d..a1c9c22ad3 100644 --- a/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinesmessagebehavior.livecodescript +++ b/Toolset/palettes/message box/behaviors/revmessageboxmultiplelinesmessagebehavior.livecodescript @@ -5,7 +5,6 @@ on enterInField ideMessageBoxExecuteScript(the text of me) if the result is not empty then put the result into me - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me local tMessage put the text of me into tMessage replace return with "\n" in tMessage @@ -30,7 +29,7 @@ on commandKeyDown pKey end if if pKey is "V" then put clipboardData["text"] into the selectedChunk - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me + scriptFormat "script" else pass commandKeyDown end if @@ -45,6 +44,8 @@ on arrowKey which end arrowKey command revInitialise + textInitialize + local tInHistory, tLine put revIDEGetPreference("IDEMultipleLinesMessageHistory") into lHistory @@ -62,6 +63,7 @@ command revInitialise else put 0 into lHistoryIndex end if + scriptFormat "script" end revInitialise command revNextLine @@ -70,8 +72,8 @@ command revNextLine if lHistoryIndex > lNumInHistory then put 1 into lHistoryIndex put line lHistoryIndex of lHistory into tMessage replace "\n" with return in tMessage - put tMessage into field "message" - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me + set the text of me to tMessage + scriptFormat "script" end revNextLine command revPrevLine @@ -80,10 +82,6 @@ command revPrevLine if lHistoryIndex < 1 then put lNumInHistory into lHistoryIndex put line lHistoryIndex of lHistory into tMessage replace "\n" with return in tMessage - put tMessage into field "message" - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me + set the text of me to tMessage + scriptFormat "script" end revPrevLine - -on textChanged - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me -end textChanged diff --git a/Toolset/palettes/message box/behaviors/revmessageboxsinglelinecardbehavior.livecodescript b/Toolset/palettes/message box/behaviors/revmessageboxsinglelinecardbehavior.livecodescript index 0e9f6d720f..7c7db6b5a5 100644 --- a/Toolset/palettes/message box/behaviors/revmessageboxsinglelinecardbehavior.livecodescript +++ b/Toolset/palettes/message box/behaviors/revmessageboxsinglelinecardbehavior.livecodescript @@ -68,8 +68,8 @@ on layoutCard set the rect of field "results" of me to tLeft,(tTop + tHeight),tRight,tBottom put (tRight - tLeft) into tWidth - set the width of graphic "line" to tWidth - set the loc of graphic "line" to (tWidth/2),(tTop+tHeight) + set the width of graphic "line" of me to tWidth + set the loc of graphic "line" of me to (tWidth/2),(tTop+tHeight) unlock messages send "positionOpenStacksButton" to me in 0 milliseconds diff --git a/Toolset/palettes/message box/behaviors/revmessageboxsinglelinemessagebehavior.livecodescript b/Toolset/palettes/message box/behaviors/revmessageboxsinglelinemessagebehavior.livecodescript index e8c8c9e9e0..4f18318c05 100644 --- a/Toolset/palettes/message box/behaviors/revmessageboxsinglelinemessagebehavior.livecodescript +++ b/Toolset/palettes/message box/behaviors/revmessageboxsinglelinemessagebehavior.livecodescript @@ -22,8 +22,13 @@ on enterInField returnInField end enterInField +local sColorizeMsg + on textChanged - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of me + cancel sColorizeMsg + get the long id of me + send "revSEColorizeField it" to stack "revSEUtilities" in 100 milliseconds + put the result into sColorizeMsg revDisplayAutoComplete(the text of me) end textChanged @@ -78,6 +83,8 @@ command revInitialise end if end revInitialise +local sColorizeAutocompleteMsg + command revDisplayAutoComplete pString lock screen local tString @@ -87,17 +94,28 @@ command revDisplayAutoComplete pString put tString into lMatchingHistory put the number of lines in lMatchingHistory into lNumMatching put 1 into lMatchingIndex - put field "message" & char (the number of chars of field "message" +1) to (the number of chars of line 1 of lMatchingHistory) of line 1 of lMatchingHistory into field "auto complete" + get field "message" & char (the number of chars of field "message" +1) to (the number of chars of line 1 of lMatchingHistory) of line 1 of lMatchingHistory + if it is the text of field "auto complete" then + set the hscroll of field "auto complete" to the hscroll of field "message" + unlock screen + return empty + end if + put it into field "auto complete" set the hscroll of field "auto complete" to the hscroll of field "message" else put empty into field "auto complete" end if - - dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of field "auto complete" - set the textColor of char 1 to -1 of field "auto complete" to "gray70" + cancel sColorizeAutocompleteMsg + send "__ColorizeAutocomplete" to me in 100 milliseconds + put the result into sColorizeAutocompleteMsg unlock screen end revDisplayAutoComplete +on __ColorizeAutocomplete + dispatch "revSEColorizeField" to stack "revSEUtilities" with the long id of field "auto complete" + set the textColor of char 1 to -1 of field "auto complete" to "gray70" +end __ColorizeAutocomplete + command revNextLine lock messages if field "auto complete" is empty then diff --git a/Toolset/palettes/message box/revmessagebox.8.rev b/Toolset/palettes/message box/revmessagebox.8.rev index e645a9256f..4bc36dcf74 100644 Binary files a/Toolset/palettes/message box/revmessagebox.8.rev and b/Toolset/palettes/message box/revmessagebox.8.rev differ diff --git a/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontainerrowbehavior.livecodescript b/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontainerrowbehavior.livecodescript index 98a3ce90df..ff2e451c63 100644 --- a/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontainerrowbehavior.livecodescript +++ b/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontainerrowbehavior.livecodescript @@ -21,14 +21,70 @@ on FillInData pDataA, pRow put pDataA["scriptlines"] into field "scriptLines" of me end if - if pDataA["behavior scriptlines"] is empty then - hide field "behaviorScriptLines" of me - put "-" into field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to "This control does not have an associated behavior" + -- Behaviors + if pDataA["behavior"] is empty then + repeat with i = 1 to 10 + hide grc ("behaviorScriptLines" & i) of me + end repeat else - show field "behaviorScriptLines" of me - put pDataA["behavior scriptlines"] into field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to pDataA["behavior"] + + # check parent behaviors + local tTargetBehavior + local tBehaviorList + local tMissingBehaviorList + local tSkipRepeat + + put pDataA["behavior"] into tTargetBehavior + + if tTargetBehavior <> empty then + if exists(tTargetBehavior) then + put tTargetBehavior & cr into tBehaviorList + put false into tSkipRepeat + else --## + put tTargetBehavior & cr into tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + put true into tSkipRepeat + end if + end if + + if not tSkipRepeat then + repeat + put the behavior of tTargetBehavior into tTargetBehavior + + if tTargetBehavior = empty then + exit repeat + end if + + if not (exists(tTargetBehavior)) then --## + put tTargetBehavior & cr after tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + exit repeat + else + put tTargetBehavior & cr after tBehaviorList + end if + end repeat + end if + delete char -1 of tBehaviorList -- return + delete char -1 of tMissingBehaviorList -- return + + local tNoOfLInes + local tCounter + local tCPName + + put min(the number of lines of tBehaviorList, 10) into tNoOfLines + repeat with i = 1 to tNoOfLines + set the toolTip of grc ("behaviorScriptLines" & i) of me to line i of tBehaviorList + if line i of tBehaviorList is among the lines of tMissingBehaviorList then + set the toolTip of grc ("behaviorScriptLines" & i) of me to ("Missing: " & line i of tBehaviorList) + end if + show grc ("behaviorScriptLines" & i) of me + put ("cBehaviorLongID" & i) into tCPName + set the tCPName of me to line i of tBehaviorList + put i into tCounter + end repeat + repeat with j = tCounter + 1 to 10 + hide grc ("behaviorScriptLines" & j) of me + end repeat end if if pDataA["type"] is "stack" then @@ -111,16 +167,20 @@ on LayoutControl pControlRect end if set the height of field "scriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 - set the fixedLineHeight of field "behaviorScriptLines" of me to true - set the textSize of field "behaviorScriptLines" of me to empty - set the textHeight of field "behaviorScriptLines" of me to the textHeight of field "scriptLines" of me - set the height of field "behaviorScriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + repeat with i = 1 to 10 + set the textSize of grc ("behaviorScriptLines" & i) of me to empty + set the height of grc ("behaviorScriptLines" & i) of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + set the width of grc ("behaviorScriptLines" & i) of me to tTextSize + 2 + end repeat set the loc of field "type" of me to tLoc set the loc of field "name" of me to tLoc set the loc of button "typeIcon" of me to tLoc set the loc of field "scriptLines" of me to tLoc - set the loc of field "behaviorScriptLines" of me to tLoc + + repeat with i = 1 to 10 + set the loc of grc ("behaviorScriptLines" & i) of me to tLoc + end repeat ## Set the vertical location of the name and text fields if tTextSize <= 14 then @@ -129,9 +189,7 @@ on LayoutControl pControlRect set the top of field "name" of me to the top of me end if set the top of field "type" of me to the top of field "name" of me - set the width of field "scriptLines" of me to the formattedWidth of field "scriptLines" of me - set the width of field "behaviorScriptLines" of me to the formattedWidth of field "behaviorScriptLines" of me set the width of field "name" of me to the formattedWidth of field "name" of me connectorResize "disclosure" @@ -169,12 +227,22 @@ on LayoutControl pControlRect end if set the right of field "scriptLines" of me to item 3 of pControlRect - the palettePadding of me - set the right of field "behaviorScriptLines" of me to the left of field "scriptLines" of me - 2 + set the right of grc "behaviorScriptLines1" of me to the left of field "scriptLines" of me - the palettePadding of me -2 + repeat with i = 2 to 10 + set the right of grc ("behaviorScriptLines" & i) of me to the left of grc ("behaviorScriptLines" & i - 1) of me - the palettePadding of me + 2 + end repeat ## Check the width of the "name" field so it doesn't overrun the space local tNameWidth - if the visible of field "behaviorScriptLines" of me then - put the left of field "behaviorScriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + + if the visible of grc "behaviorScriptLines1" of me then + put the left of grc "behaviorScriptLines1" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + repeat with i = 10 down to 2 + if the visible of grc ("behaviorScriptLines" & i) of me then + put the left of grc ("behaviorScriptLines" & i) of me - tNameFieldLeft - the palettePadding of me into tNameWidth + exit repeat + end if + end repeat else put the left of field "scriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth end if @@ -192,14 +260,22 @@ end dvRowControl setProp dvHilite[pHiliteColor] pBoolean # Override basic hilite feature... + local tCPName if pBoolean then set the foregroundColor of field "type" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "name" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_1") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_1") set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_TextHiliteColor") - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_TextHiliteColor") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_1") + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_TextHiliteColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + end if + end repeat set the colorOverlay["color"] of button "typeIcon" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of me to revIDEColor("dataView_disclosureIconHiliteColor") set the foregroundColor of widget "icon" of group "disclosure" of me to revIDEColor("dataView_disclosureIconHiliteColor") @@ -207,7 +283,10 @@ setProp dvHilite[pHiliteColor] pBoolean set the foregroundColor of field "type" of me to revIDEColor("text_2") set the foregroundColor of field "name" of me to revIDEColor("text_1") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_3") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_3") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_3") + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end repeat if exists(the cObjectLongID of me) and the scriptStatus of the cObjectLongID of me is "error" then set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") @@ -215,11 +294,16 @@ setProp dvHilite[pHiliteColor] pBoolean set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_hiliteColor") end if - if exists(the cBehaviorLongID of me) and the scriptStatus of the cBehaviorLongID of me is "error" then - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") - else - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_hiliteColor") - end if + repeat with i = 1 to 10 + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) and the scriptStatus of the tCPName of me is "error" then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else if not (exists(the tCPName of me)) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end if + end repeat set the colorOverlay of button "typeIcon" of me to empty set the foregroundColor of me to revIDEColor("dataView_disclosureIconColor") @@ -232,8 +316,45 @@ on mouseUp case "scriptLines" edit the script of the cObjectLongID of me break - case "behaviorScriptLines" - edit the script of the cBehaviorLongID of me + case "behaviorScriptLines1" + checkExistence (the cBehaviorLongID1 of me), 1 + edit the script of the cBehaviorLongID1 of me + break + case "behaviorScriptLines2" + checkExistence (the cBehaviorLongID2 of me), 2 + edit the script of the cBehaviorLongID2 of me + break + case "behaviorScriptLines3" + checkExistence (the cBehaviorLongID3 of me), 3 + edit the script of the cBehaviorLongID3 of me + break + case "behaviorScriptLines4" + checkExistence (the cBehaviorLongID4 of me), 4 + edit the script of the cBehaviorLongID4 of me + break + case "behaviorScriptLines5" + checkExistence (the cBehaviorLongID5 of me), 5 + edit the script of the cBehaviorLongID5 of me + break + case "behaviorScriptLines6" + checkExistence (the cBehaviorLongID6 of me), 6 + edit the script of the cBehaviorLongID6 of me + break + case "behaviorScriptLines7" + checkExistence (the cBehaviorLongID7 of me), 7 + edit the script of the cBehaviorLongID7 of me + break + case "behaviorScriptLines8" + checkExistence (the cBehaviorLongID8 of me), 8 + edit the script of the cBehaviorLongID8 of me + break + case "behaviorScriptLines9" + checkExistence (the cBehaviorLongID9 of me), 9 + edit the script of the cBehaviorLongID9 of me + break + case "behaviorScriptLines10" + checkExistence (the cBehaviorLongID10 of me), 10 + edit the script of the cBehaviorLongID10 of me break case "icon" case "disclosure" @@ -254,8 +375,25 @@ on mouseDoubleUp goToObject the cObjectLongID of me end mouseDoubleUp +command checkExistence pLongID, pOrdinal + local tGraphic + if exists(pLongID) then + return empty + else + put ("behaviorScriptLines" & pOrdinal) into tGraphic + answer the toolTip of grc tGraphic of me + exit to top + end if +end checkExistence + on CloseFieldEditor pFieldEditor, pRow, pKey, pClosingTriggeredBy # The text the user entered is different than the current value of the target field. + if word 1 of the cObjectLongID of me is "stack" and \ + not ideCheckStackName(the text of pFieldEditor) then + // Force a refresh + set the text of field "name" of me to the text of field "name" of me + exit CloseFieldEditor + end if set the textColor of field "name" of me to revIDEColor("text_3") set the text of field "name" of me to the text of pFieldEditor updateProperty the cObjectLongID of me, "name", the text of pFieldEditor @@ -347,7 +485,26 @@ command connectorResize pControl set the width of group pControl of me to 20 set the top of group pControl of me to the top of me - set the width of widget "icon" of group pControl of me to 12 + local tTextSize, tWidgetSize + put the effective textsize of me into tTextSize + switch + case tTextSize >= 8 and tTextSize < 12 + put 11 into tWidgetSize + break + case tTextSize >= 12 and tTextSize < 14 + put 13 into tWidgetSize + break + case tTextSize >= 14 and tTextSize < 18 + put 15 into tWidgetSize + break + case tTextSize >= 18 + put 17 into tWidgetSize + break + default + put 13 into tWidgetSize + end switch + + set the width of widget "icon" of group pControl of me to tWidgetSize set the height of widget "icon" of group pControl of me to the width of widget "icon" of group pControl of me set the loc of widget "icon" of group pControl of me to the loc of group pControl of me end connectorResize diff --git a/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontrolrowbehavior.livecodescript b/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontrolrowbehavior.livecodescript index 5946cee986..704ca2e259 100644 --- a/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontrolrowbehavior.livecodescript +++ b/Toolset/palettes/project browser/behaviors/revideprojectbrowsercontrolrowbehavior.livecodescript @@ -1,6 +1,7 @@ script "revIDEProjectBrowserControlRowBehavior" on FillInData pDataA, pRow # Map pDataA values to physical controls... + if pDataA is empty then exit FillInData set the cIndent of me to pDataA["level"] -1 @@ -27,14 +28,67 @@ on FillInData pDataA, pRow put pDataA["scriptlines"] into field "scriptLines" of me end if - if pDataA["behavior scriptlines"] is empty then - put "-" into field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to "This control does not have an associated behavior" - hide field "behaviorScriptLines" of me + -- Behaviors + if pDataA["behavior"] is empty then + repeat with i = 1 to 10 + hide grc ("behaviorScriptLines" & i) of me + end repeat else - put pDataA["behavior scriptlines"] into field "behaviorScriptLines" of me - show field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to pDataA["behavior"] + + # check parent behaviors + local tTargetBehavior + local tBehaviorList + local tMissingBehaviorList + local tSkipRepeat + + put pDataA["behavior"] into tTargetBehavior + + if tTargetBehavior <> empty then + if exists(tTargetBehavior) then + put tTargetBehavior & cr into tBehaviorList + put false into tSkipRepeat + else + put tTargetBehavior & cr into tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + put true into tSkipRepeat + end if + end if + + if not tSkipRepeat then + repeat + put the behavior of tTargetBehavior into tTargetBehavior + if tTargetBehavior = empty then exit repeat + + if not (exists(tTargetBehavior)) then + put tTargetBehavior & cr after tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + exit repeat + else + put tTargetBehavior & cr after tBehaviorList + end if + end repeat + end if + delete char - 1 of tBehaviorList -- return + delete char -1 of tMissingBehaviorList -- return + + local tNoOfLInes + local tCounter + local tCPName + + put min(the number of lines of tBehaviorList, 10) into tNoOfLines + repeat with i = 1 to tNoOfLines + set the toolTip of grc ("behaviorScriptLines" & i) of me to line i of tBehaviorList + if line i of tBehaviorList is among the lines of tMissingBehaviorList then + set the toolTip of grc ("behaviorScriptLines" & i) of me to ("Missing: " & line i of tBehaviorList) + end if + show grc ("behaviorScriptLines" & i) of me + put ("cBehaviorLongID" & i) into tCPName + set the tCPName of me to line i of tBehaviorList + put i into tCounter + end repeat + repeat with j = tCounter + 1 to 10 + hide grc ("behaviorScriptLines" & j) of me + end repeat end if if revIDEGetPreference("pb_indicator") is "text" then @@ -45,23 +99,8 @@ on FillInData pDataA, pRow show button "controlIcon" of me end if - ## Visibility - if pDataA["visible"] is true then - set the icon of button "visible" of me to the id of image "visible_on" of card "templates" of this stack - set the tooltip of button "visible" of me to "Hide" - else if pDataA["visible"] is false then - set the icon of button "visible" of me to the id of image "visible_off" of card "templates" of this stack - set the tooltip of button "visible" of me to "Show" - end if - - ## Can't select - if pDataA["cantSelect"] is true then - set the icon of button "cantSelect" of me to the id of image "cantSelect_on" of card "templates" of this stack - set the tooltip of button "cantSelect" of me to "Hide" - else if pDataA["cantSelect"] is false then - set the icon of button "cantSelect" of me to the id of image "cantSelect_off" of card "templates" of this stack - set the tooltip of button "cantSelect" of me to "Show" - end if + __SetBoolProp "visible", pDataA["visible"] + __SetBoolProp "cantSelect", pDataA["cantSelect"] end FillInData on LayoutControl pControlRect @@ -93,10 +132,11 @@ on LayoutControl pControlRect end if set the height of field "scriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 - set the fixedLineHeight of field "behaviorScriptLines" of me to true - set the textSize of field "behaviorScriptLines" of me to empty - set the textHeight of field "behaviorScriptLines" of me to the textHeight of field "scriptLines" of me - set the height of field "behaviorScriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + repeat with i = 1 to 10 + set the textSize of grc ("behaviorScriptLines" & i) of me to empty + set the height of grc ("behaviorScriptLines" & i) of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + set the width of grc ("behaviorScriptLines" & i) of me to tTextSize + 2 + end repeat set the loc of field "type" of me to tLoc set the loc of field "name" of me to tLoc @@ -104,9 +144,12 @@ on LayoutControl pControlRect set the loc of button "cantSelect" of me to tLoc set the loc of button "visible" of me to tLoc set the loc of field "scriptLines" of me to tLoc - set the loc of field "behaviorScriptLines" of me to tLoc + + repeat with i = 1 to 10 + set the loc of grc ("behaviorScriptLines" & i) of me to tLoc + end repeat + set the width of field "scriptLines" of me to the formattedWidth of field "scriptLines" of me - set the width of field "behaviorScriptLines" of me to the formattedWidth of field "behaviorScriptLines" of me set the width of field "name" of me to the formattedWidth of field "name" of me ## Set the vertical location of the name and text fields @@ -145,12 +188,22 @@ on LayoutControl pControlRect set the right of button "cantSelect" of me to the item 3 of pControlRect - the palettePadding of me set the right of button "visible" of me to the left of button "cantSelect" of me - the palettePadding of me set the right of field "scriptLines" of me to the left of button "visible" of me - the palettePadding of me - set the right of field "behaviorScriptLines" of me to the left of field "scriptLines" of me - the palettePadding of me + set the right of grc "behaviorScriptLines1" of me to the left of field "scriptLines" of me - the palettePadding of me -2 + repeat with i = 2 to 10 + set the right of grc ("behaviorScriptLines" & i) of me to the left of grc ("behaviorScriptLines" & i - 1) of me - the palettePadding of me + 2 + end repeat ## Check the width of the "name" field so it doesn't overrun the space local tNameWidth - if the visible of field "behaviorScriptLines" of me then - put the left of field "behaviorScriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + + if the visible of grc "behaviorScriptLines1" of me then + put the left of grc "behaviorScriptLines1" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + repeat with i = 10 down to 2 + if the visible of grc ("behaviorScriptLines" & i) of me then + put the left of grc ("behaviorScriptLines" & i) of me - tNameFieldLeft - the palettePadding of me into tNameWidth + exit repeat + end if + end repeat else put the left of field "scriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth end if @@ -166,20 +219,31 @@ getProp dvRowControl end dvRowControl setProp dvHilite[pHiliteColor] pBoolean + local tCPName if pBoolean then set the foregroundColor of field "type" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "name" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_1") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_1") set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_TextHiliteColor") - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_TextHiliteColor") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_1") + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_TextHiliteColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + end if + end repeat set the colorOverlay["color"] of button "controlIcon" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of me to revIDEColor("dataView_disclosureIconHiliteColor") else set the foregroundColor of field "type" of me to revIDEColor("text_2") set the foregroundColor of field "name" of me to revIDEColor("text_1") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_3") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_3") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_3") + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end repeat if exists(the cObjectLongID of me) and the scriptStatus of the cObjectLongID of me is "error" then set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") @@ -187,11 +251,18 @@ setProp dvHilite[pHiliteColor] pBoolean set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_hiliteColor") end if - if exists(the cBehaviorLongID of me) and the scriptStatus of the cBehaviorLongID of me is "error" then - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") - else - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_hiliteColor") - end if + repeat with i = 1 to 10 + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) and the scriptStatus of the tCPName of me is "error" then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else if not (exists(the tCPName of me)) then --## + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else if not (exists(the tCPName of me)) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end if + end repeat set the colorOverlay of button "controlIcon" of me to empty set the foregroundColor of me to revIDEColor("dataView_disclosureIconColor") @@ -203,8 +274,45 @@ on mouseUp case "scriptLines" edit the script of the cObjectLongID of me break - case "behaviorScriptLines" - edit the script of the cBehaviorLongID of me + case "behaviorScriptLines1" + checkExistence (the cBehaviorLongID1 of me), 1 + edit the script of the cBehaviorLongID1 of me + break + case "behaviorScriptLines2" + checkExistence (the cBehaviorLongID2 of me), 2 + edit the script of the cBehaviorLongID2 of me + break + case "behaviorScriptLines3" + checkExistence (the cBehaviorLongID3 of me), 3 + edit the script of the cBehaviorLongID3 of me + break + case "behaviorScriptLines4" + checkExistence (the cBehaviorLongID4 of me), 4 + edit the script of the cBehaviorLongID4 of me + break + case "behaviorScriptLines5" + checkExistence (the cBehaviorLongID5 of me), 5 + edit the script of the cBehaviorLongID5 of me + break + case "behaviorScriptLines6" + checkExistence (the cBehaviorLongID6 of me), 6 + edit the script of the cBehaviorLongID6 of me + break + case "behaviorScriptLines7" + checkExistence (the cBehaviorLongID7 of me), 7 + edit the script of the cBehaviorLongID7 of me + break + case "behaviorScriptLines8" + checkExistence (the cBehaviorLongID8 of me), 8 + edit the script of the cBehaviorLongID8 of me + break + case "behaviorScriptLines9" + checkExistence (the cBehaviorLongID9 of me), 9 + edit the script of the cBehaviorLongID9 of me + break + case "behaviorScriptLines10" + checkExistence (the cBehaviorLongID10 of me), 10 + edit the script of the cBehaviorLongID10 of me break case "icon" case "disclosure" @@ -219,6 +327,17 @@ on mouseUp end switch end mouseUp +command checkExistence pLongID, pOrdinal + local tGraphic + if exists(pLongID) then + return empty + else + put ("behaviorScriptLines" & pOrdinal) into tGraphic + answer the toolTip of grc tGraphic of me + exit to top + end if +end checkExistence + on mouseDown pButton if pButton is 3 then dispatch "pbRightClick" to stack "revIDEProjectBrowser" with the cObjectLongID of me @@ -248,25 +367,25 @@ on ExitFieldEditor pFieldEditor, pRow, pKey, pClosingTriggeredBy end ExitFieldEditor on toggleVisible - if the icon of button "visible" of me is the id of image "visible_on" of card "templates" of this stack then - set the icon of button "visible" of me to the id of image "visible_off" of card "templates" of this stack - updateProperty the cObjectLongID of me, "visible", "false" - else - set the icon of button "visible" of me to the id of image "visible_on" of card "templates" of this stack - updateProperty the cObjectLongID of me, "visible", "true" - end if + __SetBoolProp "visible", the icon of button "visible" of me is the id of image "visible_off" of card "templates" of this stack, true end toggleVisible on toggleCantSelect - if the icon of button "cantSelect" of me is the id of image "cantSelect_on" of card "templates" of this stack then - set the icon of button "cantSelect" of me to the id of image "cantSelect_off" of card "templates" of this stack - updateProperty the cObjectLongID of me, "cantSelect", "false" - else - set the icon of button "cantSelect" of me to the id of image "cantSelect_on" of card "templates" of this stack - updateProperty the cObjectLongID of me, "cantSelect", "true" - end if + __SetBoolProp "cantSelect", the icon of button "cantSelect" of me is the id of image "cantSelect_off" of card "templates" of this stack, true end toggleCantSelect +private command __SetBoolProp pProp, pValue, pUpdate + if pValue then + set the icon of button pProp of me to the id of image (pProp & "_on") of card "templates" of this stack + else + set the icon of button pProp of me to the id of image (pProp & "_off") of card "templates" of this stack + end if + set the tooltip of button pProp of me to "Set" && pProp && "to" && not pValue + if pUpdate then + updateProperty the cObjectLongID of me, pProp, pValue + end if +end __SetBoolProp + getProp dvAcceptsDrop local theA, tRow, tDraggedRow, tDraggedType, tDraggedStyle local tDescendants, tLongID, tNextRow, tType @@ -316,7 +435,26 @@ command connectorResize pControl set the width of group pControl of me to 20 set the top of group pControl of me to the top of me - set the width of widget "icon" of group pControl of me to 12 + local tTextSize, tWidgetSize + put the effective textsize of me into tTextSize + switch + case tTextSize >= 8 and tTextSize < 12 + put 11 into tWidgetSize + break + case tTextSize >= 12 and tTextSize < 14 + put 13 into tWidgetSize + break + case tTextSize >= 14 and tTextSize < 18 + put 15 into tWidgetSize + break + case tTextSize >= 18 + put 17 into tWidgetSize + break + default + put 13 into tWidgetSize + end switch + + set the width of widget "icon" of group pControl of me to tWidgetSize set the height of widget "icon" of group pControl of me to the width of widget "icon" of group pControl of me set the loc of widget "icon" of group pControl of me to the loc of group pControl of me end connectorResize diff --git a/Toolset/palettes/project browser/behaviors/revideprojectbrowsergrouprowbehavior.livecodescript b/Toolset/palettes/project browser/behaviors/revideprojectbrowsergrouprowbehavior.livecodescript index e5c66fa478..00fec0e1a1 100644 --- a/Toolset/palettes/project browser/behaviors/revideprojectbrowsergrouprowbehavior.livecodescript +++ b/Toolset/palettes/project browser/behaviors/revideprojectbrowsergrouprowbehavior.livecodescript @@ -20,14 +20,70 @@ on FillInData pDataA, pRow put pDataA["scriptlines"] into field "scriptLines" of me end if - if pDataA["behavior scriptlines"] is empty then - hide field "behaviorScriptLines" of me - put "-" into field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to "This control does not have an associated behavior" + -- Behaviors + if pDataA["behavior"] is empty then + repeat with i = 1 to 10 + hide grc ("behaviorScriptLines" & i) of me + end repeat else - show field "behaviorScriptLines" of me - put pDataA["behavior scriptlines"] into field "behaviorScriptLines" of me - set the tooltip of field "behaviorScriptLines" of me to pDataA["behavior"] + + # check parent behaviors + local tTargetBehavior + local tBehaviorList + local tMissingBehaviorList + local tSkipRepeat + + put pDataA["behavior"] into tTargetBehavior + + if tTargetBehavior <> empty then + if exists(tTargetBehavior) then + put tTargetBehavior & cr into tBehaviorList + put false into tSkipRepeat + else + put tTargetBehavior & cr into tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + put true into tSkipRepeat + end if + end if + + if not tSkipRepeat then + repeat + put the behavior of tTargetBehavior into tTargetBehavior + + if tTargetBehavior = empty then + exit repeat + end if + + if not (exists(tTargetBehavior)) then + put tTargetBehavior & cr after tBehaviorList + put tTargetBehavior & cr after tMissingBehaviorList + exit repeat + else + put tTargetBehavior & cr after tBehaviorList + end if --## + end repeat + end if + delete char -1 of tBehaviorList + delete char -1 of tMissingBehaviorList + + local tNoOfLInes + local tCounter + local tCPName + + put min(the number of lines of tBehaviorList, 10) into tNoOfLines + repeat with i = 1 to tNoOfLines + set the toolTip of grc ("behaviorScriptLines" & i) of me to line i of tBehaviorList + if line i of tBehaviorList is among the lines of tMissingBehaviorList then + set the toolTip of grc ("behaviorScriptLines" & i) of me to ("Missing: " & line i of tBehaviorList) + end if + show grc ("behaviorScriptLines" & i) of me + put ("cBehaviorLongID" & i) into tCPName + set the tCPName of me to line i of tBehaviorList + put i into tCounter + end repeat + repeat with j = tCounter + 1 to 10 + hide grc ("behaviorScriptLines" & j) of me + end repeat end if if pDataA["childCount"] is empty or pDataA["childCount"] is 0 then @@ -45,23 +101,8 @@ on FillInData pDataA, pRow enable group "disclosure" of me end if - ## Visibility - if pDataA["visible"] is true then - set the icon of button "visible" of me to the id of image "visible_on" of card "templates" of this stack - set the tooltip of button "visible" of me to "Hide" - else if pDataA["visible"] is false then - set the icon of button "visible" of me to the id of image "visible_off" of card "templates" of this stack - set the tooltip of button "visible" of me to "Show" - end if - - ## Can't select - if pDataA["cantSelect"] is true then - set the icon of button "cantSelect" of me to the id of image "cantSelect_on" of card "templates" of this stack - set the tooltip of button "cantSelect" of me to "Hide" - else if pDataA["cantSelect"] is false then - set the icon of button "cantSelect" of me to the id of image "cantSelect_off" of card "templates" of this stack - set the tooltip of button "cantSelect" of me to "Show" - end if + __SetBoolProp "visible", pDataA["visible"] + __SetBoolProp "cantSelect", pDataA["cantSelect"] if revIDEGetPreference("pb_indicator") is "text" then show field "type" of me @@ -102,13 +143,23 @@ on LayoutControl pControlRect end if set the height of field "scriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 - set the fixedLineHeight of field "behaviorScriptLines" of me to true - set the textSize of field "behaviorScriptLines" of me to empty - set the textHeight of field "behaviorScriptLines" of me to the textHeight of field "scriptLines" of me - set the height of field "behaviorScriptLines" of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + repeat with i = 1 to 10 + set the textSize of grc ("behaviorScriptLines" & i) of me to empty + set the height of grc ("behaviorScriptLines" & i) of me to the viewProp["row height"] of the owner of the owner of the owner of me - 6 + set the width of grc ("behaviorScriptLines" & i) of me to tTextSize + 2 + end repeat + + set the loc of field "type" of me to tLoc + set the loc of field "name" of me to tLoc + set the loc of button "cantSelect" of me to tLoc + set the loc of button "visible" of me to tLoc + set the loc of field "scriptLines" of me to tLoc + + repeat with i = 1 to 10 + set the loc of grc ("behaviorScriptLines" & i) of me to tLoc + end repeat set the width of field "scriptLines" of me to the formattedWidth of field "scriptLines" of me - set the width of field "behaviorScriptLines" of me to the formattedWidth of field "behaviorScriptLines" of me set the width of field "name" of me to the formattedWidth of field "name" of me set the loc of field "type" of me to tLoc @@ -116,7 +167,6 @@ on LayoutControl pControlRect set the loc of button "cantSelect" of me to tLoc set the loc of button "visible" of me to tLoc set the loc of field "scriptLines" of me to tLoc - set the loc of field "behaviorScriptLines" of me to tLoc set the loc of image "groupIcon" of me to tLoc ## Set the vertical location of the name and text fields @@ -160,17 +210,26 @@ on LayoutControl pControlRect set the right of button "cantSelect" of me to the item 3 of pControlRect - the palettePadding of me set the right of button "visible" of me to the left of button "cantSelect" of me - the palettePadding of me set the right of field "scriptLines" of me to the left of button "visible" of me - the palettePadding of me - set the right of field "behaviorScriptLines" of me to the left of field "scriptLines" of me - the palettePadding of me + set the right of grc "behaviorScriptLines1" of me to the left of field "scriptLines" of me - the palettePadding of me -2 + repeat with i = 2 to 10 + set the right of grc ("behaviorScriptLines" & i) of me to the left of grc ("behaviorScriptLines" & i - 1) of me - the palettePadding of me + 2 + end repeat ## Check the width of the "name" field so it doesn't overrun the space local tNameWidth - if the visible of field "behaviorScriptLines" of me then - put the left of field "behaviorScriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + if the visible of grc "behaviorScriptLines1" of me then + put the left of grc "behaviorScriptLines1" of me - tNameFieldLeft - the palettePadding of me into tNameWidth + repeat with i = 10 down to 2 + if the visible of grc ("behaviorScriptLines" & i) of me then + put the left of grc ("behaviorScriptLines" & i) of me - tNameFieldLeft - the palettePadding of me into tNameWidth + exit repeat + end if + end repeat else put the left of field "scriptLines" of me - tNameFieldLeft - the palettePadding of me into tNameWidth end if - if the width of field "name" of me > tNameWidth then + if the width of field "name" of me > tNameWidth then set the width of field "name" of me to tNameWidth end if set the left of field "name" of me to tNameFieldLeft @@ -183,14 +242,22 @@ end dvRowControl setProp dvHilite[pHiliteColor] pBoolean # Override basic hilite feature... + local tCPName if pBoolean then set the foregroundColor of field "type" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "name" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_1") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_1") set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_TextHiliteColor") - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_TextHiliteColor") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_1") + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_TextHiliteColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + end if + end repeat set the colorOverlay["color"] of image "groupIcon" of me to revIDEColor("dataView_TextHiliteColor") set the foregroundColor of widget "icon" of group "disclosure" of me to revIDEColor("dataView_disclosureIconHiliteColor") set the foregroundColor of me to revIDEColor("dataView_disclosureIconHiliteColor") @@ -198,7 +265,10 @@ setProp dvHilite[pHiliteColor] pBoolean set the foregroundColor of field "type" of me to revIDEColor("text_2") set the foregroundColor of field "name" of me to revIDEColor("text_1") set the foregroundColor of field "scriptLines" of me to revIDEColor("text_3") - set the foregroundColor of field "behaviorScriptLines" of me to revIDEColor("text_3") + repeat with i = 1 to 10 + set the foregroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("text_3") + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end repeat if exists(the cObjectLongID of me) and the scriptStatus of the cObjectLongID of me is "error" then set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") @@ -206,11 +276,16 @@ setProp dvHilite[pHiliteColor] pBoolean set the backgroundColor of field "scriptLines" of me to revIDEColor("dataView_hiliteColor") end if - if exists(the cBehaviorLongID of me) and the scriptStatus of the cBehaviorLongID of me is "error" then - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_scriptErrorBackgroundColor") - else - set the backgroundColor of field "behaviorScriptLines" of me to revIDEColor("dataView_hiliteColor") - end if + repeat with i = 1 to 10 + put ("cBehaviorLongID" & i) into tCPName + if exists(the tCPName of me) and the scriptStatus of the tCPName of me is "error" then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else if not (exists(the tCPName of me)) then + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_scriptErrorBackgroundColor") + else + set the backgroundColor of grc ("behaviorScriptLines" & i) of me to revIDEColor("dataView_hiliteColor") + end if + end repeat set the colorOverlay of image "groupIcon" of me to empty set the foregroundColor of widget "icon" of group "disclosure" of me to revIDEColor("dataView_disclosureIconColor") @@ -223,8 +298,45 @@ on mouseUp case "scriptLines" edit the script of the cObjectLongID of me break - case "behaviorScriptLines" - edit the script of the cBehaviorLongID of me + case "behaviorScriptLines1" + checkExistence (the cBehaviorLongID1 of me), 1 + edit the script of the cBehaviorLongID1 of me + break + case "behaviorScriptLines2" + checkExistence (the cBehaviorLongID2 of me), 2 + edit the script of the cBehaviorLongID2 of me + break + case "behaviorScriptLines3" + checkExistence (the cBehaviorLongID3 of me), 3 + edit the script of the cBehaviorLongID3 of me + break + case "behaviorScriptLines4" + checkExistence (the cBehaviorLongID4 of me), 4 + edit the script of the cBehaviorLongID4 of me + break + case "behaviorScriptLines5" + checkExistence (the cBehaviorLongID5 of me), 5 + edit the script of the cBehaviorLongID5 of me + break + case "behaviorScriptLines6" + checkExistence (the cBehaviorLongID6 of me), 6 + edit the script of the cBehaviorLongID6 of me + break + case "behaviorScriptLines7" + checkExistence (the cBehaviorLongID7 of me), 7 + edit the script of the cBehaviorLongID7 of me + break + case "behaviorScriptLines8" + checkExistence (the cBehaviorLongID8 of me), 8 + edit the script of the cBehaviorLongID8 of me + break + case "behaviorScriptLines9" + checkExistence (the cBehaviorLongID9 of me), 9 + edit the script of the cBehaviorLongID9 of me + break + case "behaviorScriptLines10" + checkExistence (the cBehaviorLongID10 of me), 10 + edit the script of the cBehaviorLongID10 of me break case "icon" case "disclosure" @@ -239,6 +351,17 @@ on mouseUp end switch end mouseUp +command checkExistence pLongID, pOrdinal + local tGraphic + if exists(pLongID) then + return empty + else + put ("behaviorScriptLines" & pOrdinal) into tGraphic + answer the toolTip of grc tGraphic of me + exit to top + end if +end checkExistence + on mouseDown pButton if pButton is 3 then dispatch "pbRightClick" to stack "revIDEProjectBrowser" with the cObjectLongID of me @@ -252,25 +375,25 @@ on mouseDown pButton end mouseDown on toggleVisible - if the icon of button "visible" of me is the id of image "visible_on" of card "templates" of this stack then - set the icon of button "visible" of me to the id of image "visible_off" of card "templates" of this stack - updateProperty the cObjectLongID of me, "visible", "false" - else - set the icon of button "visible" of me to the id of image "visible_on" of card "templates" of this stack - updateProperty the cObjectLongID of me, "visible", "true" - end if + __SetBoolProp "visible", the icon of button "visible" of me is the id of image "visible_off" of card "templates" of this stack, true end toggleVisible on toggleCantSelect - if the icon of button "cantSelect" of me is the id of image "cantSelect_on" of card "templates" of this stack then - set the icon of button "cantSelect" of me to the id of image "cantSelect_off" of card "templates" of this stack - updateProperty the cObjectLongID of me, "cantSelect", "false" - else - set the icon of button "cantSelect" of me to the id of image "cantSelect_on" of card "templates" of this stack - updateProperty the cObjectLongID of me, "cantSelect", "true" - end if + __SetBoolProp "cantSelect", the icon of button "cantSelect" of me is the id of image "cantSelect_off" of card "templates" of this stack, true end toggleCantSelect +private command __SetBoolProp pProp, pValue, pUpdate + if pValue then + set the icon of button pProp of me to the id of image (pProp & "_on") of card "templates" of this stack + else + set the icon of button pProp of me to the id of image (pProp & "_off") of card "templates" of this stack + end if + set the tooltip of button pProp of me to "Set" && pProp && "to" && not pValue + if pUpdate then + updateProperty the cObjectLongID of me, pProp, pValue + end if +end __SetBoolProp + on mouseDoubleUp if the short name of the target is "name" then set the textColor of field "name" of me to revIDEColor("text_1") @@ -341,7 +464,26 @@ command connectorResize pControl set the width of group pControl of me to 20 set the top of group pControl of me to the top of me - set the width of widget "icon" of group pControl of me to 12 + local tTextSize, tWidgetSize + put the effective textsize of me into tTextSize + switch + case tTextSize >= 8 and tTextSize < 12 + put 11 into tWidgetSize + break + case tTextSize >= 12 and tTextSize < 14 + put 13 into tWidgetSize + break + case tTextSize >= 14 and tTextSize < 18 + put 15 into tWidgetSize + break + case tTextSize >= 18 + put 17 into tWidgetSize + break + default + put 13 into tWidgetSize + end switch + + set the width of widget "icon" of group pControl of me to tWidgetSize set the height of widget "icon" of group pControl of me to the width of widget "icon" of group pControl of me set the loc of widget "icon" of group pControl of me to the loc of group pControl of me end connectorResize diff --git a/Toolset/palettes/project browser/behaviors/revideprojectbrowserlibraryrowbehavior.livecodescript b/Toolset/palettes/project browser/behaviors/revideprojectbrowserlibraryrowbehavior.livecodescript index cad8c9e7ea..0b73ccbb4b 100644 --- a/Toolset/palettes/project browser/behaviors/revideprojectbrowserlibraryrowbehavior.livecodescript +++ b/Toolset/palettes/project browser/behaviors/revideprojectbrowserlibraryrowbehavior.livecodescript @@ -151,7 +151,26 @@ command connectorResize pControl set the width of group pControl of me to 20 set the top of group pControl of me to the top of me - set the width of widget "icon" of group pControl of me to 12 + local tTextSize, tWidgetSize + put the effective textsize of me into tTextSize + switch + case tTextSize >= 8 and tTextSize < 12 + put 11 into tWidgetSize + break + case tTextSize >= 12 and tTextSize < 14 + put 13 into tWidgetSize + break + case tTextSize >= 14 and tTextSize < 18 + put 15 into tWidgetSize + break + case tTextSize >= 18 + put 17 into tWidgetSize + break + default + put 13 into tWidgetSize + end switch + + set the width of widget "icon" of group pControl of me to tWidgetSize set the height of widget "icon" of group pControl of me to the width of widget "icon" of group pControl of me set the loc of widget "icon" of group pControl of me to the loc of group pControl of me end connectorResize diff --git a/Toolset/palettes/project browser/behaviors/revideprojectbrowsersectionrowbehavior.livecodescript b/Toolset/palettes/project browser/behaviors/revideprojectbrowsersectionrowbehavior.livecodescript index adad5513d8..5cdf7fee3d 100644 --- a/Toolset/palettes/project browser/behaviors/revideprojectbrowsersectionrowbehavior.livecodescript +++ b/Toolset/palettes/project browser/behaviors/revideprojectbrowsersectionrowbehavior.livecodescript @@ -117,7 +117,26 @@ command connectorResize pControl set the width of group pControl of me to 20 set the top of group pControl of me to the top of me - set the width of widget "icon" of group pControl of me to 12 + local tTextSize, tWidgetSize + put the effective textsize of me into tTextSize + switch + case tTextSize >= 8 and tTextSize < 12 + put 11 into tWidgetSize + break + case tTextSize >= 12 and tTextSize < 14 + put 13 into tWidgetSize + break + case tTextSize >= 14 and tTextSize < 18 + put 15 into tWidgetSize + break + case tTextSize >= 18 + put 17 into tWidgetSize + break + default + put 13 into tWidgetSize + end switch + + set the width of widget "icon" of group pControl of me to tWidgetSize set the height of widget "icon" of group pControl of me to the width of widget "icon" of group pControl of me set the loc of widget "icon" of group pControl of me to the loc of group pControl of me end connectorResize diff --git a/Toolset/palettes/project browser/revprojectbrowserbehavior.livecodescript b/Toolset/palettes/project browser/revprojectbrowserbehavior.livecodescript index 0da43181bb..d94a836051 100644 --- a/Toolset/palettes/project browser/revprojectbrowserbehavior.livecodescript +++ b/Toolset/palettes/project browser/revprojectbrowserbehavior.livecodescript @@ -6,7 +6,7 @@ on arrowKey pDirection put the dvHilitedRows of group "objectList" of me into tHilitedRow -- up and down are handled by the data view - if the number of items of tHilitedRow is 1 then + if the number of items of tHilitedRow is 1 and not (the dvIsFieldEditor of the target) then switch pDirection case "left" if getRowExpanded(getAbsoluteRow(tHilitedRow)) then @@ -14,7 +14,7 @@ on arrowKey pDirection end if break case "right" - if not getRowExpanded(getAbsoluteRow(tHilitedRow)) then + if not getRowExpanded(getAbsoluteRow(tHilitedRow)) then toggleGroup tHilitedRow, true end if break @@ -81,9 +81,9 @@ on preOpenStack # Preferences addFrameItem "pb_indicator", "header", "preference", "Object type indicator", "enum","Text,Icon", "preferenceChanged", the long id of me addFrameItem "pb_sections", "header", "preference", "Show Sections", "set","Front Scripts,Stacks,Back Scripts,Stacks in use", "preferenceChanged", the long id of me - addFrameItem "pb_stackSort","header","preference","Order stacks by","enum","Name - ascending,Name - descending,Number - ascending,Number - descending","preferenceChanged",the long id of me - addFrameItem "pb_cardSort","header","preference","Order cards by","enum","Name - ascending,Name - descending,Number - ascending,Number - descending","preferenceChanged",the long id of me - addFrameItem "pb_controlSort","header","preference","Order controls by","enum","Name - ascending,Name - descending,Number - ascending,Number - descending","preferenceChanged",the long id of me + addFrameItem "pb_stackSort","header","preference","Order stacks by","enum","Name - ascending,Name - descending,Layer - ascending,Layer - descending","preferenceChanged",the long id of me + addFrameItem "pb_cardSort","header","preference","Order cards by","enum","Name - ascending,Name - descending,Layer - ascending,Layer - descending","preferenceChanged",the long id of me + addFrameItem "pb_controlSort","header","preference","Order controls by","enum","Name - ascending,Name - descending,Layer - ascending,Layer - descending","preferenceChanged",the long id of me addFrameItem "pb_textSize","header","preference","Text size","enum","default,8,10,12,14,18,24","preferenceChanged",the long id of me revIDESubscribe "ideSelectedObjectChanged" @@ -746,7 +746,6 @@ on goToObject pObjectID exit goToObject end if - lock messages if word 1 of pObjectID is "stack" then if not the visible of pObjectID then show pObjectID go pObjectID @@ -757,7 +756,6 @@ on goToObject pObjectID go ideStackOfObject(pObjectID) revIDESelectObjects pObjectID end if - unlock messages end goToObject ########### Footer actions ############ @@ -887,12 +885,16 @@ on cloneControls put pbSelectedObjects() into tControlList lock screen + local tOldDefaultStack + put the defaultStack into tOldDefaultStack + set the defaultStack to revIDEStackOfObject(line 1 of tControlList) repeat for each line tControlID in tControlList revIDECloneObject tControlID put the result & return after tClonedIDs end repeat selectObjects tClonedIDs + set the defaultStack to tOldDefaultStack unlock screen end cloneControls @@ -1037,6 +1039,19 @@ end DataViewUpdated ####################################### function getRow pLongID + if sLongIDToRow[pLongID] is not empty or \ + there is not a pLongID then + return sLongIDToRow[pLongID] + end if + + -- if the stack was new or cloned the long id + -- may have the stack name rather than file name + -- so we try that before returning empty + + --!NOTE this should be considered a workaround until we have an + -- immutable object reference to use instead of long id + put quote & the short name of ideMainStackOfObject(pLongID) & quote into the last word of pLongID + return sLongIDToRow[pLongID] end getRow @@ -1050,6 +1065,7 @@ end getAbsoluteRow function getVisibleRow pLongID local tRow put getRow(pLongID) into tRow + set the wholeMatches to true return itemOffset(tRow, sDisplayArray["visible object keys"]) end getVisibleRow @@ -1461,7 +1477,7 @@ function levelConnectors pObjectArray, pParentRow, pPosition put "branch" into tLevelConnectors[1] end if else if pObjectArray["type"] is "card" then - if word 1 of pObjectArray["owner"] is "stack" AND pObjectArray["owner"] contains "of" then + if word 1 of pObjectArray["owner"] is "stack" AND the owner of pObjectArray["owner"] is not empty then put sDisplayArray["objects"][pParentRow]["levels"] into tParentLevelConnectors if pPosition is "only" then if tParentLevelConnectors[1] is "branch" then put "vertical" into tLevelConnectors[1] @@ -1943,16 +1959,18 @@ on addControlToProjectBrowser pTarget end addControlToProjectBrowser on deleteStackFromProjectBrowser pTarget - if getRow(pTarget) is empty then + local tRow + put getRow(pTarget) into tRow + if tRow is empty then return false end if - local tVisibleRows, tRow, tChildren, tChildOffset + local tVisibleRows, tChildren, tChildOffset put sDisplayArray["visible object keys"] into tVisibleRows ## Only update if expanded - put getRow(pTarget) into tRow + delete variable sLongIDToRow[pTarget] dispatch function "TreeDescendantNodesOfNode" to group "objectList" with sDisplayArray, tRow,false put the result into tChildren @@ -1998,6 +2016,7 @@ on deleteCardFromProjectBrowser pTarget if tParentRow is empty then exit deleteCardFromProjectBrowser put getRow(pTarget) into tRow + delete variable sLongIDToRow[pTarget] put sDisplayArray["objects"][tParentRow]["expanded"] into tParentExpanded if tParentExpanded is false then exit deleteCardFromProjectBrowser @@ -2060,6 +2079,7 @@ on deleteControlFromProjectBrowser pTarget put getRow(pTarget) into tRow if tRow is empty then exit deleteControlFromProjectBrowser + delete variable sLongIDToRow[pTarget] put sDisplayArray["objects"][tParentRow]["children"] into tChildren diff --git a/Toolset/palettes/project browser/templates/revideprojectbrowsercontainerrowtemplate.livecode b/Toolset/palettes/project browser/templates/revideprojectbrowsercontainerrowtemplate.livecode index 245a84de64..02b8652000 100644 Binary files a/Toolset/palettes/project browser/templates/revideprojectbrowsercontainerrowtemplate.livecode and b/Toolset/palettes/project browser/templates/revideprojectbrowsercontainerrowtemplate.livecode differ diff --git a/Toolset/palettes/project browser/templates/revideprojectbrowsercontrolrowtemplate.livecode b/Toolset/palettes/project browser/templates/revideprojectbrowsercontrolrowtemplate.livecode index effeb2a2c4..ffa5f8b760 100644 Binary files a/Toolset/palettes/project browser/templates/revideprojectbrowsercontrolrowtemplate.livecode and b/Toolset/palettes/project browser/templates/revideprojectbrowsercontrolrowtemplate.livecode differ diff --git a/Toolset/palettes/project browser/templates/revideprojectbrowsergrouprowtemplate.livecode b/Toolset/palettes/project browser/templates/revideprojectbrowsergrouprowtemplate.livecode index 9372101834..0f79c75dde 100644 Binary files a/Toolset/palettes/project browser/templates/revideprojectbrowsergrouprowtemplate.livecode and b/Toolset/palettes/project browser/templates/revideprojectbrowsergrouprowtemplate.livecode differ diff --git a/Toolset/palettes/revCore.8.livecode b/Toolset/palettes/revCore.8.livecode index 86385abdee..b308e831f5 100644 Binary files a/Toolset/palettes/revCore.8.livecode and b/Toolset/palettes/revCore.8.livecode differ diff --git a/Toolset/palettes/revIDEExtensionManager.livecode b/Toolset/palettes/revIDEExtensionManager.livecode deleted file mode 100644 index 47b89f83e4..0000000000 Binary files a/Toolset/palettes/revIDEExtensionManager.livecode and /dev/null differ diff --git a/Toolset/palettes/revabout.rev b/Toolset/palettes/revabout.rev index f0c6d51d33..ede409a649 100755 Binary files a/Toolset/palettes/revabout.rev and b/Toolset/palettes/revabout.rev differ diff --git a/Toolset/palettes/revanswerdialog.rev b/Toolset/palettes/revanswerdialog.rev index 0b5eb90467..cf07896281 100755 Binary files a/Toolset/palettes/revanswerdialog.rev and b/Toolset/palettes/revanswerdialog.rev differ diff --git a/Toolset/palettes/revaskdialog.rev b/Toolset/palettes/revaskdialog.rev index 734639e435..636d18325e 100644 Binary files a/Toolset/palettes/revaskdialog.rev and b/Toolset/palettes/revaskdialog.rev differ diff --git a/Toolset/palettes/revcolorchooser.rev b/Toolset/palettes/revcolorchooser.rev index 2cb2127322..966306f381 100644 Binary files a/Toolset/palettes/revcolorchooser.rev and b/Toolset/palettes/revcolorchooser.rev differ diff --git a/Toolset/palettes/revdatagridlibrary.rev b/Toolset/palettes/revdatagridlibrary.rev index e8e6a69564..387446af40 100755 Binary files a/Toolset/palettes/revdatagridlibrary.rev and b/Toolset/palettes/revdatagridlibrary.rev differ diff --git a/Toolset/palettes/revdatagridlibrary/bahaviorsswipecontrolholderbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/bahaviorsswipecontrolholderbehavior.livecodescript new file mode 100644 index 0000000000..0de4d3a800 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/bahaviorsswipecontrolholderbehavior.livecodescript @@ -0,0 +1,218 @@ +script "RevDataGridLibraryBehaviorsSwipeControlHolderBehavior" +---------------------------------------------------------------------- +-- This behavior is applied to a group used to house fully visible swipe +-- controls for a give row and side, dealing with animating the control in an +-- out as well as catching any clicks. (Partially visible - i.e. during a row +-- drag left/right action - are handled in the row's chained behavior). When +-- fully visible, a swipe control takes over the full DataGrid, using the holder +-- group as message catcher, with all clicks in th DataGrid either hiding the +-- swipe control or performing the swipe control click action. + +local sRowIndex +local sSwipeControlSide +local sSwipeControl +local sSwipeControlOwner + +setProp dgSwipeControlSide pSide + put pSide into sSwipeControlSide +end dgSwipeControlSide + +getProp dgSwipeControlSide + return sSwipeControlSide +end dgSwipeControlSide + +-- Animate in the swipe control for the given row index using from the +-- previously specified side. +-- Setting to empty will animate out any visible swipe control. +setProp dgSwipeControlRowIndex pIndex + if pIndex is not empty then + local tRowControl + put the dgDataControlOfIndex[pIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + switch sSwipeControlSide + case "left" + get DG2_CustomisableControlsGetLeftSwipeControlForControl(the long id of tRowControl) + break + case "right" + get DG2_CustomisableControlsGetRightSwipeControlForControl(the long id of tRowControl) + break + default + return "Unknown swipe side" && sSwipeControlSide + end switch + if it is empty then + return "Could not find swipe control" + end if + + put it into sSwipeControl + put pIndex into sRowIndex + put the owner of sSwipeControl into sSwipeControlOwner + + lock screen + set the rect of me to the rect of group "dgList" of the dgControl of me + set the rect of graphic "Message Catcher" of me to the rect of me + set the visible of me to true + unlock screen + + DG2_SwipeControlShow + return the result + else + local tResult + DG2_SwipeControlHide + put empty into sRowIndex + return tResult + end if +end dgSwipeControlRowIndex + +getProp dgSwipeControlRowIndex + return sRowIndex +end dgSwipeControlRowIndex + +-- A scroll or resize has occurred. Reposition the group inside the the list, +-- the swipe control next to the appropriate row and the row to the left or +-- right of the swipe control. +command DG2_SwipeControlHolderReposition + if not the visible of me then + return empty + end if + if sRowIndex is empty then + return empty + end if + if sSwipeControl is empty then + return empty + end if + + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + set the visible of sSwipeControl to false + return empty + end if + + lock screen + set the visible of sSwipeControl to true + set the rect of me to the rect of group "dgList" of the dgControl of me + set the rect of graphic "Message Catcher" of me to the rect of me + set the top of sSwipeControl to the top of tRowControl + switch sSwipeControlSide + case "left" + set the left of tRowControl to the right of sSwipeControl + break + case "right" + set the right of tRowControl to the left of sSwipeControl + break + end switch + unlock screen + + return empty +end DG2_SwipeControlHolderReposition + +private command DG2_SwipeControlShow + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + -- A swipe has been occured so tell the user by sending the + -- appropriate message. If the user handles the message then we + -- can assume they are dealing with the action and on't need to do + -- anything more. If it's not handled, then fully animate in the + -- swipe control. + switch sSwipeControlSide + case "left" + dispatch DG2_GetMessageNameForTag("RowSwipedRight") to tRowControl + if it is not "handled" then + DG2_AnimationsAdd the long id of tRowControl, "left", the left of tRowControl, the right of sSwipeControl, the dgAnimationProp["SwipeCompleteDuration"] of the dgControl of me, the dgAnimationProp["SwipeCompleteEasing"] of the dgControl of me, "DG2_SwipeControlShowComplete", empty, the long id of me + end if + break + case "right" + dispatch DG2_GetMessageNameForTag("RowSwipedLeft") to tRowControl + if it is not "handled" then + DG2_AnimationsAdd the long id of tRowControl, "right", the right of tRowControl, the left of sSwipeControl, the dgAnimationProp["SwipeCompleteDuration"] of the dgControl of me, the dgAnimationProp["SwipeCompleteEasing"] of the dgControl of me, "DG2_SwipeControlShowComplete", empty, the long id of me + end if + break + end switch + + return empty +end DG2_SwipeControlShow + +on DG2_SwipeControlShowComplete + -- When the animation is complete, the swipe control should be fully visible. + -- This means we can now bring it to the front of the DataGrid allowing it or + -- the holder group to catch all messages. + lock screen + relayer me to front of owner + relayer sSwipeControl to front of me + unlock screen + + return empty +end DG2_SwipeControlShowComplete + +private command DG2_SwipeControlHide + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + local tIsVisible + put the visible of me into tIsVisible + + lock screen + relayer sSwipeControl before tRowControl + set the visible of me to false + unlock screen + + -- The row script takes care of returning the swipe control. + -- If we're not visible then tell the row control not to bother animating the + -- return. + dispatch "DG2_SwipeReturn" to tRowControl with not tIsVisible + return the result +end DG2_SwipeControlHide + +on DG2_SwipeControlHideComplete + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is not empty then + set the left of tRowControl to the left of group "dgList" of the dgControl of me + end if + + if sSwipeControl is not empty then + set the visible of sSwipeControl to false + relayer sSwipeControl to back of sSwipeControlOwner + end if + + return empty +end DG2_SwipeControlHideComplete + +on mouseUp + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + exit mouseUp + end if + + if the long id of the target contains the long id of sSwipeControl then + switch sSwipeControlSide + case "left" + dispatch DG2_GetMessageNameForTag("RowLeftSwipeControlClicked") to tRowControl with the target + break + case "right" + dispatch DG2_GetMessageNameForTag("RowRightSwipeControlClicked") to tRowControl with the target + break + end switch + else + DG2_SwipeControlHide + switch sSwipeControlSide + case "left" + dispatch DG2_GetMessageNameForTag("RowLeftSwipeControlHidden") to tRowControl + break + case "right" + dispatch DG2_GetMessageNameForTag("RowRightSwipeControlHidden") to tRowControl + break + end switch + end if +end mouseUp diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsactioncontrolholderbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsactioncontrolholderbehavior.livecodescript new file mode 100644 index 0000000000..e9bf38a384 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsactioncontrolholderbehavior.livecodescript @@ -0,0 +1,168 @@ +script "RevDataGridLibraryBehaviorsActionControlHolderBehavior" +---------------------------------------------------------------------- +-- This behavior is applied to a group used to house the action control for a +-- given row. It takes care of animating the action control in and out as well +-- as handling any actions when visible: When visible, the action control takes +-- over the full DataGrid, with all clicks either resulting in the action +-- control being hidden or the action control action being applied. The +-- behaviors's group acts as a message catcher, spanning the whole DataGrid. + +local sRowIndex +local sActionControl +local sActionControlOwner + +-- Animate in the action control for the row with the given index. +-- Setting to empty will animate out any visible action control. +setProp dgActionControlRowIndex pIndex + if pIndex is not empty then + local tRowControl + put the dgDataControlOfIndex[pIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + get DG2_CustomisableControlsGetEditModeActionControlForControl(the long id of tRowControl) + if it is empty then + return "Could not find action control" + end if + + put it into sActionControl + put pIndex into sRowIndex + put the owner of sActionControl into sActionControlOwner + + lock screen + set the rect of me to the rect of group "dgList" of the dgControl of me + set the rect of graphic "Message Catcher" of me to the rect of me + set the visible of me to true + unlock screen + + DG2_EditModeActionControlShow + return the result + else + local tResult + DG2_EditModeActionControlHide + put the result into tResult + put empty into sRowIndex + return the result + end if +end dgActionControlRowIndex + +getProp dgActionControlRowIndex + return sRowIndex +end dgActionControlRowIndex + +-- A scroll or resize has occurred. Reposition the group inside the the list, +-- the action control next to the appropriate row and the row to the left of +-- the action control. +command DG2_EditModeActionControlHolderReposition + if not the visible of me then + return empty + end if + if sRowIndex is empty then + return empty + end if + if sActionControl is empty then + return empty + end if + + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + set the visible of sActionControl to false + return empty + end if + + lock screen + set the visible of sActionControl to true + set the rect of me to the rect of group "dgList" of the dgControl of me + set the rect of graphic "Message Catcher" of me to the rect of me + set the top of sActionControl to the top of tRowControl + set the right of tRowControl to the left of sActionControl + unlock screen + + return empty +end DG2_EditModeActionControlHolderReposition + +private command DG2_EditModeActionControlShow + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + -- We relayer the action control behind the row so that it is revealed as the + -- row animates left. + lock screen + relayer sActionControl before tRowControl + set the rect of sActionControl to the right of tRowControl - the width of sActionControl, the top of tRowControl, the right of tRowControl, the bottom of tRowControl + set the visible of sActionControl to true + unlock screen + + DG2_AnimationsAdd the long id of tRowControl, "left", the left of tRowControl, the left of tRowControl - the width of sActionControl, the dgAnimationProp["EditModeActionControlAnimationDuration"] of the dgControl of me, the dgAnimationProp["EditModeActionControlAnimationEasing"] of the dgControl of me, "DG2_EditModeActionControlShowComplete", empty, the long id of me + + return empty +end DG2_EditModeActionControlShow + +on DG2_EditModeActionControlShowComplete + -- When the animation is complete, the action control should be fully visible. + -- This means we can now bring it to the front of the DataGrid allowing it or + -- the holder group to catch all messages. + lock screen + relayer me to front of owner + relayer sActionControl to front of me + unlock screen + + return empty +end DG2_EditModeActionControlShowComplete + +private command DG2_EditModeActionControlHide + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + return "Could not find row control" + end if + + if the visible of me then + -- Put the action control back behind the row control so that it is hidden + -- as the row animates right. + lock screen + relayer sActionControl before tRowControl + set the visible of me to false + unlock screen + + DG2_AnimationsAdd the long id of tRowControl, "left", the left of tRowControl, the left of tRowControl + the width of sActionControl, the dgAnimationProp["EditModeActionControlAnimationDuration"] of the dgControl of me, the dgAnimationProp["EditModeActionControlAnimationEasing"] of the dgControl of me, "DG2_EditModeActionControlHideComplete", empty, the long id of me + else + -- If we're not visible, don't bother with any animating. + set the left of tRowControl to the left of group "dgList" of the dgControl of me + DG2_EditModeActionControlHideComplete + end if + + return empty +end DG2_EditModeActionControlHide + +on DG2_EditModeActionControlHideComplete + -- Return the action control to where it was before being added to the group. + if sActionControl is not empty then + lock screen + set the visible of sActionControl to false + relayer sActionControl to back of sActionControlOwner + unlock screen + end if + + return empty +end DG2_EditModeActionControlHideComplete + +on mouseUp + local tRowControl + put the dgDataControlOfIndex[sRowIndex] of the dgControl of me into tRowControl + if tRowControl is empty then + exit mouseUp + end if + + if the long id of the target contains the long id of sActionControl then + dispatch DG2_GetMessageNameForTag("EditModeActionControlClicked") to tRowControl with the target + else + DG2_EditModeActionControlHide + dispatch DG2_GetMessageNameForTag("EditModeActionControlHidden") to tRowControl + end if +end mouseUp diff --git a/Toolset/palettes/revdatagridlibrary/behaviorscolumngroupbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorscolumngroupbuttonbehavior.livecodescript new file mode 100644 index 0000000000..c3968a6638 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorscolumngroupbuttonbehavior.livecodescript @@ -0,0 +1,12 @@ +script "RevDataGridLibraryBehaviorsColumnGroupButtonBehavior" +--> all handlers + + +getprop dgColumnGroup + return the long id of me +end dgColumnGroup + + +getprop dgColumn + return the short name of me +end dgColumn diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsdatagridbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsdatagridbuttonbehavior.livecodescript new file mode 100644 index 0000000000..d15695b9aa --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsdatagridbuttonbehavior.livecodescript @@ -0,0 +1,11579 @@ +script "RevDataGridLibraryBehaviorsDataGridButtonBehavior" +local sDataArray -- Multi-dimensional array +local sIndexSequencing -- sDataArray indexes in order they should appear + +local sInit -- Has control been opened once before? +local sControlIsOpen + +constant kDefaultDimmedHiliteColor = "212,212,212" +constant kRowColor = "255,255,255" +constant kHeaderBkgrndStartColor = "219,219,219" +constant kHeaderBkgrndEndColor = "188,188,188" +constant kHeaderBkgrndHiliteStartColor = "194,207,221" +constant kHeaderBkgrndHiliteEndColor = "125,147,148" +constant kHeaderDividerColor = "168,168,168" +constant kHeaderDividerThreeDColor = "227,227,227" +constant kAlternateRowColor = "230,237,247" +constant kDefaultTableColWidth = 100 +constant kDefaultRowHeight = 21 +constant kDefaultRowColor = "255,255,255" +constant kDefaultCornerColor = "232,232,232" +constant kAlternatingRowModValue = 0 -- 0 to have first color be first, 1 to have first color be alternating color +constant kSortTypes = "text,international,numeric,datetime,system datetime" + +constant kSBWidthWin = 17 +constant kSBWidthMac = 15 +constant kSBWidthLinux = 16 + +constant kErrInvalidArray = 422 +constant kErrInvalidBoolean = 452 +constant kErrInvalidNumber = 453 +constant kErrPropDoesntExist = 456 +constant kErrInvalidInteger = 354 +constant kErrInvalidPoint = 355 +constant kErrInvalidRect = 356 +constant kErrInvalidColor = 343 +constant kErrReadOnlyProp = 449 +constant kErrInvalidProperty = 348 +constant kErrCantFindObject = 619 +constant kErrRenameErrorInDestination = 487 + +constant kFieldEditorName = "DataGridFieldEditor" +local sFieldEditor + +local sControlOfIndexA -- Links an index to a particular control. Used when dgProps["cache controls"] = true and drawing is not done in real time. +local sControlHeights -- if uFixedLineHeight is true then the height of a single contorl. Otherwise an array keyed by INDEX of sDataArray. +local sFormattedHeight +local sFormattedWidth +local sControlsRequiredToFillSpace +local sHilitedIndexes -- comma delimited list +local sFirstIndexClickedWithShiftKeyDown -- When shift clicking we need to store first index clicked on for reference +local sPendingMsgsA +local sRunningActionsA + +local sIsAnimating = false +local sDeselectOnMouseUp +local sSystemA -- stores system specific settings +local sFocusLeftMe + +local sDefaultDropIndicatorRect + +local sDropStructure + +local sLockDrawing -- todo: add set/get. When locked we don't redraw when data is created, deleted, reordered or updated. + +## for tables +local sTableObjectsA + +local sScrollerId +local sPollID + +-------------------------------------------------------------------------------- +-- DataGrid 2 Variables + +local sEditMode + +--- + +local sReorderInProgress +local sReorderControl +local sReorderStartIndex +local sReorderStartLine +local sReorderLastHoverLine +local sReorderMouseMoveInProgress +local sReorderMoveMsgId + +constant sReorderMovePollRate = 30 + +constant kReorderDragControlBlendLevel = 30 +constant kReorderDragControlGlowColor = "0,0,0" +constant kReorderDragControlGlowSize = 10 +constant kReorderDragControlGlowSpread = 10 + +--- + +local sReorderScrollPollMsgID + +constant kReorderScrollPollRate = 30 +constant kReorderScrollPollMargin = 30 +constant kReorderScollPollIncrement = 10 + +--- + +local sAnimationsA +local sAnimationsLastID +local sAnimationsPulseMsgID + +constant kAnimationsPulseRate = 30 +--- + +local sAnimationProps + +constant kEditModeEnterExitDuration = 250 +constant kEditModeEnterExitActionSelectControlControlEasing = "in out" +constant kEditModeEnterExitReorderControlEasing = "linear" + +constant kEditModeActionControlAnimationDuration = 250 +constant kEditModeActionControlAnimationEasing = "in out" + +constant kReorderAnimationDuration = 250 +constant kReorderAnimationEasing = "in out" + +constant kReorderHomingDuration = 250 +constant kReorderHomingEasing = "in out" + +constant kDeleteIndexAnimationDuration = 250 +constant kDeleteIndexAnimationEasing = "in out" + +constant kSwipeCompleteDuration = 300 +constant kSwipeCompleteEasing = "out back" + +constant kSwipeReturnDuration = 500 +constant kSwipeReturnEasing = "out bounce" + +--- + +local sCustomisableControlsInitialised +local sCustomisableControlsA +local sCustomisableControlsSingletonsA +local sCustomisableControlsSingletonCopyMapA + +constant kCustomisableControlNames = "edit mode action control,edit mode action select control,edit mode reorder control,left swipe control,right swipe control" +constant kCustomisableControlSingletons = "edit mode action control,left swipe control,right swipe control" + +constant kEditModeReorderControlMargins = 8 +constant kEditModeReorderControlWidth = 20 +constant kEditModeReorderControlIcon = "reorder" +constant kEditModeReorderControlColor = "199,199,199" + +constant kEditModeActionSelectControlMargins = 8 +constant kEditModeActionSelectControlWidth = 15 +constant kEditModeActionSelectControlIcon = "minus sign" +constant kEditModeActionSelectControlIconColor = "255,59,48" + +constant kEditModeActionControlText = "Delete" +constant kEditModeActionControlTextColor = "255,255,255" +constant kEditModeActionControlBGColor = "255,59,48" +constant kEditModeActionControlWidth = 100 + +constant kSwipeControlWidth = 125 +constant kSwipeControlBGColor = "255,59,48" +constant kSwipeControlIcon = "trash" +constant kSwipeControlIconWidth = 20 +constant kSwipeControlIconColor = "255,255,255" + +--- + +constant kEditModeEditModeReorderStarted = "EditModeReorderStarted" +constant kEditModeEditModeReorderCompleted = "EditModeReorderCompleted" +constant kMessageEditModeActionSelectControlClicked = "EditModeActionSelectControlClicked" +constant kMessageEditModeActionControlClicked = "EditModeActionControlClicked" +constant kMessageEditModeActionControlHidden = "EditModeActionControlHidden" +constant kMessageRowSwipedRight = "RowSwipedRight" +constant kMessageRowSwipedLeft = "RowSwipedLeft" +constant kMessageRowLeftSwipeControlClicked = "RowLeftSwipeControlClicked" +constant kMessageRowRightSwipeControlClicked = "RowRightSwipeControlClicked" +constant kMessageRowLeftSwipeControlHidden = "RowLeftSwipeControlHidden" +constant kMessageRowRightSwipeControlHidden = "RowRightSwipeControlHidden" + +-------------------------------------------------------------------------------- + +--> Messages (engine) + +before preopenControl + if the target is not me then pass preopencontrol + local isOpen + put sControlIsOpen into isOpen + + try + _Initialize + put true into sControlIsOpen + + if not isOpen then + _DrawAlternatingRows + end if + catch e + put e + end try + + pass preopenControl +end preopenControl + + +before closeControl + if the target is not me then pass closeControl + + DeleteFieldEditor + put false into sControlIsOpen + put true into sFocusLeftMe + + if the environment is "mobile" then + mobileControlDelete sScrollerId + put empty into sScrollerId + end if + + cancel sPollID + pass closeControl +end closeControl + + +before newGroup + if the target is not me then pass newGroup + _Initialize + pass newGroup +end newGroup + +on __PollVisibility + cancel sPollID + if __HasMobileScroller() then + send "__PollVisibility" to me in 300 milliseconds + put the result into sPollID + + mobileControlSet sScrollerId, "visible", the effective visible of me + end if +end __PollVisibility + +private command _Initialize + if not sInit then + set the wholeMatches to true + local theMasterRect + put the rect of me into theMasterRect + + ## Configure the DG subgroups to enable use of acceleratedRendering + ## effectively in form mode. + + ## The top-level group must be container (this means that no adornment + ## props must be set on the top-level group). + set the layerMode of me to "container" + + ## The dgBackground group holds the backdrop behind the row-templates. + ## This can be changed to static when the engine is changed so that + ## a control is only redrawn when focused *if* it will change appearance. + set the layerMode of control "dgBackground" of me to "dynamic" + + ## The dgListMask group holds the scrolling elements; in form view mode + ## only the dgList subgroup is relevant. As it holds other subgroups which + ## will hold dynamic layers it must be container. + set the layerMode of group "dgListMask" of me to "container" + + ## The dgList group holds the replicated row template groups. As it holds + ## dynamic layer groups it must be container. + set the layerMode of group "dgList" of me to "container" + + ## The dgHorizontalComponents group holds the horizontal scrollbar and + ## corner wedge. Making it dynamic means that it doesn't cause re-rendering + ## of static layers above when it changes. + set the layerMode of group "dgHorizontalComponents" of me to "dynamic" + + ## The dgScrollbar group holds the vertical scrollbar. Making it dynamic + ## means that it doesn't cause re-rendering of static layers above when it + ## changes. + set the layerMode of scrollbar "dgScrollbar" of me to "dynamic" + + ## The following groups all relate to table mode. These are all set to + ## static for now. + set the layerMode of group "dgAlternatingRowsMask" of me to "static" + set the layerMode of group "dgHighlights" of me to "static" + set the layerMode of group "dgHeaderComponents" of me to "static" + set the layerMode of group "dgDividers" of me to "static" + + switch the platform + case "Win32" + if "registryRead" is among the items of the securityPermissions then + put queryRegistry("HKEY_CURRENT_USER\Control Panel\Colors\HilightText") into sSystemA["hilited text color"] + if sSystemA["hilited text color"] is not empty then + replace space with comma in sSystemA["hilited text color"] + end if + local theValue + put queryRegistry("HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\ScrollWidth") into theValue + if theValue is an integer then + put abs(theValue/15) into sSystemA["scrollbarWidth"] + end if + end if + + break + end switch + + ## Set behaviors as needed + ## These behaviors weren't set in original template + set the behavior of group "dgHeaderMask" of me to the long ID of button "Header Mask" of group "Behaviors" of stack _ResourceStack() + set the behavior of group "dgList" of me to the long ID of button "dgList Message Catcher" of group "Behaviors" of stack _ResourceStack() + + ## Developer could have set data before control opened + if the keys of sDataArray is empty then + _DeleteControls + _RestorePersistentData + end if + + if the environment is not "mobile" then + set the traversalOn of scrollbar "dgScrollbar" of me to false ## take out of tabbing + set the traversalOn of scrollbar "dgHScrollbar" of me to false ## take out of tabbing + set the visible of scrollbar "dgScrollbar" of me to the dgProps["show vscrollbar"] of me is not false + + if _ControlType() is "table" then + set the visible of group "dgHorizontalComponents" of me to the dgProps["show hscrollbar"] of me is not false + end if + + set the borderWidth of scrollbar "dgScrollbar" of me to 0 ## For Windows 2000 + set the borderWidth of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0 ## For Windows 2000 + + _SetScrollbarWidth + else + _CreateMobileScroller + end if + + ## Set props which didn't come with original Data Grid + if the dgProps["header divider color"] of me is not a color then + set the dgProps["header divider color"] of me to kHeaderDividerColor + end if + if the dgProps["header divider threeD color"] of me is not a color then + set the dgProps["header divider threeD color"] of me to kHeaderDividerThreeDColor + end if + + if _ControlType() is "table" then + _table.CreateColumns + end if + + _ResetTemplateFieldEditor + + ## Make sure rect is as it started + lock messages + set the rect of me to theMasterRect + unlock messages + + -- Set up DataGrid 2 + DG2_ClearVars + DG2_AnimationsInitProps + DG2_EnsureRowChainedBehavior + + put true into sInit + else if the environment is "mobile" then + _CreateMobileScroller + end if + + ResizeToFit +end _Initialize + + +private command _CreateMobileScroller + set the visible of scrollbar "dgScrollbar" of me to false + set the visible of scrollbar "dgHScrollbar" of me to false + if the dgProps["show vscrollbar"] of me is not false or \ + (_ControlType() is "table" and \ + the dgProps["show hscrollbar"] of me is not false) then + if sScrollerId is empty or sScrollerId is not among the lines of mobileControls() then + put the long id of me into sScrollerId + mobileControlCreate "scroller", sScrollerId + end if + mobileControlSet sScrollerId, "canBounce", "true" + mobileControlSet sScrollerId, "pagingEnabled", "false" + mobileControlSet sScrollerId, "canScrollToTop", "true" + mobileControlSet sScrollerId, "delayTouches", "false" + mobileControlSet sScrollerId, "canCancelTouches", "true" + __PollVisibility + end if +end _CreateMobileScroller + + +command _SetScrollbarWidth pWidth + lock screen + if pWidth is not an integer then + if the dgProps["scrollbar width"] of me is an integer then + put the dgProps["scrollbar width"] of me into pWidth + else + if sSystemA["scrollbarWidth"] is an integer then + put sSystemA["scrollbarWidth"] into pWidth + else + if the platform is "MacOS" then + put kSBWidthMac into pWidth + else if the platform is "win32" then + put kSBWidthWin into pWidth + else + put kSBWidthLinux into pWidth + end if + end if + end if + end if + + local theRectV, theRectH + put the rect of scrollbar "dgScrollbar" of me into theRectV + put the rect of scrollbar "dgHScrollbar" of me into theRectH + put item 3 of theRectV - pWidth into item 1 of theRectV + put item 4 of theRectH - pWidth into item 2 of theRectH + + set the rect of scrollbar "dgScrollbar" of me to theRectV + set the rect of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to theRectH + unlock screen +end _SetScrollbarWidth + + +before deleteGroup + if the target is not me then pass deleteGroup +end deleteGroup + + +before resizeControl + if the target is not me then return empty + ResizeToFit + pass resizeControl +end resizeControl + + +before focusIn + ## update the hilite when focus enters control + if sFocusLeftMe is not false then + _UpdateHiliteColor + end if + + put false into sFocusLeftMe + pass focusIn +end focusIn + + +before openField + if sFocusLeftMe is not false then + _UpdateHiliteColor + end if + pass openField +end openField + + +before focusOut + ## As of Rev 3.5 we don't know whether or not focus is leaving the data grid in focusOut + ## We send a message in time and check the focusedobject in order to work around this. + ## This is not ideal and leads to other issues as focus shifts around some UIs but it is all we have. + send "_CheckForFocusLeavingMe" to me in 0 milliseconds + pass focusOut +end focusOut + +before closeField + send "_CheckForFocusLeavingMe" to me in 0 seconds + pass closeField +end closeField + +before exitField + send "_CheckForFocusLeavingMe" to me in 0 seconds + pass exitField +end exitField + + +command _CheckForFocusLeavingMe + if not sControlIsOpen then return empty + + if the long ID of me is not in the long ID of the focusedObject then + ## focus left me + put true into sFocusLeftMe + _UpdateHiliteColor + end if +end _CheckForFocusLeavingMe + + +## Store data that will be sent when user reorders row +setprop dgDragReorderData pValue + put pValue into sDropStructure["drag drop data"] +end dgDragReorderData + + +getprop dgDragReorderData + return sDropStructure["drag drop data"] +end dgDragReorderData + + +setprop dgDragImageIndex pIndex + if _ControlType() is "form" then + local theControl + put the dgDataControlOfIndex[pIndex] of me into theControl + if theControl is not empty then + _CreateDragImageFromControl theControl + end if + else + _CreateDragImageFromIndex pIndex + end if +end dgDragImageIndex + + +setprop dgDragImageLine pLine + if _ControlType() is "form" then + local theControl + put the dgDataControlOfLine[pLine] of me into theControl + if theControl is not empty then + _CreateDragImageFromControl theControl + end if + else + _CreateDragImageFromIndex the dgIndexOfLine[pLine] of me + end if +end dgDragImageLine + + +private command _CreateDragImageFromControl pControl + if there is not a image "dgDragImage" of me then + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + reset the templateImage + create image "dgDragImage" in me + set the lockMessages to msgsAreLocked + set the visible of it to false + unlock screen + end if + export snapshot from pControl to image "dgDragImage" of me as PNG + + local theImageOffset + set the dragImage to the ID of image "dgDragImage" of me + put the clickH - the left of pControl & comma & \ + the clickV - the top of pControl into theImageOffset + set the dragImageOffset to theImageOffset +end _CreateDragImageFromControl + + +private command _CreateDragImageFromIndex pIndex + local theControls, theRect, theVisibleRect, msgsAreLocked + put sTableObjectsA["columns"][ line 1 of the keys of sTableObjectsA["columns"] ]["row controls"] into theControls + repeat for each line theControl in theControls + if the dgIndex of theControl is pIndex then + put the rect of theControl into theRect + put _VisibleDataRect() into theVisibleRect + put item 1 of theVisibleRect into item 1 of theRect + put item 3 of theVisibleRect into item 3 of theRect + + if there is not a image "dgDragImage" of me then + lock screen + put the lockMessages into msgsAreLocked + lock messages + reset the templateImage + create image "dgDragImage" in me + set the lockMessages to msgsAreLocked + set the visible of it to false + unlock screen + end if + + export snapshot from rect theRect of this card to image "dgDragImage" of me as PNG + + set the dragImage to the ID of image "dgDragImage" of me + + local theImageOffset + put the clickH - item 1 of theRect & comma & \ + the clickV - item 2 of theRect into theImageOffset + set the dragImageOffset to theImageOffset + + exit repeat + end if + end repeat +end _CreateDragImageFromIndex + + +## Set to true to turn on drag indicator and announce +## if a successful drop occurs +setprop dgTrackDragReorder [pOriginatingIndex] pValue + if there is not a group "dgDropIndicator" of me then throw "Group Drag Indicator does not exist in list group:" && the long ID of me + + if pValue is not sDropStructure["tracking"] then + if pValue then + put pOriginatingIndex into sDropStructure["originating index"] + + set the topLeft of group "dgDropIndicator" of me to the topLeft of group "dgList" of me + dispatch "resizeControl" to group "dgDropIndicator" of me + put the rect of group "dgDropIndicator" of me into sDefaultDropIndicatorRect + insert script of button "dgTrackDragDrop" of me into front + set the dgTargetControl of group "dgDropIndicator" of me to the long ID of me + ## initialize index mouse is over + dgDragMove the mouseH, the mouseV + else + remove script of button "dgTrackDragDrop" of me from front + set the visible of group "dgDropIndicator" of me to false + put empty into sDropStructure + + if there is a image "dgDragImage" of me then + delete image "dgDragImage" of me + end if + end if + + put pValue is true into sDropStructure["tracking"] + end if +end dgTrackDragReorder + + +on dgDragEnd + set the dgTrackDragReorder of me to false +end dgDragEnd + + +on dgDragDrop + ## Cache before we clean up + local processTheDrop + put the visible of group "dgDropIndicator" of me into processTheDrop + + local theDropStructure + put sDropStructure into theDropStructure + + ## If some other control displays a dialog during dragDrop, dragMove will still be sent + ## if the mouse moves within the dialog. We don't want to process those any longer at this point. + set the dgTrackDragReorder of me to false + + if processTheDrop then + local theStartLine, theDroppedAfterLine, theDroppedOnLine + put the dgLineOfIndex[ theDropStructure["originating index"] ] of me into theStartLine + put max(0, the dgLineOfIndex[ theDropStructure["dropped after index"] ] of me) into theDroppedAfterLine + put theDroppedAfterLine into theDroppedOnLine + + if theDroppedAfterLine < theStartLine then add 1 to theDroppedOnLine + + dispatch "DragReorderDrop" with theDropStructure["originating index"], \ + theStartLine, theDroppedOnLine + end if +end dgDragDrop + + +## Sent from TrackDragDrop +on dgDragMove pMouseH,pMouseV + ## Throttle calls to this + if sRunningActionsA["drag move"] then return empty + + ## Make sure data grid control will accept drop + if the dragSource contains the long ID of me and (the mouseControl is not empty and the long id of the mouseControl contains the long ID of me) then + set the dragAction to "move" + end if + + put true into sRunningActionsA["drag move"] + try + _PositionDropIndicator pMouseH,pMouseV + + ## We can't send messages so hang out until mouseloc changes + repeat until (the mouseLoc is not pMouseH,pMouseV) or (mouse(1) is "up" and mouse(3) is "up") + ## Throttle calls to redrawing + if not sRunningActionsA["v scroll"] then + _ListGroupDragReorderAutoScroll pMouseH,pMouseV + _PositionDropIndicator pMouseH, pMouseV + end if + end repeat + catch e + end try + put false into sRunningActionsA["drag move"] +end dgDragMove + + +private function _VisibleDataRect + local theRect + put the rect of group "dgListMask" of me into theRect + if _ControlType() is "table" then + if the visible of scrollbar "dgScrollbar" of me then + put the left of scrollbar "dgScrollbar" of me into item 3 of theRect + else + put the right of group "dgHeaderComponents" of me into item 3 of theRect + end if + end if + + return theRect +end _VisibleDataRect + + +private command _PositionDropIndicator pMouseH, pMouseV + ----- + local i,theX,theY + local index, theIndex + local showDropIndicator, theDropIndicatorOffset + local theControl, theControlIndex + local theControlsToCheck + local theCorralRect + local theEndControl + local theHeight + local theSequence + local theStartControl + local theTargetControl + ----- + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the wholeMatches to true + put false into showDropIndicator + + if pMouseH,pMouseV is within _VisibleDataRect() then --the rect of group "dgListMask" of me then + put true into showDropIndicator + + if the mouseControl is not empty then + if not (the long ID of the mouseControl contains the long ID of me) then + put false into showDropIndicator ## control over the list but not part of the list + else + put the dgDataControl of the mouseControl into theTargetControl + + ## Check for drags in empty columns of tables. + if theTargetControl is empty then + if the target is not the name of scrollbar "dgScrollbar" of me then + ## Perhaps no column in clicked area or no mouse receiving controls in column + repeat for each line thePotentialControl in _ListOfVisibleControls() + local theRect + put the rect of thePotentialControl into theRect + if pMouseV >= item 2 of theRect and pMouseV <= item 4 of theRect then + put the dgIndex of thePotentialControl into theIndex + put thePotentialControl into theTargetControl + exit repeat + end if + end repeat + end if + + ## Still no control + ## Assume we are below the last control + if theTargetControl is empty then + put the last line of _ListOfVisibleControls() into theTargetControl ## explicitly draw on only visible controls + end if + end if + + if theTargetControl is not empty then + + -- put true into showDropIndicator + + ## Determine offset of control in list + put _LineNoOfControlInListControls(theTargetControl, the dgColumn of theTargetControl) into theControlIndex + -- put "ControlIndex:" && theControlIndex + + ## Look for next/prev control that is not filtered out + ## Direction we look depends on position of mouse + ## relative to Y of control + put item 2 of the loc of theTargetControl into theY + + ## Look for start/end controls in our drop + if the dgAcceptsDrop of theTargetControl is false then + ## Look for next control that accepts a drop + put line theControlIndex to -1 of sTableObjectsA["visible row controls"] into theControlsToCheck + repeat for each line theControl in theControlsToCheck + if the dgAcceptsDrop of theControl is false then next repeat + else + put theControl into theEndControl + exit repeat + end if + end repeat + + ## Look for preceding control that accepts a drop + repeat with i = theControlIndex down to 1 + put line i of sTableObjectsA["visible row controls"] into theControl + if the dgAcceptsDrop of theControl is false then next repeat + else + put theControl into theStartControl + exit repeat + end if + end repeat + else + put theTargetControl into theStartControl + put theTargetControl into theEndControl + end if + + ## What is height of drop area as defined by start/end controls? + if theStartControl is empty and theEndControl is empty then + ## No drop. Hide the drop indicator + put false into showDropIndicator + else + if theStartControl is empty then put theEndControl into theStartControl + else if theEndControl is empty then put theStartControl into theEndControl + + put the bottom of theEndControl - the top of theStartControl into theHeight + if pMouseV < (the top of theStartControl + round(theHeight / 2)) then + ## if start/end control are same OR the mouse is above theStartControl then use + ## the top of control as reference + if theStartControl is theEndControl or pMouseV < the top of theStartControl then + put the top of theStartControl into theY + put the dgIndex of theStartControl into theIndex + put itemOffset(theIndex, sIndexSequencing) into theSequence + put max(item (theSequence - 1) of sIndexSequencing, 0) into sDropStructure["dropped after index"] + else + put the bottom of theStartControl into theY + put the dgIndex of theStartControl into sDropStructure["dropped after index"] + end if + else + ## If start/end control are same OR the mouse below theEndControl then use + ## bottom of control as reference + if theEndControl is theStartControl or pMouseV > the bottom of theEndControl then + put the bottom of theEndControl into theY + put the dgIndex of theEndControl into sDropStructure["dropped after index"] + else + put the top of theEndControl into theY + put the dgIndex of theEndControl into theIndex + put itemOffset(theIndex, sIndexSequencing) into theSequence + put max(item (theSequence - 1) of sIndexSequencing, 0) into sDropStructure["dropped after index"] + end if + end if + + ## Position drop indicator + put _VisibleDataRect() into theCorralRect + put (item 4 of sDefaultDropIndicatorRect - item 2 of sDefaultDropIndicatorRect) / 2 div 1 into theDropIndicatorOffset ## div 1 = floor + + lock screen + lock messages + put item 1 of sDefaultDropIndicatorRect into theX + put min(item 4 of theCorralRect, max(item 2 of theCorralRect - theDropIndicatorOffset, theY)) into theY ## don't let outside of the List group + put theY - theDropIndicatorOffset into theY + set the topLeft of group "dgDropIndicator" of me to theX, theY + set the visible of group "dgDropIndicator" of me to true + unlock messages + dispatch "PositionDropIndicator" to group "dgDropIndicator" of me + unlock screen + end if + end if + end if ## mousecontrol is part of list group control + else + ## mousecontrol is empty + end if + + end if ## within rect of list + + set the lockMessages to msgsAreLocked + + if not showDropIndicator then + set the visible of group "dgDropIndicator" of me to false + end if +end _PositionDropIndicator + + +private function _LineNoOfControlInListControls pControl, pColumn + ----- + local theLineNo = 0 + local theListControl + local i + ----- + if _ControlType() is "form" then + repeat for each line theListControl in sTableObjectsA["visible row controls"] + add 1 to i + ## We use this technique so that the developer can have uListConrol return a child of the actual list control + ## Useful when a record can have more than one possible view. + if pControl ends with theListControl then + put i into theLineNo + exit repeat + end if + end repeat + else + local theShortID + put the short ID of pControl into theShortID + repeat for each line theListControl in sTableObjectsA["columns"][ pColumn ]["row controls"] + add 1 to i + ## We use this technique so that the developer can have uListConrol return a child of the actual list control + ## Useful when a record can have more than one possible view. + if word 3 of theListControl is theShortID then + put i into theLineNo + exit repeat + end if + end repeat + end if + + return theLineNo +end _LineNoOfControlInListControls + + +private command _ListGroupDragReorderAutoScroll pMouseH, pMouseV + local theMaskRect + + put the rect of group "dgListMask" of me into theMaskRect + + ## Check that mouse is within vertical space of group + if pMouseH > item 1 of theMaskRect and pMouseH < item 3 of theMaskRect then + local theAvailHeight, theScroll, theHotZone, theDiff + + put item 4 of theMaskRect - item 2 of theMaskRect into theAvailHeight + put round(theAvailHeight * .1) into theScroll + + ## Decide the zone where auto scrolling will occur + if the dgProps["fixed row height"] of me then + put round(sControlHeights / 2) into theHotZone + else + put 20 into theHotZone ## 20 is arbitrary number + end if + + ## First check above + put item 2 of theMaskRect - pMouseV into theDiff + if theDiff > 0 and theDiff <= theHotZone then + put theDiff * -1 into theDiff + -- put (theHotZone - theDiff) * -1 into theDiff ## This speeds up scrolling too much + else + put pMouseV - item 4 of theMaskRect into theDiff + -- put item 4 of theMaskRect - pMouseV into theDiff + if theDiff > 0 and theDiff <= theHotZone then + -- put (theHotZone - theDiff) into theDiff + else + put 0 into theDiff + end if + end if + + if abs(theDiff) > 0 and abs(theDiff) <= theHotZone then + local theCurrentScroll + + ## Mouse is in a hot zone; auto scroll. + put round((theDiff * 5) / 100 * theScroll) into theScroll + put the dgVScroll of me into theCurrentScroll + put theCurrentScroll + theScroll into theScroll + _SetVScroll theScroll + end if + end if +end _ListGroupDragReorderAutoScroll + + +on scrollbarDrag pScrollValue + if the long ID of the target is the long ID of scrollbar "dgScrollbar" of me then + dgScrollbarDragV pScrollValue + else if the long ID of the target is the long ID of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me then + dgScrollbarDragH pScrollValue + else + pass "scrollbarDrag" + end if +end scrollbarDrag + + +command dgScrollbarDragV pScrollValue + _ScrollListV pScrollValue +end dgScrollbarDragV + + +command dgScrollbarDragH pScrollValue + _ScrollListH pScrollValue +end dgScrollbarDragH + + +before arrowKey pDirection + dgArrowKey pDirection + pass arrowkey + -- if the result then pass arrowkey +end arrowKey + + +command dgArrowKey pDirection + ## Look for cases where we pass arrowkey + if the selectedField is not empty and not the lockText of the selectedField then return true + if the dgProps["auto hilite"] of me is false then return true + + ## Don't let queue of key repeats build up or list might keep scrolling after user releases arrow key + ## Mac needs 'autokey'. Windows needs 'keyDown'. + get flushEvents("autokey") + get flushEvents("keyDown") + + local theSelectionChanged + put false into theSelectionChanged + + lock screen + + if sHilitedIndexes is not empty then + set the wholeMatches to true + local thePreviouslyHilitedIndexes + put sHilitedIndexes into thePreviouslyHilitedIndexes + + switch pDirection + case "up" + local theItemNo + put itemOffset(item 1 of sHilitedIndexes, sIndexSequencing) into theItemNo + + if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then + if theItemNo > 1 then + local theNewIndex + put max(1, item (theItemNo - 1) of sIndexSequencing) into theNewIndex + put itemOffset(theNewIndex, thePreviouslyHilitedIndexes) into theItemNo + if theItemNo is 0 then + put comma & theNewIndex after thePreviouslyHilitedIndexes + set the dgHilitedIndexes of me to thePreviouslyHilitedIndexes + put true into theSelectionChanged + end if + end if + else + put max(1, item (theItemNo - 1) of sIndexSequencing) into theNewIndex + if theItemNo > 1 then + set the dgHilitedIndexes of me to theNewIndex + put true into theSelectionChanged + else if theItemNo is 1 and sHilitedIndexes is not theNewIndex then + ## Case for multiple selections going all the way to top + set the dgHilitedIndexes of me to item 1 of sIndexSequencing + put true into theSelectionChanged + end if + end if + break + + case "down" + put itemOffset(the last item of sHilitedIndexes, sIndexSequencing) into theItemNo + + if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then + if theItemNo > 0 and theItemNo < the number of items of sIndexSequencing then + put item (theItemNo + 1) of sIndexSequencing into theNewIndex + put itemOffset(theNewIndex, thePreviouslyHilitedIndexes) into theItemNo + if theItemNo is 0 then + put comma & theNewIndex after thePreviouslyHilitedIndexes + put _SortIndexesSequentially(thePreviouslyHilitedIndexes) into thePreviouslyHilitedIndexes + put thePreviouslyHilitedIndexes into sHilitedIndexes + ScrollIndexIntoView theNewIndex + _HiliteIndexesInVisibleControls + put true into theSelectionChanged + end if + end if + else + local theIndexCount + put the number of items of sIndexSequencing into theIndexCount + put item (theItemNo + 1) of sIndexSequencing into theNewIndex + if theItemNo > 0 and theItemNo < theIndexCount then + set the dgHilitedIndexes of me to theNewIndex + put true into theSelectionChanged + else if theItemNo is theIndexCount and sHilitedIndexes is not theNewIndex then + ## Case for multiple selections going all the way to bottom + set the dgHilitedIndexes of me to the last item of sIndexSequencing + put true into theSelectionChanged + end if + end if + break + end switch + + else if the dgNumberOfRecords of me > 0 then + set the dgHilitedIndexes of me to 1 + end if + + if theSelectionChanged then _SelectionChanged thePreviouslyHilitedIndexes + + unlock screen + + return false +end dgArrowKey + + +## Scrolls the group vertically when using the scroll wheel +before rawKeyDown pKeyNum + ## exit immediately if an editable field is the target and action isn't scroll wheel. + set the wholeMatches to true + if word 1 of the target is "field" and not the lockText of the target and pKeyNum is not among the items of "65308,65309,65310,65311" then pass rawkeydown + + -- 65308 - Mouse wheel down + -- 65309 - Mouse wheel up + -- 65310 - Mouse wheel right + -- 65311 - Mouse wheel left + -- 65365 - page up + -- 65366 - page down + -- 65360 - home + -- 65367 - end + + ## Note: Messages are locked when setting thumbpostion and we call scrolling code directly. + ## This is done so that scrolling works when scrollbars are hidden. + switch pKeyNum + case "65360" + ## home + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + _SetVScroll 0 + end if + break + case "65367" + ## end + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + _SetVScroll the endValue of scrollbar "dgScrollbar" of me + end if + break + case "65365" + ## scroll page up + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + _SetVScroll the thumbPosition of scrollbar "dgScrollbar" of me - \ + the pageIncrement of scrollbar "dgScrollbar" of me + end if + break + case "65366" + ## scroll page down + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + _SetVScroll the thumbPosition of scrollbar "dgScrollbar" of me + \ + the pageIncrement of scrollbar "dgScrollbar" of me + end if + break + case "65309" # scroll up + ## mouse wheel up + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + local theAvailHeight + put the height of group "dgListMask" of me into theAvailHeight + + local theScroll + put round(theAvailHeight * .1) into theScroll + _SetVScroll round(the thumbPosition of scrollbar "dgScrollbar" of me) - theScroll + end if + break + case "65308" # scroll down + ## mouse wheel down + if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then + put the height of group "dgListMask" of me into theAvailHeight + put round(theAvailHeight * .1) into theScroll + _SetVScroll round(the thumbPosition of scrollbar "dgScrollbar" of me) + theScroll + end if + break + case "65310" + ## mouse wheel right + if _ControlType() is "table" and (the visible of group "dgHorizontalComponents" of me or the dgProps["scroll when hScrollbar is hidden"] of me) then + local theAvailWidth + put the width of group "dgList" of me into theAvailWidth + put round(theAvailWidth * .1) into theScroll + _SetHScroll round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) + theScroll + end if + break + case "65311" + ## mouse wheel left + if _ControlType() is "table" and (the visible of group "dgHorizontalComponents" of me or the dgProps["scroll when hScrollbar is hidden"] of me) then + put the width of group "dgList" of me into theAvailWidth + put round(theAvailWidth * .1) into theScroll + _SetHScroll round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) - theScroll + end if + break + default + pass rawKeyDown + end SWITCH +end rawKeyDown + + +before mouseDown pMouseBtnNum + // Mikey-2015-05-19: [[ Bug 15387 ]] Don't send dgMouseDown on mobile on mouseUp + if the environment is "mobile" then exit mouseDown + dgMouseDown pMouseBtnNum + pass mousedown +end mouseDown + +// Mikey-2015-05-19: [[ Bug 15387 ]] Use touchStart for mobile +before touchStart + dgMouseDown 1 + pass touchStart +end touchStart + + +getprop dgClickLine + local theIndex + put the dgClickIndex of me into theIndex + if theIndex > 0 then return the dgLineOfIndex[theIndex] of me + else return empty +end dgClickLine + + +getprop dgClickIndex + ## figure out the index clicked on + local theIndex, theControl + put empty into theIndex + put _RowControlClickedOn() into theControl + + if theControl is not empty then + put the dgIndex of theControl into theIndex + end if + return theIndex +end dgClickIndex + + +getprop dgClickedInDataView + ## Note that Rev doesn't report scrollbars as mousecontrol if thumb is not + ## showing. Hence the checks for visibility and click not within of vertical scrollbar + ## (dglist overlaps with rect of vertical scrollbar) + local theClickLoc + put the clickLoc into theClickLoc + return theClickLoc is within the rect of group "dgListMask" of me \ + and (not the visible of scrollbar "dgScrollbar" of me \ + or (the visible of scrollbar "dgScrollbar" of me and theClickLoc is not within the rect of scrollbar "dgScrollbar" of me)) +end dgClickedInDataView + + +private function _RowControlClickedOn + local theControl + + ## figure out the index clicked on + put the dgDataControl of the target into theControl + + local theY, theRect + ## Make sure user clicked in valid area. + if theControl is empty and the dgClickedInDataView of me then + ## Perhaps no column in clicked area or no mouse receiving controls in column + put the clickV into theY + repeat for each line thePotentialControl in _ListOfVisibleControls() + put the rect of thePotentialControl into theRect + if theY >= item 2 of theRect and theY <= item 4 of theRect then + put thePotentialControl into theControl + exit repeat + end if + end repeat + end if + + return theControl +end _RowControlClickedOn + + +command dgMouseDown pMouseBtnNum + ## figure out the index clicked on + local theIndex, theControl + put empty into theIndex + put _RowControlClickedOn() into theControl + if theControl is not empty then + put the dgIndex of theControl into theIndex + end if + + ## Bring focus into control. Do this before any possible exit points. + if theIndex is not empty then + ## Clicked on a control. Bring focus into control but away from scrollbar. + if the long ID of me is not in the long ID of the focusedObject or word 1 of the target is "scrollbar" or \ + (sFieldEditor is not empty and sFieldEditor is the long ID of the focusedObject) then + focus on graphic "dgBackground" of me + end if + else + ## clicked in space but no on list control + focus on graphic "dgBackground" of me + end if + + if the dgProps["auto hilite"] of me is false then return empty + + local theSelectionChanged + put false into theSelectionChanged + + local unlockTheScreen + put true into unlockTheScreen + + lock screen + set the wholeMatches to true + + ## Close field editor. Note: I don't think the target can ever be sFieldEditor + if sFieldEditor is not empty and the long ID of the target is not sFieldEditor then + DeleteFieldEditor true + end if + + ## No do what we need to do + if theIndex is not empty then + local theHilitedIndexes, thePreviouslyHilitedIndexes + put sHilitedIndexes into theHilitedIndexes + put sHilitedIndexes into thePreviouslyHilitedIndexes + + if pMouseBtnNum is 1 then + // Mikey-2015-05-19: [[ Bug 15240 ]] for mobile, if "multiple lines", then every tap selects/deselects a line + if (_IsThisModifierSetActive("command") or the environment is "mobile") and the dgProps["multiple lines"] of me then + ## Add or remove hilite + local theItemNo + put itemOffset(theIndex, theHilitedIndexes) into theItemNo + if theItemNo > 0 then + delete item theItemNo of theHilitedIndexes + else + put theIndex into item (the number of items of theHilitedIndexes + 1) of theHilitedIndexes + ScrollIndexIntoView theIndex + end if + put _SortIndexesSequentially(theHilitedIndexes) into theHilitedIndexes + ## At this point we want to hilite controls but not scroll them + put theHilitedIndexes into sHilitedIndexes + _HiliteIndexesInVisibleControls + put true into theSelectionChanged + + ## Update reference for shift clicking + if theHilitedIndexes is empty then + put empty into sFirstIndexClickedWithShiftKeyDown + else if the number of items of theHilitedIndexes is 1 then + put theIndex into sFirstIndexClickedWithShiftKeyDown + end if + + else if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then + if theHilitedIndexes is empty then put theIndex into theHilitedIndexes + + if sFirstIndexClickedWithShiftKeyDown is empty then + ## If no first index has been logged then index becomes first index + put theIndex into sFirstIndexClickedWithShiftKeyDown + end if + + local theIndexItemNo, theShiftKeyIndexItemNo + put itemOffset(theIndex, sIndexSequencing) into theIndexItemNo + put itemOffset(sFirstIndexClickedWithShiftKeyDown, sIndexSequencing) into theShiftKeyIndexItemNo + + if theIndexItemNo < theShiftKeyIndexItemNo then + put item theIndexItemNo to theShiftKeyIndexItemNo of sIndexSequencing into theHilitedIndexes + else if theIndexItemNo > theShiftKeyIndexItemNo then + put item theShiftKeyIndexItemNo to theIndexItemNo of sIndexSequencing into theHilitedIndexes + else + put theIndex into theHilitedIndexes + end if + + put _SortIndexesSequentially(theHilitedIndexes) into theHilitedIndexes + put theHilitedIndexes into sHilitedIndexes + _HiliteIndexesInVisibleControls + put true into theSelectionChanged + + else + ## If clicking on a selected control then delay deselecting until mouseUp. + ## This allows for drag/drop of multi controls. + ## Only applies if not modifier is down. + if the dgProps["multiple lines"] of me and theIndex is among the items of sHilitedIndexes and _IsThisModifierSetActive("") then + put true into sDeselectOnMouseUp + else + unlock screen ## selectionChanged will be sent. Unlock so UI can update. + _SelectTargetControl theControl ## pass in since tables might not have control clicked on + put false into unlockTheScreen ## Don't unlock screen at end of handler. + end if + end if + + else if pMouseBtnNum is 3 then + ## right-click only changes selection if clicking on index that isn't highlighted + if theIndex is not among the items of theHilitedIndexes then + ## Same behavior as mouseclick 1 + ## single click always inserts index into first index var + put theIndex into sFirstIndexClickedWithShiftKeyDown + + put theIndex into sHilitedIndexes + _HiliteIndexesInVisibleControls + put true into theSelectionChanged + end if + end if + + ## moved to top in 1.0.0 b4 + -- ## Clicked on a control. Bring focus into control but away from scrollbar. + -- if the long id of me is not in the long id of the focusedobject or word 1 of the target is "scrollbar" or \ + -- (sFieldEditor is not empty and sFieldEditor is the long id of the focusedObject) then + -- focus on graphic "dgBackground" of me + -- end if + else + ## moved to top in 1.0.0 b4 + -- ## clicked in space but no on list control + -- focus on graphic "dgBackground" of me + end if + + if unlockTheScreen then unlock screen + + if theSelectionChanged then _SelectionChanged thePreviouslyHilitedIndexes +end dgMouseDown + + +before mouseUp pMouseBtnNum + // Mikey-2015-05-19: [[ Bug 15387 ]] Don't send dgMouseUp on mobile before mouseUp + if the environment is "mobile" then exit mouseUp + dgMouseUp pMouseBtnNum + pass mouseUp +end mouseUp + + +// Mikey-2015-05-19: [[ Bug 15387 ]] Use touchEnd on mobile +before touchEnd + dgMouseUp 1 + pass touchEnd +end touchEnd + + +on dgMouseUp pMouseBtnNum + if sDeselectOnMouseUp then + _SelectTargetControl + put false into sDeselectOnMouseUp + end if +end dgMouseUp + + +before mouseRelease pMouseBtnNum + dgMouseRelease pMouseBtnNum + pass mouseRelease +end mouseRelease + + +on dgMouseRelease pMouseBtnNum + put false into sDeselectOnMouseUp +end dgMouseRelease + + +--> Commands (Data Manipulation) + + +command SelectAll + local thePreviouslyHilitedIndexes, theOrigValue, theSelectionWasChanged + put sHilitedIndexes into thePreviouslyHilitedIndexes + + put the dgProps["scroll selections into view"] of me is not false into theOrigValue + set the dgProps["scroll selections into view"] of me to false + try + local theError + + set the dgHilitedIndexes of me to sIndexSequencing + put the result into theSelectionWasChanged + catch e + put e into theError + end try + set the dgProps["scroll selections into view"] of me to theOrigValue + + if theError is not empty then throw theError + + if theSelectionWasChanged then + _SelectionChanged thePreviouslyHilitedIndexes + end if +end SelectAll + + +function GetDataOfIndex pIndex, pKey + if pKey is not empty or pKey is an array then + return sDataArray[pIndex][pKey] + else + return sDataArray[pIndex] + end if +end GetDataOfIndex + + +command SetDataOfIndex pIndex, pKey, pValue + repeat with i = 2 to the paramcount + put param(i) into pKey + if pKey is not empty or pKey is an array then + put param(i+1) into sDataArray[pIndex][pKey] + else + put param(i+1) into sDataArray[pIndex] + end if + add 1 to i + end repeat + + _StorePersistentData + return empty +end SetDataOfIndex + + +function GetDataOfLine pLine, pKey + set the wholeMatches to true + return GetDataOfIndex(item pLine of sIndexSequencing, pKey) +end GetDataOfLine + + +command SetDataOfLine pLine, pKey, pValue + set the wholematches to true + + local theIndex + put item pLine of sIndexSequencing into theIndex + repeat with i = 2 to the paramcount + put param(i) into pKey + if pKey is not empty or pKey is an array then + put param(i+1) into sDataArray[theIndex][pKey] + else + put param(i+1) into sDataArray[theIndex] + end if + add 1 to i + end repeat + + _StorePersistentData + return empty +end SetDataOfLine + + +private command _DataCanBeRepresentedAsText pBoolean + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + set the dgProps["data can be represented as text"] of me to pBoolean is true + set the lockMessages to msgsAreLocked +end _DataCanBeRepresentedAsText + + +command EditCell pColumn, pLineNo + local theIndex + put the dgIndexOfLine[pLineNo] of me into theIndex + EditCellOfIndex pColumn, theIndex + if the result is not empty then + return "no control exists for line column" + else + return empty + end if +end EditCell + + +command EditCellOfIndex pColumn, pIndex + lock screen + ScrollIndexIntoView pIndex + + local theControl + put ColumnControlOfIndex(pColumn, pIndex) into theControl + + if _ControlType() is "table" then _table.ScrollColumnIntoView pColumn + + if theControl is not empty then + dispatch "EditValue" to theControl with pColumn + unlock screen + return empty + else + unlock screen + return "no control exists for index column" + end if +end EditCellOfIndex + + +command EditKey pKey, pLineNo + local theIndex + put the dgIndexOfLine[pLineNo] of me into theIndex + EditKeyOfIndex pKey, theIndex + if the result is not empty then + return "no control exists for line" + else + return empty + end if +end EditKey + + +command EditKeyOfIndex pKey, pIndex + lock screen + ScrollIndexIntoView pIndex + local theControl + put the dgDataControlOfIndex[pIndex] of me into theControl + + if theControl is not empty then + dispatch "EditValue" to theControl with pKey + unlock screen + return empty + else + unlock screen + return "no control exists for index" + end if +end EditKeyOfIndex + + +## Use to add data to the data array +command AddData pDataArray, pSequence + local theError + local theIndex + + set the wholeMatches to true + + _DataCanBeRepresentedAsText false + + put item 2 of the extents of sDataArray + 1 into theIndex + put pDataArray into sDataArray[theIndex] + + ## Add to list or setting sequence won't work well + put theIndex into item (the number of items of sIndexSequencing + 1) of sIndexSequencing + + if pSequence is not empty then + _SetSequenceOfIndex theIndex, pSequence + put the result into theError + end if + + if theError is empty then + _StorePersistentData + _ProcessNewIndexData theIndex + _RedrawList + else + ## Reset + delete item (itemOffset(theIndex, sIndexSequencing)) of sIndexSequencing + delete local sDataArray[theIndex] + end if + + if theError is empty then + return theIndex + else + return theError + end if +end AddData + + +command AddLine pText, pColumns, pLineNo + ----- + local theResult + ----- + switch _ControlType() + case "table" + _table.AddLine pText, pColumns, pLineNo + break + case "form" + default + _list.AddLine pText, pColumns, pLineNo + end switch + put the result into theResult + + if theResult is an integer then + ## Return line number + set the wholeMatches to true + return itemOffset(theResult, sIndexSequencing) + else + return theResult + end if +end AddLine + + +command DeleteLine pLine + -- Use the new DataGrid 2 animations for single deletes. + DeleteIndex the dgIndexOfLine[pLine] of me + return the result +end DeleteLine + + +command DeleteLines pLines + ----- + local theIndexes + local theLine + ----- + repeat for each item theLine in pLines + put the dgIndexOfLine [theLine] of me & comma after theIndexes + end repeat + delete the last char of theIndexes + DeleteIndexes theIndexes + return the result +end DeleteLines + + +command DeleteIndex pIndex + -- Use the new DataGrid 2 animations for single deletes. + if the dgProps["cache controls"] of me then + -- We need to send in time here as this handler could be potentially + -- be called from a control we are about to delete! + send "DG2_DeleteIndex" && pIndex to me in 0 seconds + return empty + else + DG2_DeleteIndex pIndex + return the result + end if +end DeleteIndex + + +command DeleteIndexes pIndexes + ----- + local theIndex + local theItemNo + local theLineNo + ----- + lock screen + set the wholeMatches to true + + ## Clear out any instances of this index + repeat for each item theIndex in pIndexes + put itemOffset(theIndex, sHilitedIndexes) into theItemNo + if theItemNo > 0 then + delete item theItemNo of sHilitedIndexes + end if + + ## Clear controls when cached + if the dgProps["cache controls"] of me then + if there is a sControlOfIndexA[theIndex] then + ## So that all updates happen on refresh + delete sControlOfIndexA[theIndex] + put lineOffset(sControlOfIndexA[theIndex], sTableObjectsA["all row controls"]) into theLineNo + if theLineNo > 0 then + delete line theLineNo of sTableObjectsA["all row controls"] + subtract 1 from sTableObjectsA["row control count"] + end if + put lineOffset(sControlOfIndexA[theIndex], sTableObjectsA["visible row controls"]) into theLineNo + if theLineNo > 0 then + delete line theLineNo of sTableObjectsA["visible row controls"] + end if + end if + end if + + put itemOffset(theIndex, sIndexSequencing) into theItemNo + if theItemNo > 0 then + delete item theItemNo of sIndexSequencing + + ## Update Formatted Height and UI if already calculated + if sFormattedHeight is not empty then + if the dgProps["fixed row height"] of me then + subtract sControlHeights from sFormattedHeight + else + subtract sControlHeights[theIndex] from sFormattedHeight + end if + end if + end if + + delete local sDataArray[theIndex] + end repeat + + _StorePersistentData + + if sFormattedHeight is not empty then + _ConfigureScrollbar + _AutoHideVScrollbar ## only works for fixed height + end if + + ## Count and position has changed. Update alternating rows. + _DrawAlternatingRows + + if the keys of sDataArray is not empty then + _RedrawList + else + _ResetData + end if + + unlock screen + + return empty +end DeleteIndexes + + +--> Commands (Sorting) + + +command SortDataByKey pKey, pType, pDirection, pCaseSensitive + ----- + local msgsAreLocked + local theIndex + local theData + local theDo + local theLine + ----- + if pType is not among the items of kSortTypes then put "text" into pType + if pDirection is not "descending" then put "ascending" into pDirection + + if pKey is empty then + sort items of sIndexSequencing numeric ascending + else + ## so we get a stable sort + repeat for each item theIndex in sIndexSequencing + -- repeat for each key theIndex in sDataArray + put theIndex & tab & line 1 of sDataArray[theIndex][pKey] & cr after theData + end repeat + delete the last char of theData + set the itemDelimiter to tab + + set the caseSensitive to pCaseSensitive is true + + if pType is "system datetime" then + set the useSystemDate to true + delete word 1 of pType + end if + + put "sort lines of theData" && pType && pDirection && "by item 2 to -1 of each" into theDo + do theDo + + put empty into sIndexSequencing + repeat for each line theLine in theData + put item 1 of theLine & comma after sIndexSequencing + end repeat + delete the last char of sIndexSequencing + end if + + _StorePersistentSequence + + lock screen + _ResetIndexesOnControls + _RedrawList + unlock screen + + return empty +end SortDataByKey + + +## Reverses order of current sequence of data +command ReverseSort pColumn + lock screen + + if sIndexSequencing is not empty then + local theNewSequence + repeat for each item theIndex in sIndexSequencing + put comma & theIndex before theNewSequence + end repeat + delete the first char of theNewSequence + put theNewSequence into sIndexSequencing + + _ResetIndexesOnControls + _RedrawList + end if + + if pColumn is not empty then + HiliteAndStoreSortByColumn pColumn + end if + + unlock screen + + return empty +end ReverseSort + + +command HiliteAndStoreSortByColumn pColumn + local msgsAreLocked + put the lockMessages into msgsAreLocked + unlock messages + + lock screen + + local theOldSortKey + put the dgProps["sort by column"] of me into theOldSortKey + + if theOldSortKey is not empty and there is a sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] then + set the dgHilite of sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] to false + dispatch "LayoutControl" to sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] \ + with the rect of sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] + end if + + if pColumn is not empty and there is a sTableObjectsA["columns"][ pColumn ]["header"]["group"] then + set the dgHilite of sTableObjectsA["columns"][ pColumn ]["header"]["group"] to true + dispatch "LayoutControl" to sTableObjectsA["columns"][ pColumn ]["header"]["group"] \ + with the rect of sTableObjectsA["columns"][ pColumn ]["header"]["group"] + end if + + lock messages + set the dgProps["sort by column"] of me to pColumn + unlock screen + set the lockMessages to msgsAreLocked +end HiliteAndStoreSortByColumn + + +## Used internally to dispatch the "SortDataGridColumn" message +private command _SortByColumn pColumn + lock screen + dispatch "SortDataGridColumn" to me with pColumn + if it is not "handled" then + SortByColumn pColumn + end if + unlock screen +end _SortByColumn + + +command SortByColumn pColumn + if _ControlType() is not "table" then _ThrowError kErrPropDoesntExist, "only tables can be sorted by columns" + + local theColPropsA + put the dgProps["column properties"] of me into theColPropsA + + if pColumn is not empty and pColumn is not among the keys of theColPropsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + + lock screen + + ## sort and hilite + SortDataByKey pColumn, theColPropsA[pColumn]["sort type"], \ + theColPropsA[pColumn]["sort direction"], theColPropsA[pColumn]["sort is case sensitive"] + + HiliteAndStoreSortByColumn pColumn + + unlock screen + + return empty +end SortByColumn + + +--> Commands (Control) + +local sResizingToFit +local sResendResizeToFit + + +command ResizeToFit + ----- + local theError + local theLockLoc + local theOffset + local theRect + ----- + ## Throttle just in case developer tries to call this from different timers + if sResizingToFit then + put true into sResendResizeToFit + return empty + end if + + put true into sResizingToFit + + lock screen + put the lockloc of me into theLockLoc + set the lockloc of me to true + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the lockMessages to true + + try ## Try so we don't leave group locked + ## Clear cache + put empty into sControlsRequiredToFillSpace + + put _WorkingGroupRect(the long ID of me) into theRect + + set the rect of button "dgEventCatcher" of me to theRect + set the rect of graphic "dgBackground" of me to theRect + + ## Account for table elements + if _ControlType() is "table" then + _table.LayoutDataArea + else + if the environment is not "mobile" then + if the visible of scrollbar "dgScrollbar" of me then + subtract the width of scrollbar "dgScrollbar" of me from item 3 of theRect + end if + if the visible of scrollbar "dgScrollbar" of me then + set the rect of scrollbar "dgScrollbar" of me to item 3 of theRect, \ + item 2 of theRect, item 3 of theRect + the width of scrollbar "dgScrollbar" of me, \ + item 4 of theRect - the dgProps["scrollbar corner offset"] of me + else + set the rect of scrollbar "dgScrollbar" of me to item 3 of theRect - the width of scrollbar "dgScrollbar" of me, \ + item 2 of theRect, item 3 of theRect, \ + item 4 of theRect - the dgProps["scrollbar corner offset"] of me + end if + else if __HasMobileScroller() then + mobileControlSet sScrollerId, "rect", theRect + end if + set the rect of group "dgListMask" of me to theRect + set the rect of group "dgAlternatingRowsMask" of me to theRect + set the topLeft of group "dgList" of me to item 1 to 2 of theRect ## Shift all children of group along with group + set the rect of group "dgList" of me to theRect + end if + + ## Redo calculations + if the dgProps["cache controls"] of me then + _ResizeCachedControls + else if sFormattedHeight is empty or not the dgProps["fixed row height"] of me then + # Only recalculate if not fixed height or formatted height hasn't been calculated + # since teal-time drawing adjusts rect every time anyway. + _CalculateFormattedHeight + else + _AutoHideVScrollbar ## only works for fixed height + end if + + _ConfigureScrollbar + _ConfigureHScrollbar + + _RedrawList + + catch e + put e into theError + -- put e + finally + set the lockloc of me to theLockLoc + end try + + set the lockMessages to msgsAreLocked + unlock screen + + put false into sResizingToFit + + if theError is not empty then throw theError + + if sResendResizeToFit then + send "ResizeToFit" to me in 0 seconds + put false into sResendResizeToFit + end if +end ResizeToFit + + +private command _DrawList + lock screen + + local weHaveSomethingToDraw + put the keys of sDataArray is not empty into weHaveSomethingToDraw + if weHaveSomethingToDraw and sFormattedHeight is empty then + if the dgProps["cache controls"] of me then + _CacheControls + else + _CalculateFormattedHeight + end if + end if + + ## Update column control cache each time drawing is specifically called + if _ControlType() is "table" then + _table.CacheCustomTemplateUsage + end if + + if weHaveSomethingToDraw then + _DrawListWithProperties empty, empty, true + _DrawAlternatingRows + _ShowAlternatingRows + + end if + + unlock screen +end _DrawList + + +command ResetList + dgResetList + return empty +end ResetList + + +/** +* \brief Allows developer to intercept ResetList and manually call code to reset. +* +* \return empty +*/ +command dgResetList + DG2_ClearVars + + lock screen + + ## For cases where user copied/pasted + if not sInit then _Initialize + + local theOrigVScroll, theOrigHScroll + put _GetVScrollPercent() into theOrigVScroll + put _GetHScrollPercent() into theOrigHScroll + _ResetScrollsToZero + + _DeleteControls + + _ResetInternalCaches + + if _ControlType() is "table" then + _table.CreateColumns + end if + + ResizeToFit + + _DrawAlternatingRows + _ShowAlternatingRows + + _SetHScrollPercent theOrigHScroll + _SetVScrollPercent theOrigVScroll + unlock screen + + return empty +end dgResetList + + +command RefreshList + if the keys of sDataArray is not empty then + if the dgProps["cache controls"] of me then + lock screen + _LayoutCachedControls + _RedrawList + unlock screen + else + _ResetIndexesOnControls + _RedrawList + end if + + _HiliteIndexesInVisibleControls + else + _ResetData + end if + + return empty +end RefreshList + + +on RefreshIndex pIndex + _RefreshIndexes pIndex +end RefreshIndex + + +command RefreshLine pLine + local theIndex + put the dgIndexOfLine [pLine] of me into theIndex + if theIndex > 0 then _RefreshIndexes theIndex +end RefreshLine + + +private command _ResetIndexesOnControls + switch _ControlType() + case "table" + lock messages + repeat for each line theColumn in the dgProps["columns"] of me + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"] + set the dgIndex of theControl to empty + end repeat + end repeat + unlock messages + break + + case "form" + default + if not the dgProps["cache controls"] of me then + lock messages + repeat for each line theControl in sTableObjectsA["all row controls"] + set the dgIndex of theControl to empty + end repeat + unlock messages + end if + end switch +end _ResetIndexesOnControls + + +private command _ResetControlsOfIndex pIndex + switch _ControlType() + case "table" + lock messages + repeat for each line theColumn in the dgProps["columns"] of me + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"] + if the dgIndex of theControl is pIndex then + set the dgIndex of theControl to empty + end if + end repeat + end repeat + unlock messages + break + + case "form" + default + ## Cached controls aren't drawing new data into the same controls so + ## we don't reset indexes on them. + if not the dgProps["cache controls"] of me then + lock messages + repeat for each line theControl in sTableObjectsA["all row controls"] + if the dgIndex of theControl is pIndex then + set the dgIndex of theControl to empty + end if + end repeat + unlock messages + end if + end switch +end _ResetControlsOfIndex + + +private command _RedrawList pVScrollPercent + ----- + local thePercent + ----- + + if the keys of sDataArray is not empty then + if pVScrollPercent is empty then + put _GetVScrollPercent() into pVScrollPercent + end if + local theVScroll + put round(pVScrollPercent * (the endValue of scrollbar "dgScrollbar" of me - the thumbSize of scrollbar "dgScrollbar" of me)) into theVScroll + + if sFormattedHeight is empty then + if the dgProps["cache controls"] of me then + _CacheControls + else + _CalculateFormattedHeight + end if + end if + + _ScrollListV theVScroll, true + _ShowAlternatingRows + else + _ShowAlternatingRows + end if + + return empty +end _RedrawList + + +command ScrollLineIntoView pLine + set the wholeMatches to true + ScrollIndexIntoView item pLine of sIndexSequencing +end ScrollLineIntoView + + +command ScrollIndexIntoView pIndex + local theError + + ## Work off of a 0 based rect, not actual position on card + local theMaskHeight, theOffset, theMaskRect + put the height of group "dgListMask" of me into theMaskHeight + + put the dgVScroll of me into theOffset -- round needed for engine bug + put "0," & theOffset & ",0," & theMaskHeight + theOffset into theMaskRect + + local theSequence + put the dgLineOfIndex[pIndex] of me into theSequence + if theSequence is 0 then put "index not found" into theError + + local theTopOfControl, theBottomOfControl, theFormattedHeight + if theError is empty then + ## Determine top and bottom of control + if the dgProps["fixed row height"] of me then + put (theSequence - 1) * sControlHeights into theTopOfControl + put theSequence * sControlHeights into theBottomOfControl + else + ## Random sized Controls + repeat for each item theIndex in sIndexSequencing + add sControlHeights[theIndex] to theFormattedHeight + + if pIndex is theIndex then + put theFormattedHeight - sControlHeights[theIndex] into theTopOfControl + put theFormattedHeight into theBottomOfControl + exit repeat + end if + end repeat + end if + + ## If index is off the top then scroll to top of group + ## else if index is off the bottom then scroll to the bottom + + ## We lock messages so no scrollbarDrag message is sent. scrollbarDrag may use a slight delay when + ## drawing so that fast scrolling doesn't cue up redraws. We bypass the message + ## and call _ScrollListV directly so that screen is updated immediately regardless of how + ## scrollbarDrag is finally implemented. + + -- ====================== + local scrollTheList, theNewVScroll, theControlIsAtLeastAsTallAsMask + put false into scrollTheList + + if theBottomOfControl <= item 2 of theMaskRect or theTopOfControl < item 2 of theMaskRect then + ## control is off the top of view OR top edge is clipped off + put theTopOfControl into theNewVScroll + put true into scrollTheList + + else if theTopOfControl >= item 4 of theMaskRect or theBottomOfControl > item 4 of theMaskRect then + ## control is off the bottom of view or bottom edge is clipped off + put theBottomOfControl - theMaskHeight into theNewVScroll + put true into scrollTheList + end if + + if scrollTheList then + ## If as tall as mask group then scroll top into view. + ## Otherwise follow regular rules + put theBottomOfControl - theTopOfControl >= theMaskHeight into theControlIsAtLeastAsTallAsMask + if theControlIsAtLeastAsTallAsMask then + put theTopOfControl into theNewVScroll + end if + + if the dgProps["animate selections"] of me and sPendingMsgsA["UpdateScrollAnimation"] is empty then + StartScrollAnimation theNewVScroll + else + cancel sPendingMsgsA["UpdateScrollAnimation"] + put empty into sPendingMsgsA["UpdateScrollAnimation"] + put false into sIsAnimating + + _SetVScroll theNewVScroll + end if + end if + end if + + return theError +end ScrollIndexIntoView + + +## See dgRectOfIndex in order to get rect of a control in the data grid. +command ScrollRectIntoView pRect, pPadding + ----- + local theItemNo + local theMaskRect + local theScrollToOffset, theVScroll + ----- + + if pPadding is an integer then + put pPadding & comma & pPadding & comma & pPadding into item 2 of pPadding + else if pPadding is not empty and pPadding is not a rect then + _ThrowError kErrInvalidRect, pPadding && "is not a valid margins value" + else if pPadding is empty then + put 0,0,0,0 into pPadding + end if + + ## Mask rect is rect of this group with vscroll taken into account + put the rect of group "dgListMask" of me into theMaskRect + + local theCurrentVScroll + put the dgVScroll of me into theCurrentVScroll + + ## left,right are ignored right now + add item 1 of pPadding to item 1 of theMaskRect + add item 2 of pPadding to item 2 of theMaskRect + subtract item 3 of pPadding from item 3 of theMaskRect + subtract item 4 of pPadding from item 4 of theMaskRect + + ## If mask height is less than rect height than we focus on top of pRect. + ## Otherwise we focus on bottom of pRect. + if item 4 of theMaskRect - item 2 of theMaskRect < item 4 of pRect - item 2 of pRect then + put 2 into theItemNo + put item 4 of theMaskRect - item 2 of theMaskRect into theScrollToOffset + else + put 4 into theItemNo + put 0 into theScrollToOffset + end if + + -- Debugging + -- put "theMaskRect:" && theMaskRect & cr & \ + -- "pRect:" && pRect & cr & \ + -- "theItemNo:" && theItemNo & cr & \ + -- "theScrollToOffset:" && theScrollToOffset & cr & \ + -- "theCurrentVScroll:" && theCurrentVScroll + + if _RectIsAtLeastAsTallAsMask(pRect, theMaskRect) then + if _RectCoversMask(pRect, theMaskRect) then + ## Rect covers entire visible area. Do nothing. + else + ## If rect top or bottom is visible then do nothing. Otherwise scroll top in. + if _TopIsVisible(pRect, theMaskRect) or _BottomIsVisible(pRect, theMaskRect) then + ## Nothing + else + ## Scroll up to top of control + put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll + end if + end if + else if _TopIsClipped(pRect, theMaskRect) then + ## Scroll up to top of control + put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll + + else if _BottomIsClipped(pRect, theMaskRect) then + ## scroll down to bottom of control + put theCurrentVScroll - (item 4 of theMaskRect - item theItemNo of pRect) into theVScroll + add theScrollToOffset to theVScroll + + else if _TopAndBottomAreClipped(pRect, theMaskRect) then + if item 2 of pRect >= item 4 of theMaskRect then + ## scroll down so bottom to bottom of control + put theCurrentVScroll - (item 4 of theMaskRect - item theItemNo of pRect) into theVScroll + add theScrollToOffset to theVScroll + else + ## scroll up to top of control + put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll + end if + end if + + if theVScroll is not empty then + if the dgProps["animate selections"] of me then + StartScrollAnimation theVScroll + else + set the dgVScroll of me to theVScroll + end if + end if +end ScrollRectIntoView + + +command ResetControl + lock screen + try + ## So we don't confuse the engine + if the long ID of me is in the long ID of the focusedObject then focus on graphic "dgBackground" of me + + _DeleteControls + _ResetData + + if _ControlType() is "table" then + _table.RegenerateColumns + end if + catch e + put e + end try + unlock screen + + return empty +end ResetControl + + +-- Resets all controls in the data grid +private command _ResetAllControls + lock screen + local theControls + if _ControlType() is "table" then + repeat for each key theColumn in sTableObjectsA["columns"] + if sTableObjectsA["columns"][theColumn]["row controls"] is not empty then + put sTableObjectsA["columns"][theColumn]["row controls"] & cr after theControls + end if + end repeat + delete the last char of theControls + else + put sTableObjectsA["all row controls"] into theControls + end if + + local theCleansedControls + ## Make sure controls exist + repeat for each line theControl in theControls + if there is a theControl then + put theControl & cr after theCleansedControls + end if + end repeat + + _ResetControls theCleansedControls + + put empty into sTableObjectsA["current"] + + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", 0 + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to 0 + set the lockMessages to msgsAreLocked + unlock screen +end _ResetAllControls + + +private command _ResetScrollbarsAndRows + ## This will call scrollbardrag. We set all structures before this happens. + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", 0 + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to 0 + if _ControlType() is "table" then + if __HasMobileScroller() then + mobileControlSet sScrollerId, "hScroll", 0 + end if + set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0 + end if + + _ConfigureScrollbar + _ConfigureHScrollbar + + if the dgProps["fixed row height"] of me then + _AutoHideVScrollbar ## only works for fixed height + end if + + _DrawAlternatingRows + _ShowAlternatingRows +end _ResetScrollbarsAndRows + + +-- Send ResetControl message to any controls that aren't visible. +-- Reset dgIndex +private command _ResetControls pControls + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + ## Hide any controls in "all row controls" that aren't part of "visible list controls" + repeat for each line theControl in pControls + if the visible of theControl then + dispatch "ResetData" to theControl + set the visible of theControl to false + set the dgIndex of theControl to empty + end if + end repeat + + set the lockMessages to msgsAreLocked +end _ResetControls + + +private command _ResetData + + ## In case developer redraws while editor is open + DeleteFieldEditor true + + lock screen + ## So we don't confuse the engine + if the long ID of me is in the long ID of the focusedObject then focus on graphic "dgBackground" of me + + ## Time intensive start + -- _ResetAllControls + _DeleteDataControls ## Replaced with above in 1.0.2 build 6. No more errors when deleting control running script! + + put empty into sDataArray + ## time intensive end + put empty into sIndexSequencing + + _StorePersistentData + + _ResetInternalCaches + _DataCanBeRepresentedAsText true + + ## This will call scrollbardrag. We set all structures before this happens. + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", 0 + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to 0 + if _ControlType() is "table" then + if __HasMobileScroller() then + mobileControlSet sScrollerId, "hScroll", 0 + end if + set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0 + end if + + _ConfigureScrollbar + _ConfigureHScrollbar + + if the dgProps["fixed row height"] of me then + _AutoHideVScrollbar ## only works for fixed height + end if + + _DrawAlternatingRows + _ShowAlternatingRows + + unlock screen +end _ResetData + + +private command _ResetInternalCaches + put empty into sControlOfIndexA + put empty into sControlHeights + put empty into sFormattedHeight + put empty into sHilitedIndexes + put empty into sControlsRequiredToFillSpace + put empty into sFirstIndexClickedWithShiftKeyDown + put empty into sDeselectOnMouseUp +end _ResetInternalCaches + + +--> Commands (Find) + +## pKey can be a string or an array keyed index. +function GetKeyValuesOfIndexes pIndexes, pDelimiter, pKey --, ... + local theIndex,theValues + + if pDelimiter is empty then put comma into pDelimiter + + local theParamCount, theDelimLength + put the paramCount into theParamCount + put length(pDelimiter) into theDelimLength + + repeat for each item theIndex in pIndexes + repeat with i = 3 to theParamCount + put sDataArray[theIndex][param(i)] & pDelimiter after theValues + end repeat + delete char -theDelimLength to -1 of theValues + put cr after theValues + end repeat + delete the last char of theValues + return theValues +end GetKeyValuesOfIndexes + + +## pSearchA is array-valued index for accessing sDataArray +## pSearchA[1] = key_1 +## pSearchA[2] = key_2 +command FindIndex pKeyIndexA, pSearchString --, ... + ----- + local foundAMatch, theFoundIndex + local i + local theIndex + ----- + + repeat for each key theIndex in sDataArray + ## Developer can pass in multiple search strings to perform an AND search + repeat with i = 1 to the paramCount step 2 + if sDataArray[theIndex][param(i)] is param(i+1) then + put true into foundAMatch + else + put false into foundAMatch + end if + + ## AND search didn't pan out. Move on to next index. + if not foundAMatch then exit repeat + end repeat + + if foundAMatch then + put theIndex into theFoundIndex + exit repeat + end if + end repeat + + return max(0, theFoundIndex) +end FindIndex + + +command FindLine pKeyIndexA, pSearchString + ----- + local theIndex + ----- + FindIndex pKeyIndexA, pSearchString + put the result into theIndex + if theIndex > 0 then + return the dgLineOfIndex[theIndex] of me + else + return 0 + end if +end FindLine + + +--> Type: Template Handlers + + +private command _ToggleVScrollBarVisibility pBoolean + lock screen + set the visible of scrollbar "dgScrollbar" of me to pBoolean + + switch _ControlType() + case "table" + local theOrigHScroll + put _GetHScrollPercent() into theOrigHScroll + _ResetHScrollToZero + _AutoHideHScrollbar + + _table.LayoutDataArea + _table.RepositionHeaders + + _ConfigureHScrollbar + RefreshList + _SetHScrollPercent theOrigHScroll + break + + case "form" + default + local theRect + put the rect of group "dgList" of me into theRect + if the visible of scrollbar "dgScrollbar" of me then + put the left of scrollbar "dgScrollbar" of me into item 3 of theRect + else + put the right of scrollbar "dgScrollbar" of me into item 3 of theRect + end if + + set the rect of group "dgListMask" of me to theRect + set the rect of group "dgList" of me to theRect + set the rect of group "dgAlternatingRowsMask" of me to theRect + + if not the dgProps["fixed row height"] of me then + _CalculateFormattedHeight + end if + + RefreshList + end switch + unlock screen +end _ToggleVScrollBarVisibility + + +private command _ToggleHScrollBarVisibility pBoolean + lock screen + ## todo: can we only perform actions if visible of scrollbar is different than pBoolean? + set the visible of group "dgHorizontalComponents" of me to pBoolean + + switch _ControlType() + case "table" + local theOrigVScroll + put _GetVScrollPercent() into theOrigVScroll + _ResetVScrollToZero + + _table.LayoutDataArea + + local theSetting + put the visible of scrollbar "dgScrollbar" of me into theSetting + _AutoHideVScrollbar + if the visible of scrollbar "dgScrollbar" of me is not theSetting then + _table.LayoutDataArea + end if + + _ShowAlternatingRows + _ConfigureScrollbar + RefreshList + + _SetVScrollPercent theOrigVScroll + break + case "form" + default + end switch + unlock screen +end _ToggleHScrollBarVisibility + + +private command _DrawListWithProperties pStartingSequence, pSetVScrollTo, pForceRefresh, pCallback, pCallbackContext + lock screen + + ## For cases where user copied/pasted + if not sInit then _Initialize + + DeleteFieldEditor + + local theControl + put the long ID of the focusedObject into theControl + + local msgsAreLocked, theStart + put the lockMessages into msgsAreLocked + put the milliseconds into theStart + + if pStartingSequence is not an integer or pStartingSequence < 1 then put 1 into pStartingSequence + if pSetVScrollTo is not an integer then put 0 into pSetVScrollTo + + ## Store sequence that visible controls start drawing from + put pStartingSequence into sTableObjectsA["base sequence for visible controls"] + + switch _ControlType() + case "table" + _table.DrawWithProperties pSetVScrollTo, pForceRefresh + break + case "form" + default + _list.DrawWithProperties pSetVScrollTo, pForceRefresh, pCallback, pCallbackContext + end switch + + ## Make sure focus stays with us + if the long ID of me is in theControl then + lock messages + if there is not a theControl then + ## [[ FocusRedraw ]] Make sure focus is only changed if the target is + ## not already focused. + if the long id of the focusedObject is not the long id of graphic "dgBackground" of me then + focus on graphic "dgBackground" of me + end if + else + ## [[ FocusRedraw ]] Make sure focus is only changed if the target is + ## not already focused. + if the long id of the focusedObject is not theControl then + focus on theControl + end if + end if + unlock messages + end if + + -- put "time spent in" && param(0) & ":" && the milliseconds - theStart & cr after msg + + unlock screen + set the lockMessages to msgsAreLocked + -- put "time spent in" && param(0) & ":" && the milliseconds - theStart & cr after msg +end _DrawListWithProperties + +private command _DeleteControls + local i,theControl,msgsAreLocked + + lock screen + + switch _ControlType() + case "table" + _table.DeleteColumnControls + break + case "form" + default + end switch + + _DeleteDataControls + _ResetScrollsToZero + + ## In case one gets left around + if there is a field kFieldEditorName of group "dgListMask" of me then + put the lockMessages into msgsAreLocked + lock messages + delete field kFieldEditorName of group "dgListMask" of me + set the lockMessages to msgsAreLocked + end if + + unlock screen +end _DeleteControls + + +private command _DeleteDataControls + lock screen + + switch _ControlType() + case "table" + _table.DeleteDataControls + break + case "form" + default + _list.DeleteControls + end switch + + put empty into sTableObjectsA["current"] + put 0 into sTableObjectsA["row control count"] + + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", 0 + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to 0 + set the lockMessages to msgsAreLocked + unlock screen +end _DeleteDataControls + + +private command _CalculateFormattedHeight + put empty into sControlHeights + put 0 into sFormattedHeight + if item 2 of line 1 of the extents of sDataArray < 1 then + put kDefaultRowHeight into sControlHeights + return empty + end if + + lock screen + + switch _ControlType() + case "table" + _table.CalculateFormattedHeight + break + case "form" + default + _list.CalculateFormattedHeight + end switch + + _ConfigureScrollbar + _AutoHideVScrollbar ## only works for fixed height + + unlock screen +end _CalculateFormattedHeight + + +## Makes sure that enough controls exist to fill up the visible space +## Returns true if the number of controls required to display all records increased. +private command _FillListWithJustEnoughControls + lock screen + + switch _ControlType() + case "table" + _table.FillListWithJustEnoughControls + break + case "form" + default + _list.FillListWithJustEnoughControls + end switch + local theControlCountChanged + put the result into theControlCountChanged + + unlock screen + + return theControlCountChanged +end _FillListWithJustEnoughControls + + +private command _HiliteIndexesInVisibleControls + switch _ControlType() + case "table" + _table.HiliteIndexesInVisibleControls + break + case "form" + default + _list.HiliteIndexesInVisibleControls + end switch +end _HiliteIndexesInVisibleControls + + +private command _UpdateHiliteColor + lock screen + + if _ControlType() is "table" then + _table.LayoutRowHilites ## changes colors + end if + + _HiliteIndexesInVisibleControls + unlock screen +end _UpdateHiliteColor + + +--> Type: List + + +private function _list.GetText pIncludeKeys + ----- + local theIndex + local theKey + local theKeys + local theText + ----- + put the keys of sDataArray[item 1 of sIndexSequencing] into theKeys + sort lines of theKeys + + if pIncludeKeys then + put theKeys into theText + replace cr with tab in theText + put cr after theText + end if + + repeat for each item theIndex in sIndexSequencing + repeat for each line theKey in theKeys + put sDataArray[theIndex][theKey] & tab after theText + end repeat + put cr into the last char of theText + end repeat + delete the last char of theText + return theText +end _list.GetText + + +private command _list.SetText pText, pKeys + ----- + local theColNum + local theDataA + local theItem + local theLine + local theSequencing + ----- + lock screen + set the itemDelimiter to tab + + if pKeys is not empty then + ## Developer specified item to key mapping + local theColCount, theColLookupA + put the number of lines of pKeys into theColCount + + put 0 into theColNum + repeat for each line theColumn in pKeys + add 1 to theColNum + put theColumn into theColLookupA[theColNum] + end repeat + + local theRow + repeat for each line theLine in pText + add 1 to theRow + put 0 into theColNum + put theRow & comma after theSequencing + if theLine is empty then + ## Fill in empty records for empty lines + repeat for each line theColumn in pKeys + put empty into theDataA[theRow][theColumn] + end repeat + else + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[theRow][ theColLookupA[theColNum] ] + if theColNum is theColCount then exit repeat + end repeat + end if + end repeat + + else + ## No columns provided. We just create columns named "Label COL_NUM" + repeat for each line theLine in pText + add 1 to theRow + put 0 into theColNum + put theRow & comma after theSequencing + if theLine is empty then + ## Fill in empty value for one key + put empty into theDataA[theRow][ "Label 1"] + else + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[theRow][ "Label" && theColNum ] + end repeat + end if + end repeat + end if + delete the last char of theSequencing + + set the dgData [theSequencing] of me to theDataA + + unlock screen + return empty +end _list.SetText + + +private command _list.AddLine pText, pKeys, pLineNo + ----- + local theColNum + local theDataA + local theItem + local theLine,theResult + ----- + lock screen + set the itemDelimiter to tab + + if pKeys is not empty then + ## Developer specified mapping of data to keys + local theColCount, theColLookupA + put the number of lines of pKeys into theColCount + + put 0 into theColNum + repeat for each line theColumn in pKeys + add 1 to theColNum + put theColumn into theColLookupA[theColNum] + end repeat + + repeat for each line theLine in pText + put 0 into theColNum + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[ theColLookupA[theColNum] ] + if theColNum is theColCount then exit repeat + end repeat + + AddData theDataA, pLineNo + put the result into theResult + if pLineNo is not empty then add 1 to pLineNo + end repeat + else + ## No columns provided. We just create columns named "Label COL_NUM" + repeat for each line theLine in pText + put 0 into theColNum + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[ "Label" && theColNum ] + end repeat + + AddData theDataA, pLineNo + put the result into theResult + if pLineNo is not empty then add 1 to pLineNo + end repeat + end if + + unlock screen + return theResult +end _list.AddLine + + +private command _list.DrawWithProperties pSetVScrollTo, pForceRefresh, pCallback, pCallbackContext + ----- + local theError + ----- + lock messages + set the vScroll of group "dgList" of me to 0 + unlock messages + + ## Easier to read code + if the dgProps["cache controls"] of me then + _list.DrawCachedControlList pForceRefresh, pCallback, pCallbackContext + else + _list.DrawControlsInRealTime pForceRefresh, pCallback, pCallbackContext + end if + + # Update VScroll every time + lock messages + set the vScroll of group "dgList" of me to pSetVScrollTo + unlock messages + + -- We've potentially scrolled, so reposition any overlays. + DG2_EditModeActionControlHolderReposition + DG2_SwipeControlHolderReposition + + return theError +end _list.DrawWithProperties + + +private command _list.DeleteControls + ----- + local i + local msgsAreLocked + local theControl + ----- + put the lockMessages into msgsAreLocked + lock messages ## for speed + + repeat for each line theControl in sTableObjectsA["all row controls"] + if there is a control theControl then + delete theControl + end if + end repeat + + ## Any extra cleanup + repeat until there is not a (group 1 of group "dgList" of me) + delete group 1 of group "dgList" of me + end repeat + repeat until there is not a control 1 of group "dgList" of me + delete control 1 of group "dgList" of me + end repeat + + put empty into sTableObjectsA["all row controls"] + put empty into sTableObjectsA["visible row controls"] + + set the lockMessages to msgsAreLocked +end _list.DeleteControls + + +private command _list.FillListWithJustEnoughControls + local controlCountChanged,i + local theControl,theCurrentControlCount,theMsgsAreLocked,theRequiredControlCount + local theTemplateGroup + + local msgsAreLocked + put the lockMessages into msgsAreLocked + + put false into controlCountChanged + put the dgProps["row template"] of me into theTemplateGroup + + ## Determine required control count + put _ControlsRequiredToFillSpace() into theRequiredControlCount + + ## Make sure we have enough controls to fill visible space + put sTableObjectsA["row control count"] into theCurrentControlCount + + if theRequiredControlCount > theCurrentControlCount then + if sTableObjectsA["all row controls"] is not empty then put cr after sTableObjectsA["all row controls"] + + ## Create enough controls + lock messages ## for speed + repeat with i = theCurrentControlCount + 1 to theRequiredControlCount + copy theTemplateGroup to group "dgList" of me + put it into theControl + set the layerMode of theControl to "dynamic" + set the name of theControl to the short name of theControl && format("%04d", i) + put "control id" && word 3 of theControl && "of me" & cr after sTableObjectsA["all row controls"] + + ## take over geometry + set the lockloc of theControl to true + end repeat + unlock messages + + delete the last char of sTableObjectsA["all row controls"] + put the number of lines of sTableObjectsA["all row controls"] into sTableObjectsA["row control count"] + + put true into controlCountChanged + + else if theRequiredControlCount < theCurrentControlCount then + ## To many controls. That is okay. They just hang around invisible. + else + ## We have just enough controls + end if + + set the lockMessages to msgsAreLocked + + return controlCountChanged +end _list.FillListWithJustEnoughControls + + +private command _list.UpdateAlternatingRowColors + lock screen + + local theRow1Color, theRow2Color, theControl, theIndex + put _GetEffectiveColor("row color") into theRow1Color + put _GetEffectiveColor("alternate row color") into theRow2Color + + set the wholeMatches to true + + repeat for each line theControl in sTableObjectsA["visible row controls"] + put the dgDataControl of theControl into theControl + if there is a graphic "Background" of theControl then + put the dgIndex of theControl into theIndex + + ## don't color hilited lines + if theIndex is among the items of sHilitedIndexes then next repeat + + local theLine + put itemOffset(theIndex, sIndexSequencing) into theLine + if theLine mod 2 is kAlternatingRowModValue then + set the backgroundColor of graphic "Background" of theControl to theRow2Color + else + set the backgroundColor of graphic "Background" of theControl to theRow1Color + end if + end if + end repeat + + unlock screen + return empty +end _list.UpdateAlternatingRowColors + + +-- pControls is "all list controls" for a form or column row controls for a table +private function _GenerateReorderedControlList pControls, pIndexes + local theControl,theControlIndexesA,theControlsWithoutAHome,theIndex,theList + + set the wholeMatches to true + ## Separate controls based on whether or not they have an index + repeat for each line theControl in pControls + put the dgIndex of theControl into theIndex + + if theIndex is among the items of pIndexes then + put theControl into theControlIndexesA[theIndex] + else + put theControl & cr after theControlsWithoutAHome + end if + end repeat + delete the last char of theControlsWithoutAHome + + ## Now order everything + repeat for each item theIndex in pIndexes + if theControlIndexesA[theIndex] is not empty then + put theControlIndexesA[theIndex] & cr after theList + else + put line 1 of theControlsWithoutAHome & cr after theList + delete line 1 of theControlsWithoutAHome + end if + end repeat + put theControlsWithoutAHome after theList + if the last char of theList is cr then delete the last char of theList + + return theList +end _GenerateReorderedControlList + + +private command _list.DrawControlsInRealTime pForceRefresh, pCallback, pCallbackContext + ----- + local controlCountWasModified + local i + local msgsAreLocked + local noRedrawNeeded + local theControl, theControlIndex + local theEffectiveControl + local theIndex + local theIndexesInSequence + local theListGroupRect + local theMaxControlNumber + local theRect + local theRowColor + local theSequence + local theTopLeft + ----- + ## Get geometry properties + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + put 0 into theControlIndex + + ## Make sure there are enough controls + _FillListWithJustEnoughControls + put the result into controlCountWasModified + + ## We use sequencing to draw, not indexes + set the wholeMatches to true + put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexesInSequence + put _ControlsRequiredToFillSpace() into theMaxControlNumber + + ## filter the list of sequences + put item 1 to theMaxControlNumber of theIndexesInSequence into theIndexesInSequence + + ## Get lookup table for indexes that already have controls with correct data + local theMasterControlList + put _GenerateReorderedControlList(sTableObjectsA["all row controls"], theIndexesInSequence) into theMasterControlList + + put the lockMessages into msgsAreLocked + + put not controlCountWasModified and sTableObjectsA["current"]["indexes"] is theIndexesInSequence into noRedrawNeeded + -- put theIndexesInSequence && the milliseconds & cr into msg + + ## [[ DG2Layout ]] If edit mode or enable swipe is enabled or if minimal + ## layout is not enabled then we must still call LayoutControl on each + ## iteration. + local theMustLayout + put sEditMode or \ + the dgProps["enable swipe"] of me or \ + not the dgProps["minimal layout"] of me into theMustLayout + + if not noRedrawNeeded or pForceRefresh then + put empty into sTableObjectsA["visible row controls"] + + local theRow1Color, theRow2Color, controlHeightIsFixed + put _GetEffectiveColor("row color") into theRow1Color + put _GetEffectiveColor("alternate row color") into theRow2Color + + put sTableObjectsA["base sequence for visible controls"] - 1 into theSequence + put the dgProps["fixed row height"] of me into controlHeightIsFixed + + if pCallback is not empty then + dispatch pCallback & "Start" to me with pCallbackContext, theTopLeft + end if + + repeat for each item theIndex in theIndexesInSequence + ## Get control reference + add 1 to theControlIndex + add 1 to theSequence + + ## This will speed things up and keep us from experiencing visual lag + lock messages + + put line theControlIndex of theMasterControlList into theControl + if there is not a theControl then _ThrowError kErrCantFindObject, "control not found when drawing form:" && theControl + + unlock messages + set the visible of theControl to true + put theControl & cr after sTableObjectsA["visible row controls"] + put the dgDataControl of theControl into theEffectiveControl + lock messages + + ## Set geometry + if controlHeightIsFixed then + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + sControlHeights into theRect + else + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect + end if + + ## Set row color + if there is a graphic "Background" of theEffectiveControl then + ## Compute the new row color based on the alternating index + local theNewRowColor + if theSequence mod 2 is kAlternatingRowModValue then + put theRow2Color into theNewRowColor + else + put theRow1Color into theNewRowColor + end if + + ## [[ ColorRedraw ]] Only change the backgroundColor of the control + ## if it has changed. + if the backgroundColor of graphic "Background" of theEffectiveControl is not theNewRowColor then + set the backgroundColor of graphic "Background" of theEffectiveControl to theNewRowColor + end if + end if + + ## If control index is not the index we are working on then + ## Load new data + local theCurrentIndex, theNeedsLayout + put the dgIndex of theControl into theCurrentIndex + if theCurrentIndex is not theIndex then + ## Allow developer to do something if unloading control + if theCurrentIndex is not empty then + unlock messages + dispatch "PreFillInData" to theControl ## standardized and documented in 1.0.2 build 6 + -- dispatch "ResetDataGridControl" to theControl + lock messages + end if + + set the dgIndex of theControl to theIndex + + local theDataA + if sDataArray[theIndex] is NULL then + unlock messages + GetDataForLine theSequence, theDataA + dispatch "FillInData" to theControl with theDataA + lock messages + else + unlock messages + dispatch "FillInData" to theControl with sDataArray[theIndex] + lock messages + end if + + ## If data was changed, then the control must layout + put true into theNeedsLayout + else + -- put "not drawing index:" && theIndex & cr after msg + + ## If data has not changed then only layout if DG2 features are + ## active + put theMustLayout into theNeedsLayout + end if + + ## Set the rect AFTER filling in data in case filling in data causes the group to resize + unlock messages + if pCallback is not empty then + dispatch pCallback to me with pCallbackContext, theControl, theSequence, theRect, theTopLeft + end if + + ## Always set the topLeft of the row template - this causes unchanged + ## rows to scroll, and ensure that changed rows controls are where they + ## expect. + set the topLeft of theControl to item 1 to 2 of theRect + + ## If the width or height of the row template has changed then get the + ## user script to layout it out again. + if theNeedsLayout or \ + the width of theControl is not (item 3 of theRect - item 1 of theRect) or \ + the height of theControl is not (item 4 of theRect - item 2 of theRect) then + lock messages + set the rect of theControl to theRect + unlock messages + + set the lockUpdates of theControl to true + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + set the lockUpdates of theControl to false + + ## Resize to fit height + if not controlHeightIsFixed then + lock messages + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + set the rect of theControl to theRect + unlock messages + end if + end if + + put the bottom of theControl into item 2 of theTopLeft + + ## [[ HiliteAll ]] Update the hilite of the row template - ideally + ## this would only be done *if* the hilite of the row has changed + ## or the row template has been reused or the data for the row has + ## changed. + if theIndex is among the items of sHilitedIndexes then + _HiliteControl theEffectiveControl, true + else + _HiliteControl theEffectiveControl, false + end if + end repeat + + ## Store current sequences in list + put theIndexesInSequence into sTableObjectsA["current"]["indexes"] + + if pCallback is not empty then + dispatch pCallback & "End" to me with pCallbackContext + end if + end if + + ## Filter control list and reset controls that aren't part of visible list + put line (the number of lines of sTableObjectsA["visible row controls"] + 1) to -1 of theMasterControlList into theMasterControlList + _ResetControls theMasterControlList + + return empty +end _list.DrawControlsInRealTime + +private command _list.DrawCachedControlList pForceRefresh, pCallback, pCallbackContext + ----- + local isVisible + local msgsAreLocked + local noRedrawNeeded + local theControl + local theFirstControlHeight + local theIndex + local theIndexesInSequence + local theListGroupRect, theListGroupWidth + local theOldListControls + local theRowColor + local theSequence + local theTopLeft + ----- + + # If controls haven't been cached yet then exit + if sControlOfIndexA is not an array then return empty + + put false into noRedrawNeeded + put empty into theFirstControlHeight + + put the lockMessages into msgsAreLocked + + ## Get geometry properties + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + put item 3 of theListGroupRect - item 1 of theListGroupRect into theListGroupWidth + + ## We use sequencing to draw, not indexes + set the wholeMatches to true + put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexesInSequence + + ## Do we need to redraw? + put line 1 of sTableObjectsA["visible row controls"] into theControl + + if there is a theControl then + put the dgIndex of theControl is item 1 of theIndexesInSequence into noRedrawNeeded + end if + + if not noRedrawNeeded or pForceRefresh then + -- put "calling " & param(0) & cr after msg ## important log + + ## Cache currently visible controls + put sTableObjectsA["visible row controls"] into theOldListControls + put empty into sTableObjectsA["visible row controls"] + put empty into sTableObjectsA["current"]["indexes"] + + local theRow1Color, theRow2Color + put _GetEffectiveColor("row color") into theRow1Color + put _GetEffectiveColor("alternate row color") into theRow2Color + + put sTableObjectsA["base sequence for visible controls"] - 1 into theSequence + + if pCallback is not empty then + dispatch pCallback & "Start" to me with pCallbackContext, theTopLeft + end if + + ## This will speed things up and keep us from experiencing visual lag + lock messages + + -- put "theIndexesInSequence:" && theIndexesInSequence & cr after msg ## important log + repeat for each item theIndex in theIndexesInSequence + add 1 to theSequence + put theIndex & comma after sTableObjectsA["current"]["indexes"] + + ## Get control reference + -- put "control (" & theIndex & "):" && theControl & cr after msg ## important log + put sControlOfIndexA[theIndex] into theControl + put theControl & cr after sTableObjectsA["visible row controls"] + + unlock messages + local theEffectiveControl + put the dgDataControl of theControl into theEffectiveControl + lock messages + + ## Set row color + if there is a graphic "Background" of theEffectiveControl then + if theSequence mod 2 is kAlternatingRowModValue then + set the backgroundColor of graphic "Background" of theEffectiveControl to theRow2Color + else + set the backgroundColor of graphic "Background" of theEffectiveControl to theRow1Color + end if + end if + + unlock messages + put the visible of theControl into isVisible + set the visible of theControl to true + if not isVisible then + dispatch "ShowDataGridControl" to theControl + end if + + ## Set coordinates + set the topLeft of theControl to theTopLeft + put the bottom of theControl into item 2 of theTopLeft + + if pCallback is not empty then + local theRect + put the rect of theControl into theRect + dispatch pCallback to me with pCallbackContext, theControl, theSequence, theRect, theTopLeft + end if + + ## Hilited index? + if theIndex is among the items of sHilitedIndexes then + _HiliteControl theEffectiveControl, true + else + _HiliteControl theEffectiveControl, false + end if + lock messages + + ## We need to know the height of first control as it must be able to scroll off screen + if theFirstControlHeight is empty then + put the height of theControl into theFirstControlHeight + end if + + ## Check for exit + if item 2 of theTopLeft >= item 4 of theListGroupRect + theFirstControlHeight then + exit repeat + end if + end repeat + delete the last char of sTableObjectsA["visible row controls"] + delete the last char of sTableObjectsA["current"]["indexes"] + -- put "----" & cr after msg ## important log + + ## We end repeat loop with locked messages + unlock messages + + ## Hide previously visible list controls that are no longer visible. + ## This is performed after we know which controls are visible this time around so + ## that controls that are visible are not hid then shown again. + repeat for each line theControl in theOldListControls + if theControl is not among the lines of sTableObjectsA["visible row controls"] then + try + set the visible of theControl to false + catch e + -- put theOrigListControls + -- put cr & "---" & cr & the short name of the me & cr & "can't set visible of:" && theControl & cr & theIndexesInSequence after msg + end try + -- dispatch "HideDataGridControl" to theControl + dispatch "HideControl" to theControl ## standardized in 1.0.2 build 6 + end if + end repeat + + if pCallback is not empty then + dispatch pCallback & "End" to me with pCallbackContext + end if + end if + + set the lockMessages to msgsAreLocked + + return empty +end _list.DrawCachedControlList + + +private command _list.CalculateFormattedHeight + ----- + local msgsAreLocked + local theControl + local theIndex + local theListGroupRect + local theRect + local theTemplateGroup + local theTopLeft + local theDataA + local theError + ----- + + ## If height is not fixed then we calculate height by looping through data and drawing controls. + put the dgProps["row template"] of me into theTemplateGroup + if theTemplateGroup is empty then return empty + + ## This handler loops through all records and gets the height of each one. The total height is then stored + lock screen + put the lockMessages into msgsAreLocked + + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + + lock messages + copy theTemplateGroup to group "dgList" of me + put it into theControl + set the layerMode of theControl to "dynamic" + unlock messages + + try ## Watch for user errors + + put item 1 to 2 of theListGroupRect into theTopLeft + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theListGroupRect + the height of theControl into theRect + lock messages + set the rect of theControl to theRect ## Only do this once. + unlock messages + + if the dgProps["fixed row height"] of me then + put the dgProps["row height"] of me into sControlHeights + if sControlHeights is not an integer or sControlHeights < 1 then + if sDataArray[1] is NULL then + GetDataForLine 1, theDataA + dispatch "FillInData" to theControl with theDataA + else + dispatch "FillInData" to theControl with sDataArray[1] + end if + + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + put the formattedHeight of theControl into sControlHeights + end if + put sControlHeights * the number of elements of sDataArray into sFormattedHeight + else + repeat for each key theIndex in sDataArray + local theSequence + add 1 to theSequence + ## Get height + if sDataArray[theIndex] is NULL then + GetDataForLine theSequence, theDataA + + dispatch "CalculateFormattedHeight" to theControl with theDataA + if it is "not handled" or it is "unhandled" then + dispatch "FillInData" to theControl with theDataA + + set the topLeft of theControl to theTopLeft ## So developer can rely on topleft of controls in template code. + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + put the formattedHeight of theControl into sControlHeights[theIndex] + else + put the result into sControlHeights[theIndex] + end if + + else + dispatch "CalculateFormattedHeight" to theControl with sDataArray[theIndex] + if it is "not handled" or it is "unhandled" then + dispatch "FillInData" to theControl with sDataArray[theIndex] + + set the topLeft of theControl to theTopLeft ## So developer can rely on topleft of controls in template code. + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + put the formattedHeight of theControl into sControlHeights[theIndex] + else + put the result into sControlHeights[theIndex] + end if + end if + + add sControlHeights[theIndex] to sFormattedHeight + end repeat + end if + + catch e + put e into theError + end try + + lock messages + delete theControl + unlock messages + + unlock screen + set the lockMessages to msgsAreLocked + + if theError is not empty then throw theError +end _list.CalculateFormattedHeight + + +private command _list.HiliteIndexesInVisibleControls + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the lockMessages to false + set the wholeMatches to true + repeat for each line theControl in sTableObjectsA["visible row controls"] + local theBoolean + put the dgIndex of theControl is among the items of sHilitedIndexes into theBoolean + _HiliteControl the dgDataControl of theControl, theBoolean + end repeat + set the lockMessages to msgsAreLocked + unlock screen +end _list.HiliteIndexesInVisibleControls + + +--> Type: Table + + +private command _table.UpdateHeaderLabel pColumn, pLabel, pEncoding + if the paramCount is 1 then + local theColsA + put the dgProps["column properties"] of me into theColsA + put theColsA[pColumn]["label"] into pLabel + put theColsA[pColumn]["encoding"] into pEncoding + end if + + local theGroup + put sTableObjectsA["columns"][pColumn]["header"]["group"] into theGroup + if theGroup is not empty then + if pLabel is empty then put pColumn into pLabel + set the dgLabel [pEncoding] of theGroup to pLabel + end if +end _table.UpdateHeaderLabel + + +private command _table.UpdateHeaderTooltip pColumn, pTooltip + local theColsA, theGroup + if the paramCount is 1 then + put the dgProps["column properties"] of me into theColsA + put theColsA[pColumn]["tooltip"] into pTooltip + end if + + put sTableObjectsA["columns"][pColumn]["header"]["group"] into theGroup + if theGroup is not empty then + set the dgTooltip of theGroup to pTooltip + end if +end _table.UpdateHeaderTooltip + + +private command _table.ScrollColumnIntoView pColumn + local theColGroup, theColRect, theMaskRect, theDiff + put sTableObjectsA["columns"][pColumn]["group"] into theColGroup + if theColGroup is empty then return empty + + put the rect of theColGroup into theColRect + put the rect of group "dgListMask" into theMaskRect + if the visible of scrollbar "dgScrollbar" of me then + put the left of scrollbar "dgScrollbar" of me into item 3 of theMaskRect + end if + + put item 1 of theColRect - item 1 of theMaskRect into theDiff + if theDiff > 0 then + put item 3 of theColRect - item 3 of theMaskRect into theDiff + if theDiff < 0 then + put 0 into theDiff + end if + end if + + if theDiff is not 0 then + local msgsAreLocked + put the lockMessages into msgsAreLocked + unlock messages + if __HasMobileScroller() then + mobileControlSet sScrollerId, "hScroll", mobileControlGet(sScrollerId, "hScroll") + theDiff + end if + set the thumbPosition of scrollbar "dgHScrollbar" of me to the thumbPosition of scrollbar "dgHScrollbar" of me + theDiff + set the lockMessages to msgsAreLocked + end if + + return empty +end _table.ScrollColumnIntoView + + +private command _table.LayoutDataArea + local theViewRect, theRect + put _WorkingGroupRect(the long ID of me) into theViewRect + put theViewRect into theRect + + local tHeaderComponents, tHorizontalComponents + local tVScrollbar, tHScrollbar, tCornerPiece + put the long id of group "dgHeaderComponents" of me into tHeaderComponents + put the long id of group "dgHorizontalComponents" of me into tHorizontalComponents + put the long id of scrollbar "dgScrollbar" of me into tVScrollbar + put the long id of scrollbar "dgHScrollbar" of tHorizontalComponents into tHScrollbar + put the long id of graphic "dgCornerPiece" of tHorizontalComponents into tCornerPiece + + ## Shift all content + set the topLeft of tHeaderComponents to item 1 to 2 of theRect + + if the visible of tHeaderComponents then + # Set the rect of the header mask + local tHeaderMaskRect + put theRect into tHeaderMaskRect + put the bottom of group "dgHeaderMask" of tHeaderComponents into item 4 of tHeaderMaskRect + set the rect of group "dgHeaderMask" of tHeaderComponents to tHeaderMaskRect + ## Define new top of content rect + put item 4 of tHeaderMaskRect into item 2 of theRect + end if + + if the environment is not "mobile" then + ## Reposition bottom element + local theSBWidth + if the visible of tVScrollbar then + put the width of tVScrollbar into theSBWidth + else + put the dgProps["scrollbar corner offset"] of me into theSBWidth + end if + # If the hscrollbar is not shown, then the horizontal components group + # containing it is invisible, so the corner piece is also invisible. + # So we can just set visibility of corner piece to the visible of the + # vscrollbar + set the visible of tCornerPiece to the visible of tVScrollbar + + set the rect of tHScrollbar to \ + item 1 of theRect, \ + item 4 of theRect - the height of tHScrollbar, \ + item 3 of theRect - theSBWidth, item 4 of theRect + + if the visible of tHorizontalComponents then + put the top of tHScrollbar into item 4 of theRect + else + put item 4 of theViewRect - the dgProps["scrollbar corner offset"] of me \ + into item 4 of theRect + end if + + ## V Scrollbar and corner piece + set the rect of tVScrollbar to \ + item 3 of theRect - the width of tVScrollbar, \ + item 2 of theRect, item 3 of theRect, \ + item 4 of theRect + + set the rect of tCornerPiece to \ + item 3 of theRect - the width of tVScrollbar, \ + the top of tHScrollbar, \ + item 3 of theRect, \ + the bottom of tHScrollbar + + ## Masks + ## AL-2013-07-30 [[ Bug 10108 ]] Thumb and scrollbar appear over top of DataGrid + if the visible of tVScrollbar then + put item 3 of theRect - theSBWidth into item 3 of theRect + end if + else if __HasMobileScroller() then + mobileControlSet sScrollerId, "rect", theRect + end if + + set the topLeft of group "dgListMask" of me to item 1 to 2 of theRect + set the rect of group "dgListMask" of me to theRect + set the rect of group "dgAlternatingRowsMask" of me to theRect + + ## Shift List Group + _table.ResizeHeaderBackground + _table.ResizeList + _table.RepositionColumns + _table.LayoutRowHilites +end _table.LayoutDataArea + + +private command _table.SetHeaderBkgrndHiliteColor pColor + repeat for each line theColumn in the dgProps["columns"] of me + local theGroup + put sTableObjectsA["columns"][theColumn]["header"]["group"] into theGroup + if there is a theGroup then + _table.HiliteHeaderBackground theGroup, pColor + end if + end repeat +end _table.SetHeaderBkgrndHiliteColor + + +private command _table.HiliteHeaderBackground pHeaderGroup, pColor + local setFillGradient, useAGradient + put pColor is an array into setFillGradient + put the number of lines of pColor is 2 into useAGradient + + if there is a graphic "Background" of pHeaderGroup then + if setFillGradient then + repeat for each key theKey in pColor + set the fillGradient[theKey] of graphic "Background" of pHeaderGroup to pColor[theKey] + end repeat + else if useAGradient then + _SetGraphicGradient the long ID of graphic "Background" of pHeaderGroup, line 1 of pColor, line 2 of pColor + else + set the backgroundColor of graphic "Background" of pHeaderGroup to pColor + end if + end if +end _table.HiliteHeaderBackground + + +-- pTarget is optional and allows you to target a hilite background +private command _table.SetHeaderBkgrndGradient pStartColor, pEndColor + _SetGraphicGradient the long ID of graphic "dgBackground" of group "dgHeaderMask" of group "dgHeaderComponents" of me, \ + pStartColor, pEndColor +end _table.SetHeaderBkgrndGradient + + +private command _table.UpdateHeaderDividerColors + repeat for each line theColumn in the dgProps["columns"] of me + local theGroup + put sTableObjectsA["columns"][theColumn]["header"]["group"] into theGroup + if there is a theGroup then + set the foregroundColor of graphic "RightHilite" of theGroup to the dgProps["header divider color"] of me + set the foregroundColor of graphic "LeftHilite" of theGroup to the dgProps["header divider threeD color"] of me + end if + end repeat +end _table.UpdateHeaderDividerColors + + +private function _table.GetText pIncludeColumns + ----- + local theColumn, theColumns + local theIndex + local theText + ----- + put the dgProps["columns"] of me into theColumns + + if pIncludeColumns then + put theColumns into theText + replace cr with tab in theText + put cr after theText + end if + + repeat for each item theIndex in sIndexSequencing + repeat for each line theColumn in theColumns + put sDataArray[theIndex][theColumn] & tab after theText + end repeat + put cr into the last char of theText + end repeat + delete the last char of theText + return theText +end _table.GetText + + +private command _table.SetText pText, pColumns + ----- + local i + local theColNum, theColumn, theColumns, theItemNoColumnA + local theDataA + local theItem + local theLine + local theSequencing + ----- + lock screen + + set the itemDelimiter to tab + if pColumns is empty then + put the dgProps["columns"] of me into pColumns + + ## Make sure we have some columns defined + local theColCount + put the number of lines of pColumns into theColCount + if the number of lines of pColumns < the number of items of line 1 of pText then + if pColumns is not empty then put cr after pColumns + repeat with i = 1 to the number of items of line 1 of pText + if i > theColCount then + put "Col" && i & cr after pColumns + end if + end repeat + delete the last char of pColumns + set the dgProps["columns"] of me to pColumns + end if + end if + put the number of lines of pColumns into theColCount + + ## Store column item no's and total column count + put 0 into i + repeat for each line theColumn in pColumns + add 1 to i + put theColumn into theItemNoColumnA[i] + end repeat + + repeat for each line theLine in pText + local theRow + add 1 to theRow + put 0 into theColNum + put theRow & comma after theSequencing + if theLine is empty then + ## Fill in empty records for empty lines + repeat for each line theColumn in pColumns + put empty into theDataA[theRow][theColumn] + end repeat + else + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[theRow][ theItemNoColumnA[theColNum] ] + + if theColNum is theColCount then exit repeat + end repeat + end if + end repeat + delete the last char of theSequencing + + set the dgData [theSequencing] of me to theDataA + + unlock screen +end _table.SetText + + +private command _table.AddLine pText, pColumns, pLineNo + ----- + local i + local theColNum, theColumn, theColumns, theItemNoColumnA + local theDataA + local theItem + local theLine,theResult + ----- + lock screen + + set the itemDelimiter to tab + if pColumns is empty then + put the dgProps["columns"] of me into pColumns + + ## Make sure we have some columns defined + local theColCount + put the number of lines of pColumns into theColCount + if the number of lines of pColumns < the number of items of line 1 of pText then + if pColumns is not empty then put cr after pColumns + repeat with i = 1 to the number of items of line 1 of pText + if i > theColCount then + put "Col" && i & cr after pColumns + end if + end repeat + delete the last char of pColumns + set the dgProps["columns"] of me to pColumns + end if + end if + put the number of lines of pColumns into theColCount + + ## Store column item no's and total column count + put 0 into i + repeat for each line theColumn in pColumns + add 1 to i + put theColumn into theItemNoColumnA[i] + end repeat + + ## add lines + repeat for each line theLine in pText + put 0 into theColNum + put empty into theDataA + repeat for each item theItem in theLine + add 1 to theColNum + put theItem into theDataA[ theItemNoColumnA[theColNum] ] + if theColNum is theColCount then exit repeat + end repeat + + ## Note: This redraws list each time. Officially we only support one line of text right + ## now but we could bring the logic of AddData inline and not redraw until the end. + AddData theDataA, pLineNo + put the result into theResult + + if pLineNo is not empty then add 1 to pLineNo + end repeat + + unlock screen + + return theResult +end _table.AddLine + + +private command _table.DrawWithProperties pSetVScrollTo, pForceRefresh + ## We only scroll by entire records so if any scrolling is supposed to occur then + ## start 1 higher + if pSetVScrollTo > 0 then add 1 to sTableObjectsA["base sequence for visible controls"] + + _table.DrawControlsInRealTime pForceRefresh + if sTableObjectsA["base sequence for visible controls"] mod 2 is kAlternatingRowModValue then + set the top of graphic "dgAlternatingRows" of me to the top of group "dgAlternatingRowsMask" of me - sControlHeights + else + set the top of graphic "dgAlternatingRows" of me to the top of group "dgAlternatingRowsMask" of me + end if +end _table.DrawWithProperties + + +private command _table.DeleteColumn pColumn + ----- + local msgsAreLocked + local theColPropsA + local theControl + ----- + lock screen + put sTableObjectsA["columns"][pColumn]["header"]["group"] into theControl + if there is a theControl then delete theControl + + put sTableObjectsA["columns"][pColumn]["group"] into theControl + if there is a theControl then delete theControl + + put sTableObjectsA["columns"][pColumn]["divider control"] into theControl + if there is a theControl then delete theControl + delete local sTableObjectsA["columns"][pColumn] + + ## column properties + put the dgProps["column properties"] of me into theColPropsA + delete local theColPropsA[pColumn] + + put the lockMessages into msgsAreLocked + lock messages + set the dgProps["column properties"] of me to theColPropsA + set the lockMessages to msgsAreLocked + + unlock screen +end _table.DeleteColumn + + +private command _table.DeleteColumnControls + ----- + local i + local msgsAreLocked + local theColumn + ----- + put the lockMessages into msgsAreLocked + lock messages ## for speed + + repeat until there is not a group 1 of group "dgList" of group "dgListMask" of me + ## Nested groups will mess up the count as we delete + delete group 1 of group "dgList" of group "dgListMask" of me + end repeat + repeat with i = 1 to the number of controls of group "dgList" of group "dgListMask" of me + delete control 1 of group "dgList" of group "dgListMask" of me + end repeat + + repeat until there is not a group 1 of group "dgDividers" of group "dgListMask" of me + delete group 1 of group "dgDividers" of group "dgListMask" of me + end repeat + + repeat with i = 1 to the number of controls of group "dgDividers" of group "dgListMask" of me + delete control 1 of group "dgDividers" of group "dgListMask" of me + end repeat + + repeat until there is not a group 1 of group "dgHeader" of group "dgHeaderComponents" of me + delete group 1 of group "dgHeader" of group "dgHeaderComponents" of me + end repeat + + repeat with i = 1 to the number of controls of group "dgHeader" of group "dgHeaderComponents" of me + delete control 1 of group "dgHeader" of group "dgHeaderComponents" of me + end repeat + + repeat for each line theColumn in the dgProps["columns"] of me + delete local sTableObjectsA["columns"][theColumn] + end repeat + + set the lockMessages to msgsAreLocked +end _table.DeleteColumnControls + + +private command _table.DeleteDataControls + ----- + local i + local msgsAreLocked + local theColGroup, theColumn + ----- + put the lockMessages into msgsAreLocked + lock messages ## for speed + + ## cleanup + + ## Hilite graphics + repeat for each line theControl in sTableObjectsA["row hilite controls"] + delete theControl + end repeat + put empty into sTableObjectsA["row hilite controls"] + + repeat with i = 1 to the number of controls of group "dgHighlights" of group "dgListMask" of me + delete control 1 of group "dgHighlights" of group "dgListMask" of me + end repeat + + ## Columns + repeat for each line theColumn in the dgProps["columns"] of me + put sTableObjectsA["columns"][theColumn]["group"] into theColGroup + if theColGroup is empty then next repeat + + ## stored + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"] + delete theControl + end repeat + + ## cleanup + repeat with i = 1 to the number of groups of theColGroup + delete group 1 of theColGroup + end repeat + + repeat with i = 1 to the number of controls of theColGroup + delete control 1 of theColGroup + end repeat + + put empty into sTableObjectsA["columns"][theColumn]["row controls"] + end repeat + + set the lockMessages to msgsAreLocked +end _table.DeleteDataControls + + +private command _table.LayoutRowHilites + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local theRect + put the rect of group "dgList" of group "dgListMask" of me into theRect + put item 2 of theRect + sControlHeights into item 4 of theRect + repeat for each line theControl in sTableObjectsA["row hilite controls"] + set the rect of theControl to theRect + local theTop + put item 4 of theRect into theTop + put theTop into item 2 of theRect + put theTop + sControlHeights into item 4 of theRect + set the backgroundColor of theControl to _GetHiliteColor() + end repeat + + set the lockMessages to msgsAreLocked +end _table.LayoutRowHilites + + +private command _table.FillListWithJustEnoughControls + local msgsAreLocked + put the lockMessages into msgsAreLocked + + local controlCountChanged, theTemplateGroup, theColumns, theResourceStack, theRequiredControlCount, theCurrentControlCount + put false into controlCountChanged + put the dgProps["row template"] of me into theTemplateGroup + put _table.VisibleColumns() into theColumns + put _ResourceStack() into theResourceStack + + ## Determine required control count + put _ControlsRequiredToFillSpace() into theRequiredControlCount + + ## Make sure we have enough controls to fill visible space + put sTableObjectsA["row control count"] into theCurrentControlCount + -- put the number of lines of (sTableObjectsA["columns"][line 1 of theColumns]["row controls"]) into theCurrentControlCount + + lock messages ## for speed + + if theRequiredControlCount > theCurrentControlCount then + ## + ## Create highlight graphics + ## + reset the templategraphic + set the opaque of the templategraphic to true + set the lineSize of the templategraphic to 0 + set the antialiased of the templategraphic to false + + -- put _CardOf() into theDGCard + + if sTableObjectsA["row hilite controls"] is not empty then put cr after sTableObjectsA["row hilite controls"] + + repeat with i = theCurrentControlCount + 1 to theRequiredControlCount + create graphic ("hilite" && format("%04d", i)) in group "dgHighlights" of group "dgListMask" of me + put "control id" && word 3 of it && "of me" & cr after sTableObjectsA["row hilite controls"] + set the visible of it to false + end repeat + delete the last char of sTableObjectsA["row hilite controls"] + reset the templategraphic + + _table.LayoutRowHilites + + ## + ## Create column controls + ## + _table.CreateControlsForColumns theColumns, theRequiredControlCount + + ## Store first column in list of all controls so other handler can use it for information purposes + put true into controlCountChanged + + else if theRequiredControlCount < theCurrentControlCount then + ## To many controls: Leave as is for later. //Delete them as this makes management much easier with controls spread across multiple columns. + else + ## We have just enough controls + end if + + set the lockMessages to msgsAreLocked + + return controlCountChanged +end _table.FillListWithJustEnoughControls + + +private command _table.CreateControlsForColumns pColumns, pRequiredControlCount + ----- + local i + local msgsAreLocked + local theColPropsA, theColumn, theColWidth + local theControl + local theCurrentControlCount + local theResourceStack + local theTemplateGroup + local theTopLeft + local theMargins + ----- + put the lockMessages into msgsAreLocked + unlock messages + put the dgProps["column margins"] of me into theMargins + lock messages + + if sTableObjectsA["row control count"] is not an integer then put 0 into sTableObjectsA["row control count"] + if pRequiredControlCount is not an integer or pRequiredControlCount < 0 then put sTableObjectsA["row control count"] into pRequiredControlCount + + ## Initialize + put the dgProps["row template"] of me into theTemplateGroup + put _ResourceStack() into theResourceStack + -- put _CardOf() into theDGCard + put the dgProps["column properties"] of me into theColPropsA + + ## Create + repeat for each line theColumn in pColumns + put the number of lines of sTableObjectsA["columns"][theColumn]["row controls"] into theCurrentControlCount + if theCurrentControlCount >= pRequiredControlCount then next repeat + + ## We store each column's controls in separate list + ## Initialize geometry vars for this column + if sTableObjectsA["columns"][theColumn]["row controls"] is not empty then + put the bottomLeft of (the last line of sTableObjectsA["columns"][theColumn]["row controls"]) into theTopLeft + put cr after sTableObjectsA["columns"][theColumn]["row controls"] + else + put the topLeft of group theColumn of group "dgList" of me into theTopLeft + end if + put the width of group theColumn of group "dgList" of me into theColWidth + + repeat with i = theCurrentControlCount + 1 to pRequiredControlCount + if sTableObjectsA["columns"][theColumn]["uses custom template"] then + copy control theColumn of theTemplateGroup to group theColumn of group "dgList" of me + ## Use default behavior if control doesn't have one assigned. + if the behavior of it is empty then + if the dgProps["default column behavior"] of me is empty then + set the behavior of it to the long ID of button "Default Column" of theResourceStack + else + set the behavior of it to the dgProps["default column behavior"] of me + end if + end if + else + _table.ConfigureTemplateFieldForColumn line 1 of pColumns + create field in group theColumn of group "dgList" of me + set the textAlign of it to theColPropsA[theColumn]["alignment"] + set the margins of it to theMargins + if the dgProps["default column behavior"] of me is empty then + set the behavior of it to the long ID of button "Default Column" of theResourceStack + else + set the behavior of it to the dgProps["default column behavior"] of me + end if + end if + put it into theControl + set the name of theControl to theColumn && format("%04d", i) + + ## Take control of geometry + set the lockloc of theControl to true + + local theRect + put theTopLeft into theRect + put item 1 of theRect + theColWidth into item 3 of theRect + put item 2 of theRect + sControlHeights into item 4 of theRect + + set the topLeft of theControl to theTopLeft + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect + lock messages + add sControlHeights to item 2 of theTopLeft + + ## We store each column's controls in separate list + put "control id" && word 3 of theControl && "of me" & cr after sTableObjectsA["columns"][theColumn]["row controls"] + end repeat + + delete the last char of sTableObjectsA["columns"][theColumn]["row controls"] + end repeat + + put the number of lines of sTableObjectsA["columns"][line 1 of pColumns]["row controls"] into sTableObjectsA["row control count"] + + unlock messages + + set the lockMessages to msgsAreLocked + return empty +end _table.CreateControlsForColumns + + +private command _table.DrawControlsInRealTime pForceRefresh + local theColumnsA + put _table.AreColumnsVisibleWithinMask() into theColumnsA + + if the keys of sTableObjectsA["columns"] is empty or sTableObjectsA["columns"][line 1 of theColumnsA["visible"]]["group"] is empty then + _table.CreateColumns + end if + + ## Make sure there are enough controls + _table.FillListWithJustEnoughControls + local controlCountWasModified + put the result into controlCountWasModified + + ## We use sequencing to draw, not indexes + set the wholeMatches to true + local theIndexesInSequence + put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexesInSequence + local theControlIndex + put 0 into theControlIndex + + ## Do we need to redraw? + local noRedrawNeeded + put not controlCountWasModified and \ + sTableObjectsA["base sequence for last rendering"] is sTableObjectsA["base sequence for visible controls"] into noRedrawNeeded + + if not noRedrawNeeded or pForceRefresh then + if pForceRefresh then + ## force refresh should redraw all columns at once + _table.DrawColumns _table.VisibleColumns() + -- put "drawing all columns:" && the milliseconds + else + _table.DrawColumns theColumnsA["visible"] --the dgProps["columns"] of me + + ## If user is interacting with scrollbar then no need to throttle. + ## Just redraw on mouseUp + cancel sPendingMsgsA["draw hidden columns"] + if not sRunningActionsA["user is vscrolling"] then + local theHiddenColumns + put theColumnsA["hidden"] into theHiddenColumns + send "table.DrawColumns theHiddenColumns" to me in 200 milliseconds + put the result into sPendingMsgsA["draw hidden columns"] + end if + end if + + ## Cache what we started on last time + put sTableObjectsA["base sequence for visible controls"] into sTableObjectsA["base sequence for last rendering"] + end if + + return empty +end _table.DrawControlsInRealTime + + +## Needed for send call in _table.DrawControlsInRealTime +command table.DrawColumns pColumns, pIndexesToDraw + _table.DrawColumns pColumns, pIndexesToDraw +end table.DrawColumns + + +private command _table.DrawColumns pColumns, pIndexesToDraw + local theStart + put the milliseconds into theStart #####!!!!! + + if pColumns is empty then return empty + + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the wholeMatches to true + + ## Default is not to pass in value for pIndexes to draw in which case + ## we use the base sequence for visible controls to determine indexes to draw + if pIndexesToDraw is not empty then + local theSequence + put itemOffset(item 1 of pIndexesToDraw, sIndexSequencing) - 1 into theSequence + else + put item sTableObjectsA["base sequence for visible controls"] to \ + (sTableObjectsA["base sequence for visible controls"] + sTableObjectsA["row control count"] - 1) of sIndexSequencing into pIndexesToDraw + put sTableObjectsA["base sequence for visible controls"] - 1 into theSequence + end if + + ## Initialize now as this is used regardless of whether or not we have indexes to draw + local theControlIndex + put 0 into theControlIndex + + if pIndexesToDraw is not empty then + ## Get geometry properties + local theListGroupRect, theTopLeft + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + + ## How many vertical controls do we need to draw? + -- put _ControlsRequiredToFillSpace() into theMaxControlNumber + + repeat for each line theColumn in pColumns + ## Get lookup table for indexes that already have controls with correct data + local theTopLeftA, theMasterControlList + put the topLeft of sTableObjectsA["columns"][theColumn]["group"] into theTopLeftA[theColumn] + put _GenerateReorderedControlList(sTableObjectsA["columns"][theColumn]["row controls"], pIndexesToDraw) into theMasterControlList[theColumn] + + ## Store line indexes + put empty into sTableObjectsA["columns"][theColumn]["control line numbers"] + repeat for each line theControl in theMasterControlList[theColumn] + put lineOffset(theControl, sTableObjectsA["columns"][theColumn]["row controls"]) & comma after sTableObjectsA["columns"][theColumn]["control line numbers"] + end repeat + delete the last char of sTableObjectsA["columns"][theColumn]["control line numbers"] + end repeat + -- PrintKeys theMasterControlList + -- put cr & cr & the executioncontexts after msg + + ## Draw it + unlock messages + repeat for each item theIndex in pIndexesToDraw + add 1 to theControlIndex + add 1 to theSequence + + ## get row data + local theDataA + if sDataArray[theIndex] is NULL then + GetDataForLine theSequence, theDataA + end if + + ## Deal with rows controls + repeat for each line theColumn in pColumns + put line theControlIndex of theMasterControlList[theColumn] into theControl + + -- if there is not a theControl then + -- put "Control for index " & theControlIndex & " does not exist for column " & theColumn & cr & cr & \ + -- the executioncontexts & cr & cr & \ + -- "theMasterControlList:" & cr & _PrintKeys(theMasterControlList) & cr & cr & \ + -- "sDataArray:" && _PrintKeys(sDataArray) after msg + -- end if + local theCurrentIndex + put the dgIndex of theControl into theCurrentIndex + if theIndex is not theCurrentIndex then + ## Allow developer to do something if unloading control + if theCurrentIndex is not empty then + unlock messages + dispatch "PreFillInData" to theControl + lock messages + end if + + set the visible of theControl to true + lock messages + set the dgIndex of theControl to theIndex + unlock messages + if sDataArray[theIndex] is NULL then + dispatch "FillInData" to theControl with theDataA[theColumn] + else + dispatch "FillInData" to theControl with sDataArray[theIndex][theColumn] + end if + else + -- put "not drawing index " & theIndex & " for column" && theColumn & cr after msg + -- no need to redraw + end if + + set the topLeft of theControl to theTopLeftA[theColumn] + add sControlHeights to item 2 of theTopLeftA[theColumn] + end repeat + + ## Hilited index? + if theIndex is among the items of sHilitedIndexes then + _table.HiliteRow theControlIndex, true + else + _table.HiliteRow theControlIndex, false + end if + end repeat + + put pIndexesToDraw into sTableObjectsA["current"]["indexes"] + end if + + ## Reset hilites and hide any extra controls for columns + lock messages + repeat for each line theColumn in pColumns + _ResetControls line (theControlIndex + 1) to -1 of theMasterControlList[theColumn] + end repeat + repeat with theControlIndex = theControlIndex + 1 to the number of lines of theMasterControlList[line 1 of pColumns] + _table.HiliteRow theControlIndex, false + end repeat + unlock messages + + -- put "time spent in" && param(0) & ":" && the milliseconds - theStart & cr --after msg + + set the lockMessages to msgsAreLocked + unlock screen + + -- put theLog & cr after msg + return empty +end _table.DrawColumns + + +private command _table.HiliteIndexesInVisibleControls + local theColumn, i, theIndexes, theBoolean + put line 1 of _table.VisibleColumns() into theColumn + if theColumn is empty then return empty + + set the wholeMatches to true + lock screen + put 0 into i + put item sTableObjectsA["base sequence for visible controls"] to \ + (sTableObjectsA["base sequence for visible controls"] + sTableObjectsA["row control count"]) of sIndexSequencing into theIndexes + repeat for each item theIndex in theIndexes + add 1 to i + put theIndex is among the items of sHilitedIndexes into theBoolean + _table.HiliteRow i, theBoolean + end repeat + unlock screen +end _table.HiliteIndexesInVisibleControls + + +private command _table.HiliteRow pRow, pBoolean + local theControl, theColumns + put line pRow of sTableObjectsA["row hilite controls"] into theControl + if theControl is empty then return empty + + put _table.VisibleColumns() into theColumns + + local msgsAreLocked + put the lockMessages into msgsAreLocked + unlock messages + + lock screen + set the visible of theControl to pBoolean + + repeat for each line theColumn in theColumns + local theLineNo + put item pRow of sTableObjectsA["columns"][theColumn]["control line numbers"] into theLineNo + put line theLineNo of sTableObjectsA["columns"][theColumn]["row controls"] into theControl + if theControl is empty then exit repeat + set the dgHilite of theControl to pBoolean + end repeat + unlock screen + set the lockMessages to msgsAreLocked +end _table.HiliteRow + + +private command _table.ConfigureTemplateFieldForColumn pColumn, pFieldHeight + reset the templatefield + + if pFieldHeight is empty then put kDefaultRowHeight into pFieldHeight + + set the traversalOn of the templatefield to false + set the autoTab of the templatefield to true + set the dontWrap of the templatefield to true + set the showBorder of the templatefield to false + set the borderWidth of the templatefield to 2 + set the margins of the templatefield to 8 + set the lockText of the templatefield to true + set the opaque of the templatefield to false + set the height of the templatefield to pFieldHeight + + return empty +end _table.ConfigureTemplateFieldForColumn + + +private command _table.CacheCustomTemplateUsage + local theTemplateGroup, theColumns, templateExists + put the dgProps["row template"] of me into theTemplateGroup + put the dgProps["columns"] of me into theColumns + + put there is a theTemplateGroup into templateExists + repeat for each line theColumn in theColumns + if templateExists then + put there is a control theColumn of theTemplateGroup \ + and the long ID of the owner of control theColumn of theTemplateGroup is the long ID of theTemplateGroup \ + into sTableObjectsA["columns"][theColumn]["uses custom template"] + put there is a control (theColumn && "[Header]") of theTemplateGroup \ + and the long ID of the owner of control (theColumn && "[Header]") of theTemplateGroup is the long ID of theTemplateGroup \ + into sTableObjectsA["columns"][theColumn]["header"]["uses custom template"] + else + put false into sTableObjectsA["columns"][theColumn]["uses custom template"] + put false into sTableObjectsA["columns"][theColumn]["header"]["uses custom template"] + end if + end repeat +end _table.CacheCustomTemplateUsage + + +private command _table.CalculateFormattedHeight + ## Cache which are custom + _table.CacheCustomTemplateUsage + + ## Fill in row height + put the dgProps["row height"] of me into sControlHeights + if sControlHeights is not an integer or sControlHeights < 1 then put kDefaultRowHeight into sControlHeights + put sControlHeights * the number of elements of sDataArray into sFormattedHeight +end _table.CalculateFormattedHeight + + +private command _table.RegenerateColumns + lock screen + _table.CreateColumns + + _table.LayoutRowHilites + _table.CreateControlsForColumns _table.VisibleColumns() + -- set the uEffectiveColumnWidths of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me \ + -- to _table.GetEffectiveColumnWidths() + + unlock screen +end _table.RegenerateColumns + + +## Return list of visible controls in proper order +private function _ListOfVisibleControls + local theControls + if _ControlType() is "table" then + ## list of controls for a column contains all visible controls. + ## There might be less data than controls. + repeat for each line theControl in sTableObjectsA["columns"][ _table.FirstVisibleColumn() ]["row controls"] + if the visible of theControl then + put theControl & cr after theControls + end if + end repeat + delete the last char of theControls + return _GenerateReorderedControlList(theControls, sTableObjectsA["current"]["indexes"]) + else + return sTableObjectsA["visible row controls"] + end if +end _ListOfVisibleControls + + +private function _table.FirstVisibleColumn + ----- + local theColPropsA, theColumn, theColumns + local theVisibleColumns + ----- + put the dgProps["columns"] of me into theColumns + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in theColumns + if theColPropsA[theColumn]["visible"] is not false then + return theColumn + end if + end repeat + return empty +end _table.FirstVisibleColumn + + +private function _table.VisibleColumns + ----- + local theColPropsA, theColumn, theColumns + local theVisibleColumns + ----- + put the dgProps["columns"] of me into theColumns + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in theColumns + if theColPropsA[theColumn]["visible"] is not false then + put theColumn & cr after theVisibleColumns + end if + end repeat + delete the last char of theVisibleColumns + return theVisibleColumns +end _table.VisibleColumns + + +## Returns array [hidden|visible] containing list of column +## names that are hidden and visible within the list mask +private function _table.AreColumnsVisibleWithinMask + local theColumns, theWidths + put _table.VisibleColumns() into theColumns + put _table.GetEffectiveColumnWidths() into theWidths + + local theMinX, theRect, theVisibleWidth, theMaxX, theItemNo, theTotalWidth + put the dgHScroll of me into theMinX + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theRect + put the left of scrollbar "dgScrollbar" of me - item 1 of theRect into theVisibleWidth + put theMinX + theVisibleWidth into theMaxX + + put 0 into theItemNo + put 0 into theTotalWidth + repeat for each line theColumn in theColumns + local theColumnsA + if theTotalWidth > theMaxX then + put theColumn & cr after theColumnsA["hidden"] + else + add 1 to theItemNo + local theColWidth + put item theItemNo of theWidths into theColWidth + if theTotalWidth + theColWidth < theMinX then + put theColumn & cr after theColumnsA["hidden"] + add theColWidth to theTotalWidth + else + put theColumn & cr after theColumnsA["visible"] + add theColWidth to theTotalWidth + end if + end if + end repeat + + return theColumnsA +end _table.AreColumnsVisibleWithinMask + + +private command _table.CreateColumns + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local theResourceStack + put _ResourceStack() into theResourceStack + + local theOrigHScroll + put _GetHScrollPercent() into theOrigHScroll + _ResetHScrollToZero + + ## Note: We generate a group for all columns whether visible or not + ## This is just easier for the time being. Perhaps change later. + local theColumns, theTopLeft + put the dgProps["columns"] of me into theColumns + put item 1 to 2 of the rect of group "dgList" of me into theTopLeft + + ## Loop through existing columns and delete out those that are no + ## longer included + set the wholeMatches to true + repeat for each key theColumn in sTableObjectsA["columns"] + if theColumn is not among the lines of theColumns then + _table.DeleteColumn theColumn + end if + end repeat + + ## delete column props (I don't think this is necessary since + ## adding _table.deleteColumn but haven't tested yet) + local theColPropsA + put the dgProps["column properties"] of me into theColPropsA + repeat for each key theColumn in theColPropsA + if theColumn is not among the lines of theColumns then + delete local theColPropsA[theColumn] + end if + end repeat + + _table.CacheCustomTemplateUsage + + _table.CreateHeaders + + ## Prepare to create controls + reset the templategroup + set the lockloc of the templategroup to true + set the showBorder of the templategroup to false + set the margins of the templategroup to 0 + set the borderWidth of the templategroup to 0 + set the showName of the templategroup to false + + reset the templategraphic + + -- put _CardOf() into theDGCard + + ## Create controls + repeat for each line theColumn in theColumns + ## Set default values + if theColumn is not among the keys of theColPropsA then + put true into theColPropsA[theColumn]["visible"] + put "left" into theColPropsA[theColumn]["alignment"] + put "ascending" into theColPropsA[theColumn]["sort direction"] + put "text" into theColPropsA[theColumn]["sort type"] + put false into theColPropsA[theColumn]["sort is case sensitive"] + put 100 into theColPropsA[theColumn]["width"] + put 40 into theColPropsA[theColumn]["min width"] + put 1000 into theColPropsA[theColumn]["max width"] + put true into theColPropsA[theColumn]["resizable"] + end if + + ## Column + if sTableObjectsA["columns"][theColumn]["group"] is empty then + create group theColumn in group "dgList" of me + put "control id" && word 3 of it && "of me" into sTableObjectsA["columns"][theColumn]["group"] + set the topLeft of it to theTopLeft + set the visible of it to theColPropsA[theColumn]["visible"] + set the behavior of it to the long ID of button "Column Group" of group "Behaviors" of theResourceStack + end if + + ## column divider + if sTableObjectsA["columns"][theColumn]["divider control"] is empty then + create graphic in group "dgDividers" of group "dgListMask" of me + put "control id" && word 3 of it && "of me" into sTableObjectsA["columns"][theColumn]["divider control"] + set the enabled of it to false ## don't want it to get messages + set the foregroundColor of it to the dgProps["column divider color"] of me + set the rect of it to theTopLeft, item 1 of theTopLeft + 1, item 2 of theTopLeft + 1 + end if + end repeat + + reset the templategroup + reset the templategraphic + + ## Toggle visibility controls + repeat for each line theColumn in theColumns + set the visible of sTableObjectsA["columns"][theColumn]["group"] to theColPropsA[theColumn]["visible"] + set the visible of sTableObjectsA["columns"][theColumn]["header"]["group"] to theColPropsA[theColumn]["visible"] + end repeat + + set the dgProps["column properties"] of me to theColPropsA + + _table.ResizeColumns + + unlock messages + + ## Outside of locked messages so content draws + _SetHScrollPercent theOrigHScroll + + set the lockMessages to msgsAreLocked + + unlock screen +end _table.CreateColumns + + +private command _table.CreateHeaders + local theResourceStack + put _ResourceStack() into theResourceStack + -- put _CardOf() into theDGCard + local theColumns, theHeaderGroup, theHeaderRect + put the dgProps["columns"] of me into theColumns + put the long ID of group "dgHeaderMask" of group "dgHeaderComponents" of me into theHeaderGroup + + put the rect of theHeaderGroup into theHeaderRect + put item 2 of theHeaderRect + the height of theHeaderGroup into item 4 of theHeaderRect + + ## Clear out existing headers that don't exist + set the wholeMatches to true + repeat for each key theColumn in sTableObjectsA["columns"] + if theColumn is not among the lines of theColumns and sTableObjectsA["columns"][theColumn]["header"]["group"] is not empty then + local theControl + put sTableObjectsA["columns"][theColumn]["header"]["group"] into theControl + delete theControl + delete local sTableObjectsA["columns"][theColumn]["header"] + end if + end repeat + + local theTemplateGroup + put the dgProps["row template"] of me into theTemplateGroup + + ## Create header groups + local theColsA, sortByThisColumn + put the dgProps["column properties"] of me into theColsA + put the dgProps["sort by column"] of me into sortByThisColumn + repeat for each line theColumn in theColumns + ## Column + if sTableObjectsA["columns"][theColumn]["header"]["group"] is empty then + if sTableObjectsA["columns"][theColumn]["header"]["uses custom template"] and \ + theTemplateGroup is not empty then + ## Use custom template provided by user... + copy control (theColumn && "[Header]") of theTemplateGroup to group "dgHeader" of me + local theGroup + put it into theGroup + set the name of theGroup to theColumn + set the lockloc of theGroup to true + put "control id" && word 3 of theGroup && "of me" into sTableObjectsA["columns"][theColumn]["header"]["group"] + local theRect + put item 1 to 2 of theHeaderRect, item 1 of theHeaderRect + 10, item 4 of theHeaderRect into theRect + set the rect of theGroup to theRect + else + _table.CreateDefaultHeaderGroup theColumn, theHeaderRect + put the result into theGroup + + if the dgProps["default header behavior"] of me is empty then + set the behavior of theGroup to the long ID of button "Default Header" of theResourceStack + else + set the behavior of theGroup to the dgProps["default header behavior"] of me + end if + end if + + unlock messages + if theColsA[theColumn]["label"] is not empty then + set the dgLabel [theColsA[theColumn]["encoding"]] of theGroup to theColsA[theColumn]["label"] + else + set the dgLabel of theGroup to theColumn + end if + set the dgTooltip of theGroup to theColsA[theColumn]["tooltip"] + set the dgHilite of theGroup to theColumn is sortByThisColumn + set the dgAlignment of theGroup to theColsA[theColumn]["header"]["alignment"] + lock messages + end if + end repeat +end _table.CreateHeaders + + +private command _table.CreateDefaultHeaderGroup pColumn, pHeaderRect + local theHeaderGroup + put the long ID of group "dgHeaderMask" of group "dgHeaderComponents" of me into theHeaderGroup + + reset the templategroup + set the lockloc of the templategroup to true + set the showBorder of the templategroup to false + set the margins of the templategroup to 0 + set the borderWidth of the templategroup to 0 + set the showName of the templategroup to false + + reset the templatefield + + set the borderWidth of the templatefield to 0 + set the showFocusBorder of the templatefield to false + set the autoHilite of the templatefield to false + set the threeD of the templatefield to false + set the lockText of the templatefield to true + set the dontWrap of the templatefield to true + set the opaque of the templatefield to false + set the textAlign of the templatefield to "left" + set the height of the templatefield to the textSize of the templatefield + 4 + set the traversalOn of the templateField to false + + -- put _CardOf() into theDGCard + + create group pColumn in group "dgHeader" of theHeaderGroup + local theGroup + put it into theGroup + put "control id" && word 3 of theGroup && "of me" into sTableObjectsA["columns"][pColumn]["header"]["group"] + local theRect + put item 1 to 2 of pHeaderRect, item 1 of pHeaderRect + 10, item 4 of pHeaderRect into theRect + set the rect of theGroup to theRect + + ## Background + reset the templategraphic + set the style of the templategraphic to "rectangle" + set the opaque of the templategraphic to true + set the backgroundColor of the templategraphic to empty + set the lineSize of the templategraphic to 0 + set the antialiased of the templategraphic to true + create graphic "Background" in theGroup + set the rect of it to theRect + + _table.HiliteHeaderBackground theGroup, the dgProps["header background hilite color"] of me + + ## Field + set the width of the templatefield to item 3 of theRect - item 1 of theRect + create field "HeaderLabel" in theGroup + local theField + put it into theField + + ## EJB - fix for bug 9575 21/02/12 + ## Old line + ## set the height of it to the formattedHeight of it - the bottomMargin of it + ## Now checking the height is > 0 as this line was failing where the dg was on a card that had not been opened + ## as the formattedHeight was 0 + + local tHeight + put the formattedHeight of it - the bottomMargin of it into tHeight + if tHeight < 1 then + ## nothing + else + set the height of it to tHeight + end if + + set the topLeft of theField to item 1 to 2 of theRect + + ## left hilite + set the lineSize of the templategraphic to 1 + set the antialiased of the templategraphic to false + create graphic "LeftHilite" in theGroup + set the foregroundColor of it to the dgProps["header divider threeD color"] of me + set the rect of it to item 1 of theRect + 1, item 2 of theRect, item 1 of theRect + 2, item 4 of theRect + + ## right hilite + create graphic "RightHilite" in theGroup + set the foregroundColor of it to the dgProps["header divider color"] of me + set the rect of it to item 3 of theRect - 1, item 2 of theRect, item 3 of theRect, item 4 of theRect + + ## Sort arrow + reset the templatebutton + set the style of the templatebutton to "transparent" + set the opaque of the templatebutton to false + set the showName of the templatebutton to false + set the threeD of the templatebutton to false + set the showBorder of the templatebutton to false + set the hiliteBorder of the templatebutton to false + set the borderWidth of the templatebutton to 0 + set the width of the templatebutton to 9 + set the height of the templatebutton to 8 + create button "SortArrow" in theGroup + + reset the templategroup + reset the templatefield + reset the templategraphic + reset the templatebutton + + return theGroup +end _table.CreateDefaultHeaderGroup + + +private command _table.RepositionHeadersAndColumns + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + + local theOrigHScrollPercent + put _GetHScrollPercent() into theOrigHScrollPercent + _ResetHScrollToZero + + lock messages + + _table.ResizeColumns + _table.RepositionHeaders + _table.RepositionColumns + + ## Restore H Scroll + _ConfigureHScrollbar + + set the lockMessages to msgsAreLocked + + ## Outside of lock messages so content redraws + _SetHScrollPercent theOrigHScrollPercent + + unlock screen +end _table.RepositionHeadersAndColumns + + +private command _table.ResizeColumns + ## in case it gets called before initialization + if the keys of sTableObjectsA["columns"] is empty then return empty + + put 0 into sFormattedWidth + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + + ## Start at 0 point + local theOrigVScrollPercent, theOrigHScrollPercent + put _GetVScrollPercent() into theOrigVScrollPercent + put _GetHScrollPercent() into theOrigHScrollPercent + _ResetScrollsToZero + + lock messages + + ## First resize headers + _table.ResizeHeaders + + ## Now resize columns + local theColumns + put _table.VisibleColumns() into theColumns + + ## Get in column widths + local theColWidths + put _table.GetEffectiveColumnWidths() into theColWidths + + ## Set rects + local theItemNo, theColWidth, theGroup, theRect + repeat for each line theColumn in theColumns + add 1 to theItemNo + put item theItemNo of theColWidths into theColWidth + add theColWidth to sFormattedWidth + + put sTableObjectsA["columns"][theColumn]["group"] into theGroup + put the rect of theGroup into theRect + put item 1 of theRect + theColWidth into item 3 of theRect + set the rect of theGroup to theRect + + put item 2 of theRect + sControlHeights into item 4 of theRect + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"] + put the rect of theControl into theRect + put item 1 of theRect + theColWidth into item 3 of theRect + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect + lock messages + end repeat + end repeat + + _AutoHideHScrollbar + + _table.LayoutDataArea + ## Old methods below. Didn't deal with auto hiding hscrollbar though. + -- _table.RepositionColumns + -- _table.ResizeList + -- _table.LayoutRowHilites + + ## Restore H Scroll + _ConfigureHScrollbar + _ConfigureScrollbar + + set the lockMessages to msgsAreLocked + + ## Outside of lockmessages so they redraw + _SetHScrollPercent theOrigHScrollPercent + _SetVScrollPercent theOrigVScrollPercent + + unlock screen +end _table.ResizeColumns + + +private command _table.ResizeList + local theRect + put the rect of group "dgList" of me into theRect + put the top of group "dgListMask" of me into item 2 of theRect + put item 1 of theRect + the width of graphic "dgBackground" of group "dgHeaderMask" of group "dgHeaderComponents" of me into item 3 of theRect + put the bottom of group "dgListMask" of me into item 4 of theRect + set the rect of group "dgList" of me to theRect +end _table.ResizeList + + +private command _table.ResizeHeaders + local theOrigHScroll + put _GetHScrollPercent() into theOrigHScroll + _ResetHScrollToZero + + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local theColumns, includeAllColumns, theColWidths, theGroupHeight, theTopLeft + put the dgProps["columns"] of me into theColumns + put true into includeAllColumns + put _table.GetEffectiveColumnWidths(includeAllColumns) into theColWidths + put the height of group "dgHeaderMask" of me into theGroupHeight + put item 1 to 2 of the rect of group "dgHeaderComponents" of me into theTopLeft + + local theHeaderWidth, theReduction + put 0 into theHeaderWidth + put 0 into theReduction + + repeat for each line theColumn in theColumns + local theItemNo, theColWidth, theRect + add 1 to theItemNo + put item theItemNo of theColWidths into theColWidth + + put theTopLeft into theRect + put item 1 of theRect + (theColWidth- theReduction) into item 3 of theRect + put item 2 of theRect + theGroupHeight into item 4 of theRect + + local theGroup + put sTableObjectsA["columns"][theColumn]["header"]["group"] into theGroup + set the rect of theGroup to theRect + + unlock messages + dispatch "LayoutControl" to theGroup with theRect + lock messages + + put item 3 of theRect & "," & item 2 of theRect into theTopLeft + + add theColWidth to theHeaderWidth + + ## all columns after 1 need to be reduced in width in order to make room for divider + -- put 1 into theReduction + end repeat + + _table.ResizeHeaderBackground + _table.RepositionHeaders + + unlock messages + _SetHScrollPercent theOrigHScroll + + set the lockMessages to msgsAreLocked +end _table.ResizeHeaders + + +private command _table.ResizeHeaderBackground + local theRect, theHeaderWidth, theSBWidth + ## Resize Background to fill visible space. Covers at least width of list group + if the width of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me > \ + the width of group "dgHeaderMask" of group "dgHeaderComponents" of me then + put the rect of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me into theRect + else + put the rect of group "dgHeaderMask" of group "dgHeaderComponents" of me into theRect + end if + put item 3 of theRect - item 1 of theRect into theHeaderWidth + + if the visible of scrollbar "dgScrollbar" of me then put the width of scrollbar "dgScrollbar" of me into theSBWidth + else put 0 into theSBWidth + + put item 1 of theRect + max(the width of me, theHeaderWidth + theSBWidth) into item 3 of theRect + put item 2 of theRect + the height of group "dgHeaderMask" of group "dgHeaderComponents" of me into item 4 of theRect + set the rect of graphic "dgBackground" of group "dgHeaderMask" of group "dgHeaderComponents" of me to theRect + set the rect of graphic "dgHeaderBottomBorder" of group "dgHeaderMask" of group "dgHeaderComponents" of me to item 1 of theRect, \ + item 4 of theRect - 1, item 3 of theRect, item 4 of theRect +end _table.ResizeHeaderBackground + + +private command _table.RepositionHeaders + local theColumns, theHeaderGroup, theTopLeft, theItemNo, theGroup + put _table.VisibleColumns() into theColumns + put the long ID of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me into theHeaderGroup + + put item 1 of the rect of group "dgHeaderComponents" of me into theTopLeft + put the top of theHeaderGroup into item 2 of theTopLeft + + repeat for each line theColumn in theColumns + add 1 to theItemNo + + ## Headers + put sTableObjectsA["columns"][theColumn]["header"]["group"] into theGroup + if the visible of theGroup then + set the topLeft of theGroup to theTopLeft + put the right of theGroup into item 1 of theTopLeft + end if + end repeat +end _table.RepositionHeaders + + +private command _table.RepositionColumns + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local theColumns + put _table.VisibleColumns() into theColumns + + local theOffset, theMasterRect, theTopLeft + put the hScroll of group "dgListMask" of me into theOffset + put the rect of group "dgListMask" of me into theMasterRect + subtract theOffset from item 1 of theMasterRect + subtract theOffset from item 3 of theMasterRect + put item 1 to 2 of theMasterRect into theTopLeft + + local theGroup, theGraphic + repeat for each line theColumn in theColumns + ## columns + put sTableObjectsA["columns"][theColumn]["group"] into theGroup + + if theGroup is not empty and the visible of theGroup then + set the topLeft of theGroup to theTopLeft + set the rect of theGroup to theTopLeft, the right of theGroup, item 4 of theMasterRect + put the right of theGroup into item 1 of theTopLeft + + ## Column dividers + put sTableObjectsA["columns"][theColumn]["divider control"] into theGraphic + set the rect of theGraphic to item 1 of theTopLeft - 1, item 2 of theTopLeft, \ + item 1 of theTopLeft, item 4 of theMasterRect + end if + end repeat + + set the lockMessages to msgsAreLocked + unlock screen +end _table.RepositionColumns + + +private function _table.GetEffectiveColumnWidths pIncludeAllColumns + ----- + local i + local theColPropsA, theColumn, theColumns + local theFillerWidth + local theWidths + ----- + if pIncludeAllColumns then + put the dgProps["columns"] of me into theColumns + else + put _table.VisibleColumns() into theColumns + end if + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in theColumns + if theColPropsA[theColumn]["width"] is empty then + put kDefaultTableColWidth & comma after theWidths + else + put theColPropsA[theColumn]["width"] & comma after theWidths + end if + end repeat + delete the last char of theWidths + + -- put max(the last item of theWidths, kDefaultTableColWidth) into theFillerWidth + -- repeat with i = the number of items of theWidths to the number of lines of theColumns + -- put theFillerWidth into item i of theWidths + -- end repeat + + return theWidths +end _table.GetEffectiveColumnWidths + + +--> Custom Properties (Data Manipulation) + + +setprop dgText [pTextIncludesColumnNames] pText + ----- + local theError + local theResult + local theColumns, theStartLineNo + ----- + lock screen + try + if pTextIncludesColumnNames is true then + put line 1 of pText into theColumns + replace tab with cr in theColumns + put 2 into theStartLineNo + else + put empty into theColumns + put 1 into theStartLineNo + end if + + switch _ControlType() + case "table" + _table.SetText line theStartLineNo to -1 of pText, theColumns + break + case "form" + default + _list.SetText line theStartLineNo to -1 of pText, theColumns + end switch + put the result into theResult + _DataCanBeRepresentedAsText true + catch e + put e into theError + end try + unlock screen + + if theError is not empty then throw theError + + return theResult +end dgText + + +getprop dgText [pIncludeColumnNames] + if the keys of sDataArray is empty then _RestorePersistentData ## In case control hasn't been opened yet + + switch _ControlType() + case "table" + return _table.GetText(pIncludeColumnNames) + break + case "form" + default + return _list.GetText(pIncludeColumnNames) + end switch +end dgText + + +getprop dgDataOfIndex [pIndex] + return sDataArray[pIndex] +end dgDataOfIndex + + +setprop dgDataOfIndex [pIndex] pDataArray + _DataCanBeRepresentedAsText false + + put pDataArray into sDataArray[pIndex] + _StorePersistentData + _RefreshIndexes pIndex +end dgDataOfIndex + + +getprop dgDataOfLine [pLine] + local theIndex + put the dgIndexOfLine [pLine] of me into theIndex + return sDataArray[theIndex] +end dgDataOfLine + + +setprop dgDataOfLine [pLine] pDataArray + _DataCanBeRepresentedAsText false + + local theIndex + put the dgIndexOfLine [pLine] of me into theIndex + put pDataArray into sDataArray[theIndex] + _StorePersistentData + _RefreshIndexes theIndex +end dgDataOfLine + + +getprop dgData + if the keys of sDataArray is empty then _RestorePersistentData ## In case control hasn't been opened yet + + return sDataArray +end dgData + + +setprop dgData [pSequencing] pDataArray + lock screen + + ## We must initialize before going on + if not sInit then _Initialize + + _ResetData + put pDataArray into sDataArray + if pSequencing is not empty then + put pSequencing into sIndexSequencing + else + ## Populate sequencing. This determines order of indexes in array + put the keys of sDataArray into sIndexSequencing + sort lines of sIndexSequencing numeric + replace cr with comma in sIndexSequencing + end if + + switch _ControlType() + case "table" + if the dgProps["sort by column"] of me is not empty then + SortByColumn the dgProps["sort by column"] of me + end if + break + end switch + + _StorePersistentData + _DrawList + + unlock screen +end dgData + + +## We can set the number of records. You can only get the number of lines as the number +## of lines is representative of the number of records. +getprop dgNumberOfLines + return max(0, the number of elements of sDataArray) +end dgNumberOfLines + + +getprop dgNumberOfRecords + return max(0, the number of elements of sDataArray) +end dgNumberOfRecords + + +## Calling this wipes out the array and creates empty values for +## records up to pNumber. These records will be filled in on an as needed basis +## when scrolling through the list. +setprop dgNumberOfRecords pNumber + _DataCanBeRepresentedAsText false + + if pNumber is not an integer or pNumber < 0 then put 0 into pNumber + set the dgProps["persistent data"] of me to false ## can't be persistent + put empty into sDataArray + put empty into sIndexSequencing + + repeat with i = 1 to pNumber + put NULL into sDataArray[i] + put i & comma after sIndexSequencing + end repeat + delete the last char of sIndexSequencing + + _DrawList +end dgNumberOfRecords + + +--> Custom Properties (General) + + +private function _ControlType + return the dgProps["style"] of me +end _ControlType + +getprop dgAnimating + return sIsAnimating +end dgAnimating + + +getprop uScriptLocal [pVarName] + local theDo + put "return" && pVarName into theDo + do theDo +end uScriptLocal + + +setprop dgFocus pValue + if pValue then + ## Don't pull focus from child control + if the long ID of me is not in the long ID of the focusedObject then + focus on graphic "dgBackground" of me + _UpdateHiliteColor + end if + else + focus on nothing + end if +end dgFocus + + +-- Returns column number of the target. Number is relative to visible columns. +getprop dgColumnNumber + local theColumn + put the dgColumn of the target into theColumn + if theColumn is not empty then + set the wholeMatches to true + return lineOffset(theColumn, _table.VisibleColumns()) + else + return 0 + end if +end dgColumnNumber + + +## This property is dynamic so we don't have to +## constantly update property as we add/delete controls +## The target is a list control +getprop dgLine + local theControl + put the dgDataControl of the target into theControl + if the long ID of theControl is not the long ID of the target then pass dgLine + + local theIndex + put the dgIndex of theControl into theIndex + return the dgLineOfIndex[theIndex] of me +end dgLine + + +## Returns indexes in order of sequencing +getprop dgIndexes + return sIndexSequencing +end dgIndexes + + +setprop dgIndexes pIndexes + put pIndexes into sIndexSequencing + + _StorePersistentSequence + + lock screen + _ResetIndexesOnControls + _RedrawList + unlock screen +end dgIndexes + + +## Lines and sequences are synonymous +getprop dgIndexOfLine [pLine] + set the wholeMatches to true + return item pLine of sIndexSequencing +end dgIndexOfLine + + +## Use to reorder an index +setprop dgLineOfIndex [pIndex] pLine + _SetSequenceOfIndex pIndex, pLine + RefreshList +end dgLineOfIndex + + +getprop dgLineOfIndex [pIndex] + set the wholeMatches to true + return itemOffset(pIndex, sIndexSequencing) +end dgLineOfIndex + + +## doesn't refresh +command SetLineOfIndex pIndex, pLine + _SetSequenceOfIndex pIndex, pLine +end SetLineOfIndex + + +getprop dgVisibleLines + return _VisibleSequences() +end dgVisibleLines + + +private function _VisibleSequences + local theControls + put _ListOfVisibleControls() into theControls + if theControls is empty or the keys of sDataArray is empty then return "0,0" + + local theMaskRect, theFirstSequence, theLastSequence + put the rect of group "dgList" of me into theMaskRect + + put empty into theFirstSequence + put empty into theLastSequence + + repeat for each line theControl in theControls + local theRect, theLineNo + put the rect of theControl into theRect + ## When checking if opposite coordinate is in view don't use =. = does not mean visible in this case. + ## e.g. is top of control above the bottom of the mask rect? + if (item 2 of theRect >= item 2 of theMaskRect and item 2 of theRect < item 4 of theMaskRect) or \ + (item 4 of theRect > item 2 of theMaskRect and item 4 of theRect <= item 4 of theMaskRect) then + put the dgLine of theControl into theLineNo + if theLineNo > 0 then + if theFirstSequence is empty then put theLineNo into theFirstSequence + else put min(theLineNo, theFirstSequence) into theFirstSequence + if theLastSequence is empty then put theLineNo into theLastSequence + else put max(theLineNo, theLastSequence) into theLastSequence + end if + end if + end repeat + + return theFirstSequence & comma & theLastSequence +end _VisibleSequences + + +## Returns a return delimited list of the value of pKey for all highlighted indexes. +getprop dgKeyValuesOfHilitedIndexes [pKey] + return GetKeyValuesOfIndexes(sHilitedIndexes, cr, pKey) +end dgKeyValuesOfHilitedIndexes + + +getprop dgFormattedHeight + return sFormattedHeight +end dgFormattedHeight + + +getprop dgFormattedWidth + return sFormattedWidth +end dgFormattedWidth + + +## temporary aliases +setprop uProps [pProp] pValue + if the target is not me then pass uProps + set the dgProps[pProp] of me to pValue +end uProps + + +getprop uProps[pProp] + if the target is not me then pass uProps + return the dgProps[pProp] of me +end uProps +## end temporary aliases + + +setprop dgProp [pProp] pValue + set the dgProps[pProp] of me to pValue +end dgProp + + +getprop dgProp [pProp] + return the dgProps[pProp] of me +end dgProp + + +private function _IsListOPositivefIntegers pList, pMatchCount + if pMatchCount and the number of items of pList is not pMatchCount then return false + + repeat for each item theItem in pList + if theItem is not an integer or theItem < 0 then return false + end repeat + + return true +end _IsListOPositivefIntegers + + +## Setting this property resets control height properties +setprop dgProps [pProp] pValue + if the target is not me then pass dgProps + + switch pProp + case "ascending sort icon" + case "descending sort icon" + if pValue is not empty and pValue is not an integer then _ThrowError kErrInvalidInteger, pValue && "is not an integer" + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + + lock screen + local theSortBy + put the dgProps["sort by column"] of me into theSortBy + repeat for each key theColumn in sTableObjectsA["columns"] + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["header"]["group"] + set the dgHilite of theControl to theColumn is theSortBy + end repeat + end repeat + unlock screen + break + + case "border color" + if pValue is not a color and pValue is not empty then + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + + lock screen + set the borderColor of me to pValue + set the foregroundColor of graphic "dgHeaderBottomBorder" of me to pValue + unlock screen + break + + case "header margins" + case "column margins" + if pValue is not empty and pValue is not an integer and not (_IsListOPositivefIntegers(pValue, 4)) then + _ThrowError kErrInvalidProperty, "'" & pValue & "' is not a valid margin" + end if + + if pValue is an integer then + get pValue + repeat with i = 2 to 4 + put it into item i of pValue + end repeat + end if + + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + + if pProp is "header margins" then + repeat for each key theColumn in sTableObjectsA["columns"] + repeat for each line theControl in sTableObjectsA["columns"][theColumn]["header"]["group"] + dispatch "LayoutControl" to theControl with the rect of theControl + end repeat + end repeat + else + ResetList + end if + break + + case "scrollbar width" + if pValue is not "auto" and (pValue is not an integer or pValue < 0) then \ + then _ThrowError kErrInvalidInteger, pValue && "is not an integer >= 0 or 'auto'" + + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + + lock screen + _SetScrollbarWidth pValue + + if _ControlType() is "table" then + _table.LayoutDataArea + RefreshList + end if + unlock screen + break + + case "header height" + if pValue is not an integer or pValue < 0 then _ThrowError kErrInvalidInteger, pValue && "is not an integer >= 0" + lock screen + local theOrigVScroll, theRect + put _GetVScrollPercent() into theOrigVScroll + put the rect of group "dgHeaderMask" of me into theRect + put item 2 of theRect + pValue into item 4 of theRect + set the rect of group "dgHeaderMask" of me to theRect + _table.LayoutDataArea + _table.ResizeHeaders + #<mikey> + # Attempt to fix bug 12427 - resizing a header vertically doesn't resize the column dividers (also called the leftHilite and rightHilight). + # We do it here instead of _table.resizeHeader or _table.repositionHeaders b/c those handlers are designed to handle the user resizing the column by dragging + # on it.  To resize the column dividers there would mess with performance.  _table.ResizeHeaderBackground does not touch the column headers. + local rectOfMe + repeat for each line theColumn in the childControlNames of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me + put the rect of graphic "leftHilite" of group theColumn of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me into rectOfMe + put item 4 of theRect into item 4 of rectOfMe + set the rect of graphic "leftHilite" of group theColumn of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me to rectOfMe  +              + put the rect of graphic "rightHilite" of group theColumn of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me into rectOfMe + put item 4 of theRect into item 4 of rectOfMe + set the rect of graphic "rightHilite" of group theColumn of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me to rectOfMe  + end repeat # for each line theColumn of the childControlNames of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me + #</mikey> + ResizeToFit # TDK-2014-07-25: The list needs to be redrawn to fit in the new mask area. + unlock screen + break + + case "text font" + lock screen + if pValue is empty then + set the textFont of group "dgList" of me to pValue + else + local theStyle, theSize + put the textStyle of group "dgList" of me into theStyle + put the textSize of group "dgList" of me into theSize + set the textFont of group "dgList" of me to pValue + set the textStyle of group "dgList" of me to theStyle + set the textSize of group "dgList" of me to theSize + end if + unlock screen + break + + case "text style" + set the textStyle of group "dgList" of me to pValue + break + + case "text size" + set the textSize of group "dgList" of me to pValue + break + + case "text color" + set the textColor of group "dgList" of me to _ColorToRGB(pValue) + break + + case "header text font" + lock screen + if pValue is empty then + set the textFont of group "dgHeader" of me to pValue + else + put the textStyle of group "dgHeader" of me into theStyle + put the textSize of group "dgHeader" of me into theSize + set the textFont of group "dgHeader" of me to pValue + set the textStyle of group "dgHeader" of me to theStyle + set the textSize of group "dgHeader" of me to theSize + end if + unlock screen + break + + case "header text style" + lock screen + set the textStyle of group "dgHeader" of me to pValue + unlock screen + break + + case "header text size" + lock screen + set the textSize of group "dgHeader" of me to pValue + unlock screen + break + + case "header text color" + lock screen + set the textColor of group "dgHeader" of me to _ColorToRGB(pValue) + unlock screen + break + + case "show vscrollbar" + lock messages + if pValue is "auto" then + set the dgProps[pProp] of me to pValue + else + put pValue is true into pValue + set the dgProps[pProp] of me to pValue + end if + unlock messages + if pValue is "auto" then + _ToggleVScrollBarVisibility the thumbSize of scrollbar "dgScrollbar" of me < the endValue of scrollbar "dgScrollbar" of me + else + _ToggleVScrollBarVisibility the dgProps[pProp] of me + end if + break + + case "show hscrollbar" + lock messages + if pValue is "auto" then + set the dgProps[pProp] of me to pValue + else + put pValue is true into pValue + set the dgProps[pProp] of me to pValue + end if + unlock messages + if _ControlType() is "table" then + if pValue is "auto" then + _ToggleHScrollBarVisibility the thumbSize of scrollbar "dgHScrollbar" of me < the endValue of scrollbar "dgHScrollbar" of me + else + _ToggleHScrollBarVisibility the dgProps[pProp] of me + end if + end if + break + + case "corner color" + local theGraphic + put the long ID of graphic "dgCornerPiece" of group "dgHorizontalComponents" of me into theGraphic + set the backgroundColor of theGraphic to empty + + if pValue is an array then + ## Setting fillGradient + repeat for each key theKey in pValue + set the fillGradient[theKey] of theGraphic to pValue[theKey] + end repeat + + else if the number of lines of pValue is 2 and line 1 of pValue is a color and line 2 of pValue is a color then + ## Create gradient for developer + _SetGraphicGradient theGraphic, line 1 of pValue, line 2 of pValue + else if pValue is a color then + set the backgroundColor of theGraphic to pValue + else + set the backgroundColor of theGraphic to kDefaultCornerColor + put kDefaultCornerColor into pValue + end if + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + unlock screen + break + + case "header background color" + lock screen + + put the long ID of graphic "dgBackground" of group "dgHeaderMask" of group "dgHeaderComponents" of me into theGraphic + set the backgroundColor of theGraphic to empty + + if pValue is an array then + ## Setting fillGradient + repeat for each key theKey in pValue + set the fillGradient[theKey] of theGraphic to pValue[theKey] + end repeat + + else if the number of lines of pValue is 2 and line 1 of pValue is a color and line 2 of pValue is a color then + ## Create gradient for developer + _table.SetHeaderBkgrndGradient line 1 of pValue, line 2 of pValue + else if pValue is a color then + set the backgroundColor of theGraphic to pValue + else + _table.SetHeaderBkgrndGradient kHeaderBkgrndStartColor, kHeaderBkgrndEndColor + put kHeaderBkgrndStartColor & cr & kHeaderBkgrndEndColor into pValue + end if + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + unlock screen + break + + case "header background hilite color" + lock screen + if pValue is not an array and \ + (line 1 of pValue is not a color and line 2 of pValue is not a color) and \ + pValue is not a color then + put kHeaderBkgrndHiliteStartColor & cr & kHeaderBkgrndHiliteEndColor into pValue + end if + _table.SetHeaderBkgrndHiliteColor pValue + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + unlock screen + break + + case "header divider color" + case "header divider threed color" + lock screen + if pValue is not a color then + if pProp is "header divider color" then + put kHeaderDividerColor into pValue + else + put kHeaderDividerThreeDColor into pValue + end if + else + put _ColorToRGB(pValue) into pValue + end if + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + _table.UpdateHeaderDividerColors pValue + unlock screen + break + + case "style" + lock screen + _DeleteDataControls + + if pValue is "table" then + lock screen + show group "dgDividers" of group "dgListMask" of me + set the visible of group "dgHeaderComponents" of me to the dgProps["show header"] of me is true + show group "dgHorizontalComponents" of me + _table.RegenerateColumns + -- set the uEffectiveColumnWidths of group "dgHeader" of group "dgHeaderMask" of group "dgHeaderComponents" of me \ + -- to _table.GetEffectiveColumnWidths() + + ## Set any props that have special settings for table. + lock messages + set the dgProps["cache controls"] of me to false + unlock messages + unlock screen + else + put "form" into pValue + hide group "dgDividers" of group "dgListMask" of me + hide group "dgHeaderComponents" of me + hide group "dgHorizontalComponents" of me + _table.DeleteColumnControls + put empty into sTableObjectsA + end if + + lock messages ## in case target is a child of me + set the dgProps["style"] of me to pValue + unlock messages + + ResizeToFit + ResetList + unlock screen + break + + case "record template" ## early dev versions + case "row template" + put "row template" into pProp + if pValue is not empty and there is not a pValue then + answer quote & pValue & quote && "does not exist. Cannot set" && pProp & "." + else if pValue is not empty and word 1 of pValue is not "group" then + answer quote & pValue & quote && "is not a group. Cannot set" && pProp & "." + else + if pValue is not empty then + put _CustomControlReference(pValue) into pValue + end if + + lock messages ## in case target is a child of me + set the dgProps["row template"] of me to pValue + unlock messages + put empty into sFormattedHeight + put empty into sControlHeights + + DG2_EnsureRowChainedBehavior + end if + break + + case "persistent data" + lock messages ## in case target is a child of me + set the dgProps["persistent data"] of me to pValue is true + unlock messages + + if pValue then + _StorePersistentData + else + set the customProperties["dgCache"] of me to empty + end if + break + + case "fixed control height" ## early dev builds + case "fixed row height" + put "fixed row height" into pProp + ## Setting this property resets control height properties + lock messages + set the dgProps[pProp] of me to pValue is true + unlock messages + put empty into sFormattedHeight + put empty into sControlHeights + + ResetList + break + + case "multiple lines" + case "cache controls" + case "auto hilite" + case "animate selections" + case "data can be represented as text" + case "dim on focusOut" + case "allow editing" + case "allow column resizing" + case "scroll when vscrollbar is hidden" + case "scroll when hscrollbar is hidden" + case "scroll selections into view" + + case "animate actions" + case "enable swipe" + lock messages + set the dgProps[pProp] of me to pValue is true + unlock messages + break + + case "edit mode action control" + case "edit mode action select control" + case "edit mode reorder control" + case "left swipe control" + case "right swipe control" + if pValue is not empty and there is not a pValue then + answer quote & pValue & quote && "does not exist. Cannot set" && pProp & "." + else + if pValue is not empty then + put _CustomControlReference(pValue) into pValue + end if + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + + -- We're setting new template controls. Redraw the list to take these new controls into account. + DG2_CustomisableControlsClearByName pProp + RefreshList + end if + break + + case "alternate row colors" + lock messages + set the dgProps[pProp] of me to pValue is true + unlock messages + + lock screen + _DrawAlternatingRows + _ShowAlternatingRows + + if _ControlType() is "form" then + _list.UpdateAlternatingRowColors + end if + unlock screen + break + + case "opaque" + set the opaque of graphic "dgBackground" of me to pValue is true + break + + case "background color" + if pValue is a color or pValue is empty then + put _ColorToRGB(pValue) into pValue + set the backgroundColor of graphic "dgBackground" of me to pValue + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "row color" + if pValue is a color or pValue is empty then + lock messages + set the dgProps[pProp] of me to _ColorToRGB(pValue) + unlock messages + + ## Update colors + lock screen + _DrawAlternatingRows + + if _ControlType() is "form" then + _list.UpdateAlternatingRowColors + end if + unlock screen + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "alternate row color" + if pValue is a color or pValue is empty then + lock messages + set the dgProps[pProp] of me to _ColorToRGB(pValue) + unlock messages + + ## Update colors + lock screen + _DrawAlternatingRows + + if _ControlType() is "form" then + _list.UpdateAlternatingRowColors + end if + unlock screen + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "column divider color" + if pValue is a color or pValue is empty then + lock messages + set the dgProps[pProp] of me to _ColorToRGB(pValue) + unlock messages + + repeat for each line theColumn in the dgProps["columns"] of me + put sTableObjectsA["columns"][theColumn]["divider control"] into theControl + if there is a theControl then + set the foregroundColor of theControl to _GetEffectiveColor("column divider color") + end if + end repeat + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "hilite color" + case "dimmed hilite color" + if pValue is a color or pValue is empty then + lock messages + set the dgProps[pProp] of me to _ColorToRGB(pValue) + unlock messages + + ## update color + if _ControlType() is "table" then + _table.LayoutRowHilites + else + _HiliteIndexesInVisibleControls + end if + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "hilited text color" + if pValue is a color or pValue is empty then + lock messages + set the dgProps[pProp] of me to _ColorToRGB(pValue) + unlock messages + else + _ThrowError kErrInvalidColor, pValue && "is not a color" + end if + break + + case "scrollbar offset" + ## deprecated, no longer used + if pValue is not a point then + _ThrowError kErrInvalidPoint, pValue && "is not a point" + end if + lock messages + set the dgProps["scrollbar corner offset"] of me to item 2 of pValue + unlock messages + ResizeToFit + break + + case "scrollbar corner offset" + if pValue is not an integer or pValue < 0 then + _ThrowError kErrInvalidInteger, pValue && "is not an integer >= 0" + end if + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + ResizeToFit + break + + case "row height" + if pValue is not empty and (pValue is not an integer or pValue < 0) then + _ThrowError kErrInvalidInteger, pValue && "is not an integer" + else + lock messages + set the dgProps[pProp] of me to pValue + unlock messages + lock screen + + -- Update any customisable controls to take into account the row resize. + DG2_CustomisableControlsResizeDefaults + DG2_CustomisableControlsClear + + ResetList + unlock screen + end if + break + + ## Table + + case "sort by column" + _SortByColumn pValue + break + + case "show header" + -- lock messages + -- set the dgProps [pProp] of me to pValue + -- unlock messages + lock screen + set the visible of group "dgHeaderComponents" of me to pValue is true + ResizeToFit + unlock screen + break + + case "columns" + put word 1 to -1 of pValue into pValue + repeat for each line theLine in pValue + if theLine is empty then _ThrowError kErrInvalidProperty, "column name cannot be empty'" + local theLinesA + if theLinesA[theLine] is not empty then _ThrowError kErrInvalidProperty, "duplicate column name '" & theLine & "'" + put 1 into theLinesA[theLine] + end repeat + + lock messages + set the dgProps [pProp] of me to pValue + + ## Don't sort by a non-existent column + if the dgProps["sort by column"] of me is not empty \ + and the dgProps["sort by column"] of me is not among the lines of pValue then + set the dgProps["sort by column"] of me to empty + end if + + unlock messages + + lock screen + _table.RegenerateColumns + + _table.DrawColumns _table.VisibleColumns() + unlock screen + break + + case "column labels" + lock screen + repeat for each line theColumn in the dgProps["columns"] of me + add 1 to i + set the dgColumnLabel [theColumn] of me to line i of pValue + end repeat + unlock screen + break + + case "column widths" + lock screen + local theLastWidth, theWidth + put item -1 of pValue into theLastWidth + if theLastWidth is not an integer then + _ThrowError kErrInvalidInteger, "invalid column width value '" & pValue & "'" + end if + + repeat for each line theColumn in the dgProps["columns"] of me + add 1 to i + put item i of pValue into theWidth + if theWidth is not an integer then put theLastWidth into theWidth + _StoreColWidth theColumn, theWidth + end repeat + + _table.ResizeColumns + + unlock screen + break + + case "show column dividers" + set the visible of group "dgDividers" of group "dgListMask" of me to pValue is true + break + + case "column alignments" + lock screen + repeat for each line theColumn in the dgProps["columns"] of me + add 1 to i + set the dgColumnAlignment [theColumn] of me to item i of pValue + end repeat + unlock screen + break + + case "column visibility" + lock screen + repeat for each line theColumn in the dgProps["columns"] of me + add 1 to i + set the dgColumnIsVisible [theColumn] of me to item i of pValue + end repeat + unlock screen + break + + case "default column behavior" + if pValue is not empty then + put _CustomControlReference(pValue) into pValue + end if + + lock messages ## in case target is a child of me + set the dgProps["default column behavior"] of me to pValue + unlock messages + break + + case "default header behavior" + if pValue is not empty then + put _CustomControlReference(pValue) into pValue + end if + + lock messages ## in case target is a child of me + set the dgProps["default header behavior"] of me to pValue + unlock messages + break + + case "control type" + lock messages + set the dgProps[pProp] of me to "Data Grid" + unlock messages + break + + case "minimal layout" + lock messages + set the dgProps[pProp] of me to pValue is true + unlock messages + break + + default + throw "invalid property '" & pProp & "'" + end switch + + -- pass dgProps + return empty +end dgProps + + +getprop dgProps [pProp] + if the target is not me then pass dgProps + + local theValue + + switch pProp + case "ascending sort icon" + lock messages + get the dgProps[pProp] of me + unlock messages + if it < 1 then get "103004" + return it + break + case "descending sort icon" + lock messages + get the dgProps[pProp] of me + unlock messages + if it < 1 then get "103005" + return it + break + case "header margins" + case "column margins" + lock messages + get the dgProps[pProp] of me + if it is empty then get 8 + unlock messages + return it + break + case "header height" + return the height of group "dgHeader" of me + break + + case "text font" + return the textFont of group "dgList" of me + break + + case "effective text font" + return the effective textFont of group "dgList" of me + break + + case "text style" + return the textStyle of group "dgList" of me + break + + case "effective text style" + return the effective textStyle of group "dgList" of me + break + + case "text size" + return the textSize of group "dgList" of me + break + + case "effective text size" + return the effective textSize of group "dgList" of me + break + + case "header text font" + return the textFont of group "dgHeader" of me + break + + case "effective header text font" + return the effective textFont of group "dgHeader" of me + break + + case "header text style" + return the textStyle of group "dgHeader" of me + break + + case "effective header text style" + return the effective textStyle of group "dgHeader" of me + break + + case "header text size" + return the textSize of group "dgHeader" of me + break + + case "effective header text size" + return the effective textSize of group "dgHeader" of me + break + + case "header text color" + return the textColor of group "dgHeader" of me + break + + case "effective header text color" + return the effective textColor of group "dgHeader" of me + break + + case "effective alternate row color" + case "effective column divider color" + case "effective row color" + case "effective dimmed hilite color" + case "effective hilite color" + return _GetEffectiveColor(word 2 to -1 of pProp) + break + + case "effective text color" + return the effective textColor of group "dgList" of me + break + + case "text color" + return the textColor of group "dgList" of me + break + + case "hilited text color" + return _GetEffectiveColor(pProp) + break + + case "border color" + return the borderColor of me + break + + case "effective border color" + return the effective borderColor of me + break + + case "background color" + local tColor + if the dgProps[pProp] of me is not a color then + return the backgroundColor of graphic "dgBackground" of me + else + return the dgProps[pProp] of me + end if + break + + case "opaque" + return the opaque of graphic "dgBackground" of me + break + + case "visible columns" + if _ControlType() is "table" then + return _table.VisibleColumns() + else + return empty + end if + break + + case "column widths" + local theColPropsA + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in the dgProps["columns"] of me + put theColPropsA[theColumn]["width"] & comma after theValue + end repeat + delete the last char of theValue + return theValue + break + + case "column labels" + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in the dgProps["columns"] of me + put theColPropsA[theColumn]["label"] & cr after theValue + end repeat + delete the last char of theValue + return theValue + break + + case "column visibility" + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in the dgProps["columns"] of me + put theColPropsA[theColumn]["visible"] & comma after theValue + end repeat + delete the last char of theValue + return theValue + break + + case "column alignments" + put the dgProps["column properties"] of me into theColPropsA + repeat for each line theColumn in the dgProps["columns"] of me + put theColPropsA[theColumn]["alignment"] & comma after theValue + end repeat + delete the last char of theValue + return theValue + break + + case "show column dividers" + return the visible of group "dgDividers" of group "dgListMask" of me + break + + case "show header" + return the visible of group "dgHeaderComponents" of me + break + + case "effective hilite color" + return _GetHiliteColor() + break + + case "effective scrollbar width" + return the width of scrollbar "dgScrollbar" of me + break + + case "scrollbar corner offset" + ## Forced integers >= 0 + lock messages + put the dgProps[pProp] of me into theValue + unlock messages + return max(0, theValue) + break + + case "record template" ## early dev versions + return the dgProps["row template"] of me + break + + case "fixed control height" ## early dev versions + return the dgProps["fixed row height"] of me + break + + case "minimal layout" + return the dgProps["minimal layout"] of me + break + end switch + + pass dgProps +end dgProps + + +## Renames a column +setprop dgColumnName [pColumn] pValue + if word 1 to -1 of pValue is empty or char 1 of pValue is space or the last char of pValue is space then + _ThrowError kErrInvalidProperty, quote & pValue & quote && "is not a valid column name" + end if + + set the wholeMatches to true + + ## Update list of columns, replacing line with old name with new name + local theColumns, theLineNo, theBadLineNo + put the dgProps["columns"] of me into theColumns + put lineOffset(pColumn, theColumns) into theLineNo + + if theLineNo is 0 then _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + + put lineOffset(pValue, theColumns) into theBadLineNo + if theBadLineNo > 0 then _ThrowError kErrRenameErrorInDestination, "column '" & pValue & "' already exists" + + lock screen + + local theSortByColumn + put the dgProps["sort by column"] of me into theSortByColumn + + ## Rename column + put pValue into line theLineNo of theColumns + lock messages + set the dgProps["columns"] of me to theColumns + + ## rename column properties + local theColPropsA + put the dgProps["column properties"] of me into theColPropsA + put theColPropsA[pColumn] into theColPropsA[pValue] + set the dgProps["column properties"] of me to theColPropsA + unlock messages + + ## Rename data keys + repeat for each key theKey in sDataArray + put sDataArray[theKey][pColumn] into sDataArray[theKey][pValue] + delete local sDataArray[theKey][pColumn] + end repeat + + _table.DeleteColumn pColumn + + ## refresh + _table.RegenerateColumns + _table.DrawColumns pValue + + if theSortByColumn is pColumn then + _SortByColumn pValue + end if + + _StorePersistentData + + unlock screen +end dgColumnName + + +setprop dgColumnSortType [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not among the items kSortTypes then + _ThrowError kErrInvalidProperty, "invalid column sort type value '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["sort type"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## Update sort if need be + if the dgProps["sort by column"] of me is pColumn then + _SortByColumn pColumn + end if +end dgColumnSortType + +getprop dgColumnSortType [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["sort type"] +end dgColumnSortType + + +setprop dgColumnSortDirection [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not among the items "ascending,descending" then + _ThrowError kErrInvalidProperty, "invalid column sort direction value '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["sort direction"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## Update sort if need be + if the dgProps["sort by column"] of me is pColumn then + _SortByColumn pColumn + end if +end dgColumnSortDirection + +getprop dgColumnSortDirection [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["sort direction"] +end dgColumnSortDirection + + +setprop dgColumnSortIsCaseSensitive [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not a boolean then + _ThrowError kErrInvalidBoolean, "invalid boolean value for column sort is case sensitive '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["sort is case sensitive"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## Update sort if need be + if the dgProps["sort by column"] of me is pColumn then + _SortByColumn pColumn + end if +end dgColumnSortIsCaseSensitive + +getprop dgColumnSortIsCaseSensitive [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["sort is case sensitive"] +end dgColumnSortIsCaseSensitive + + +setprop dgColumnIsVisible [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not a boolean then + _ThrowError kErrInvalidBoolean, "invalid boolean value for column visibility '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["visible"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + if sTableObjectsA["columns"][pColumn]["group"] is not empty then + lock screen + set the visible of sTableObjectsA["columns"][pColumn]["group"] to pValue + set the visible of sTableObjectsA["columns"][pColumn]["header"]["group"] to pValue + set the visible of sTableObjectsA["columns"][pColumn]["divider control"] to pValue + + _table.RepositionHeadersAndColumns + + if sTableObjectsA["row control count"] > 0 then + _table.CreateControlsForColumns pColumn + _table.DrawColumns pColumn + + ## check for scrollbar show/hide + if the dgProps["show hscrollbar"] of me is "auto" then + ## todo: optimize so we don't toggle unless we need to + local theSetting + put the visible of group "dgHorizontalComponents" of me into theSetting + _AutoHideHScrollbar + if the visible of group "dgHorizontalComponents" of me is not theSetting then + _ToggleHScrollBarVisibility the visible of group "dgHorizontalComponents" of me + end if + end if + end if + unlock screen + end if +end dgColumnIsVisible + + +getprop dgColumnIsVisible [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["visible"] +end dgColumnIsVisible + + +setprop dgColumnLabel [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + + put pValue into theColsA[pColumn]["label"] + if the platform is "macos" then put "mac" into theColsA[pColumn]["encoding"] + else put "iso" into theColsA[pColumn]["encoding"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + _table.UpdateHeaderLabel pColumn, pValue, theColsA[pColumn]["encoding"] +end dgColumnLabel + + +getprop dgColumnLabel [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["label"] +end dgColumnLabel + + +getprop dgColumnLabelEncoding [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["encoding"] +end dgColumnLabelEncoding + + +setprop dgColumnTooltip [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + + put pValue into theColsA[pColumn]["tooltip"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + _table.UpdateHeaderTooltip pColumn, pValue +end dgColumnTooltip + + +getprop dgColumnTooltip [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["tooltip"] +end dgColumnTooltip + + +setprop dgColumnIsEditable [pColumn] pBoolean + local theColsA + put the dgProps["column properties"] of me into theColsA + put pBoolean is true into theColsA[pColumn]["editable"] + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + return empty +end dgColumnIsEditable + + +getprop dgColumnIsEditable [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["editable"] is not false ## default is true +end dgColumnIsEditable + + +setprop dgColumnIsResizable [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not a boolean then + _ThrowError kErrInvalidBoolean, "invalid boolean value for column is resizable '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["resizable"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + return empty +end dgColumnIsResizable + + +getprop dgColumnIsResizable [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["resizable"] +end dgColumnIsResizable + + +setprop dgColumnAlignment [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not among the items "left,right,center" then + _ThrowError kErrInvalidProperty, "invalid column alignment value '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["alignment"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## Update alignment + lock screen + if not sTableObjectsA["columns"][pColumn]["uses custom template"] then + repeat for each line theControl in sTableObjectsA["columns"][pColumn]["row controls"] + set the textAlign of theControl to pValue + end repeat + end if + unlock screen +end dgColumnAlignment + + +getprop dgColumnAlignment [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["alignment"] +end dgColumnAlignment + + +setprop dgHeaderAlignment [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not among the items "left,right,center" then + _ThrowError kErrInvalidProperty, "invalid header alignment value '" & pValue & "'" + end if + + put toLower(pValue) into theColsA[pColumn]["header"]["alignment"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## Update alignment + lock screen + if sTableObjectsA["columns"][pColumn]["header"]["group"] is not empty then + set the dgAlignment of sTableObjectsA["columns"][pColumn]["header"]["group"] to pValue + end if + unlock screen +end dgHeaderAlignment + + +getprop dgHeaderAlignment [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + return theColsA[pColumn]["header"]["alignment"] +end dgHeaderAlignment + + +setprop dgColumnWidth [pColumn] pValue + _StoreColWidth pColumn, pValue + _table.ResizeColumns +end dgColumnWidth + + +private command _StoreColWidth pColumn, pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not an integer then + _ThrowError kErrInvalidInteger, "invalid column width value '" & pValue & "'" + end if + + if theColsA[pColumn]["min width"] is empty then put 40 into theColsA[pColumn]["min width"] + if theColsA[pColumn]["max width"] is empty then put 1000 into theColsA[pColumn]["max width"] + + put max(theColsA[pColumn]["min width"], min(pValue, theColsA[pColumn]["max width"])) into theColsA[pColumn]["width"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages +end _StoreColWidth + + +getprop dgColumnWidth [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + if theColsA[pColumn]["width"] is empty then return 100 + else return theColsA[pColumn]["width"] +end dgColumnWidth + + +function _ColumnHeaderGroup pColumn + return sTableObjectsA["columns"][pColumn]["header"]["group"] +end _ColumnHeaderGroup + + +setprop dgColumnMinWidth [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not an integer then + _ThrowError kErrInvalidInteger, "invalid column width value '" & pValue & "'" + end if + + put pValue into theColsA[pColumn]["min width"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## current size must be at least min size + if theColsA[pColumn]["width"] is empty or theColsA[pColumn]["min width"] > theColsA[pColumn]["width"] then + set the dgColumnWidth[pColumn] of me to theColsA[pColumn]["min width"] + end if + return empty +end dgColumnMinWidth + + +getprop dgColumnMinWidth [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + if theColsA[pColumn]["min width"] is not empty then + return theColsA[pColumn]["min width"] + else + return 40 + end if +end dgColumnMinWidth + + +setprop dgColumnMaxWidth [pColumn] pValue + local theColsA + put the dgProps["column properties"] of me into theColsA + if pColumn is not among the keys of theColsA then + _ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist" + end if + if pValue is not an integer then + _ThrowError kErrInvalidInteger, "invalid column width value '" & pValue & "'" + end if + + put pValue into theColsA[pColumn]["max width"] + + lock messages + set the dgProps["column properties"] of me to theColsA + unlock messages + + ## current size must be at least min size + if theColsA[pColumn]["width"] is empty or theColsA[pColumn]["width"] > theColsA[pColumn]["max width"] then + set the dgColumnWidth[pColumn] of me to theColsA[pColumn]["max width"] + end if + return empty +end dgColumnMaxWidth + + +getprop dgColumnMaxWidth [pColumn] + local theColsA + put the dgProps["column properties"] of me into theColsA + if theColsA[pColumn]["max width"] is not empty then + return theColsA[pColumn]["max width"] + else + return 1000 + end if +end dgColumnMaxWidth + + +## deprecated +getprop dgColumnCustomControl + return the dgColumnTemplate of me +end dgColumnCustomControl + + +getprop dgColumnTemplate [pColumn] + local theTemplateGroup + put the dgProps["row template"] of me into theTemplateGroup + if there is a control pColumn of theTemplateGroup then + return the long ID of control pColumn of theTemplateGroup + else + return empty + end if +end dgColumnTemplate + + +getprop dgColumnHeaderTemplate [pColumn] + local theTemplateGroup + put the dgProps["row template"] of me into theTemplateGroup + if there is a control (pColumn && "[Header]") of theTemplateGroup then + return the long ID of control (pColumn && "[Header]") of theTemplateGroup + else + return empty + end if +end dgColumnHeaderTemplate + + +getprop dgWorkingRect + if the long ID of the target is the long ID of me then + return _WorkingGroupRect(the long ID of group "dgList" of me) + else + return _WorkingGroupRect(the long ID of the target) + end if +end dgWorkingRect + + +getprop dgFindIndex [pKeyValues] + ----- + local foundAMatch, theFoundIndex + local theIndex + local theKey + ----- + + split pKeyValues by cr and ":" ## Provide multiple lines of key:value to perform AND search + + repeat for each key theIndex in sDataArray + ## Developer can pass in multiple search strings to perform an AND search + repeat for each key theKey in pKeyValues + if sDataArray[theIndex][theKey] is word 1 to -1 of pKeyValues[theKey] then + put true into foundAMatch + else + put false into foundAMatch + end if + + ## AND search didn't pan out. Move on to next index. + if not foundAMatch then exit repeat + end repeat + + if foundAMatch then + put theIndex into theFoundIndex + exit repeat + end if + end repeat + + return max(0, theFoundIndex) +end dgFindIndex + + +getprop dgFindLine [pKeyValues] + local theFoundIndex + put the dgFindIndex [pKeyValues] of me into theFoundIndex + if theFoundIndex > 0 then + return the dgLineOfIndex[theFoundIndex] of me + else + return 0 + end if +end dgFindLine + + +getprop dgDataControlOfIndex [pIndex] + if _ControlType() is "form" then + if the dgProps["cache controls"] of me then + return the long ID of sControlOfIndexA[pIndex] + else + ## only visible controls are in play + repeat for each line theControl in sTableObjectsA["visible row controls"] + if the dgIndex of theControl is pIndex then + return the long ID of theControl + end if + end repeat + end if + end if + return empty +end dgDataControlOfIndex + + +function ColumnControlOfIndex pColumn, pIndex + if _ControlType() is "table" then + ## only visible controls are in play + repeat for each line theControl in sTableObjectsA["columns"][pColumn]["row controls"] + if the dgIndex of theControl is pIndex then + return the long id of theControl ## resolve the shortened 'of me' reference + end if + end repeat + end if + return empty +end ColumnControlOfIndex + + +function ColumnControlOfLine pColumn, pLine + local theIndex + put the dgIndexOfLine [pLine] of me into theIndex + return ColumnControlOfIndex(pColumn, theIndex) +end ColumnControlOfLine + + +getprop dgDataControlOfLine [pLine] + local theIndex + put the dgIndexOfLine [pLine] of me into theIndex + return the dgDataControlOfIndex [theIndex] of me +end dgDataControlOfLine + + +## Returns the rect of the control connected with pIndex. Rect +## is relative to this group but takes into account current vscroll. +## This may not prove very useful if you don't have control caching on. +getprop dgRectOfIndex [pIndex] + local theControl, theRect, theSequence, theControlBottom + put the dgDataControlOfIndex[pIndex] of me into theControl + if theControl is not empty then + put the rect of theControl into theRect + + if the dgProps["fixed row height"] of me then + put the dgLineOfIndex[pIndex] of me into theSequence + put sControlHeights * theSequence into item 4 of theRect + put item 4 of theRect - sControlHeights into item 2 of theRect + else + put 0 into theControlBottom + repeat for each item theIndex in sIndexSequencing + add sControlHeights[theIndex] to theControlBottom + + if theIndex is pIndex then + exit repeat + end if + end repeat + + put theControlBottom into item 4 of theRect + put theControlBottom - sControlHeights[theIndex] into item 2 of theRect + end if + + ## Adjust for vscroll + local theVScroll + put the dgVScroll of me into theVScroll + subtract theVScroll from item 2 of theRect + subtract theVScroll from item 4 of theRect + + ## Now adjust for position of control + add the top of group "dgListMask" of me to item 2 of theRect + add the top of group "dgListMask" of me to item 4 of theRect + end if + + return theRect +end dgRectOfIndex + + +getprop dgControl + return the long ID of me +end dgControl + + +getprop dgVScroll + if __HasMobileScroller() then + return mobileControlGet(sScrollerId, "vScroll") + end if + return round(the thumbPosition of scrollbar "dgScrollbar" of me) +end dgVScroll + + +setprop dgVScroll pValue + _SetVScroll pValue +end dgVScroll + + +private command _SetVScroll pValue + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + set the thumbPosition of scrollbar "dgScrollbar" of me to pValue + put the thumbPosition of scrollbar "dgScrollbar" of me into pValue + + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", pValue + end if + + set the lockMessages to msgsAreLocked + + if not msgsAreLocked and the visible of scrollbar "dgScrollbar" of me then + send "scrollbarDrag pValue" to scrollbar "dgScrollbar" of me + ## dispatch slows things down terribly here + -- dispatch "scrollbarDrag" to scrollbar "dgScrollbar" of me with pValue + else + _ScrollListV pValue + end if + + unlock screen +end _SetVScroll + + +## Vscroll percentage is useful when refreshing the list with new data and keeping the scroll in relatively the same position +getprop dgVScrollPercent + return _GetVScrollPercent() +end dgVScrollPercent + + +private function _GetVScrollPercent + local theWorkingEndValue + put __WorkingScrollVEndValue() into theWorkingEndValue + if theWorkingEndValue > 0 then + if __HasMobileScroller() then + return mobileControlGet(sScrollerId, "vScroll") / theWorkingEndValue + end if + return round(the thumbPosition of scrollbar "dgScrollbar" of me) / theWorkingEndValue + else + return 0 + end if +end _GetVScrollPercent + + +setprop dgVScrollPercent pPercent + _SetVScrollPercent pPercent +end dgVScrollPercent + +private function __WorkingScrollVEndValue + local theWorkingEndValue + if the environment is not "mobile" then + put the endValue of scrollbar "dgScrollbar" of me - the thumbSize of scrollbar "dgScrollbar" of me into theWorkingEndValue + else if __HasMobileScroller() then + local tContentRect + put mobileControlGet(sScrollerId, "contentrect") into tContentRect + put item 4 of tContentRect - the height of group "dgList" of me into theWorkingEndValue + else + put 0 into theWorkingEndValue + end if + return theWorkingEndValue +end __WorkingScrollVEndValue + +private command _SetVScrollPercent pPercent + _SetVScroll round(__WorkingScrollVEndValue() * pPercent) +end _SetVScrollPercent + + +getprop dgHScroll + if __HasMobileScroller() then + return mobileControlGet(sScrollerId, "hScroll") + else + return round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) + end if +end dgHScroll + + +setprop dgHScroll pValue + _SetHScroll pValue +end dgHScroll + + +private command _SetHScroll pValue + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to pValue + put the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me into pValue + if __HasMobileScroller() then + mobileControlSet sScrollerId, "hScroll", pValue + end if + + set the lockMessages to msgsAreLocked + + if not msgsAreLocked and the visible of group "dgHorizontalComponents" of me then + send "scrollbarDrag pValue" to scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me + ## dispatch slows things down terribly here + -- dispatch "scrollbarDrag" to scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me with pValue + else + _ScrollListH pValue + end if + + unlock screen +end _SetHScroll + + +private command _ScrollListH pScrollValue + lock screen + set the hScroll of group "dgHeaderMask" of group "dgHeaderComponents" of me to pScrollValue + set the hScroll of group "dgListMask" of me to pScrollValue + unlock screen +end _ScrollListH + + +getprop dgHScrollPercent + return _GetHScrollPercent() +end dgHScrollPercent + + +private function __WorkingScrollHEndValue + local theWorkingEndValue + if the environment is not "mobile" then + put the endValue of scrollbar "dgHScrollbar" of me - the thumbSize of scrollbar "dgHScrollbar" of me into theWorkingEndValue + else if __HasMobileScroller() then + local tContentRect + put mobileControlGet(sScrollerId, "contentrect") into tContentRect + put item 3 of tContentRect - the width of group "dgList" of me into theWorkingEndValue + else + put 0 into theWorkingEndValue + end if + return theWorkingEndValue +end __WorkingScrollHEndValue + +private function _GetHScrollPercent + local theWorkingEndValue + put __WorkingScrollHEndValue() into theWorkingEndValue + if theWorkingEndValue > 0 then + if __HasMobileScroller() then + return mobileControlGet(sScrollerId, "hScroll") / theWorkingEndValue + end if + return round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) / theWorkingEndValue + else + return 0 + end if +end _GetHScrollPercent + + +setprop dgHScrollPercent pPercent + _SetHScrollPercent pPercent +end dgHScrollPercent + + +private command _ResetScrollsToZero + _ResetVScrollToZero + _ResetHScrollToZero +end _ResetScrollsToZero + + +private command _ResetVScrollToZero + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the lockMessages to true + + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", 0 + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to 0 + set the vScroll of group "dgList" of group "dgListMask" of me to 0 + + set the lockMessages to msgsAreLocked +end _ResetVScrollToZero + + +private command _ResetHScrollToZero + local msgsAreLocked + put the lockMessages into msgsAreLocked + set the lockMessages to true + + if __HasMobileScroller() then + mobileControlSet sScrollerId, "hScroll", 0 + end if + set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0 + set the hScroll of group "dgHeaderMask" of group "dgHeaderComponents" of me to 0 + set the hScroll of group "dgListMask" of me to 0 + + set the lockMessages to msgsAreLocked +end _ResetHScrollToZero + + +private command _SetHScrollPercent pPercent + _SetHScroll round(__WorkingScrollHEndValue() * pPercent) +end _SetHScrollPercent + + +getprop dgDataControls + local theControls, theList + if _ControlType() is "form" then + if the dgProps["cache controls"] of me then + ## sTableObjectsA["visible row controls"] only contains visible controls but all controls are valid. + put sTableObjectsA["all row controls"] into theControls + else + put sTableObjectsA["visible row controls"] into theControls + end if + + repeat for each line theControl in theControls + put the long ID of theControl & cr after theList + end repeat + delete the last char of theList + return theList + else + return empty + end if +end dgDataControls + + +getprop dgHilitedIndex + return sHilitedIndexes ## indexes will be in order of selection +end dgHilitedIndex + + +getprop dgHilitedIndexes + return sHilitedIndexes ## indexes will be in order of selection +end dgHilitedIndexes + + +setprop dgHilitedIndex pIndexes + _SetHilitedIndexes pIndexes + return the result +end dgHilitedIndex + + +## Hmmm, this handler needs to ensure that the one of the hilited indexes +## will be visible on screen. For that we may need to query the range of +## indexes currently visible and then scroll the index into view if need be. +setprop dgHilitedIndexes pIndexes + _SetHilitedIndexes pIndexes + return the result +end dgHilitedIndexes + + +private command _SetHilitedIndexes pIndexes + put _SortIndexesSequentially(pIndexes) into pIndexes + + lock screen + local theReturnValue + if pIndexes is not sHilitedIndexes then + put pIndexes into sHilitedIndexes + if the dgProps["scroll selections into view"] of me is not false then + ScrollIndexIntoView item 1 of sHilitedIndexes + end if + + _HiliteIndexesInVisibleControls + put true into theReturnValue + + else + put false into theReturnValue + end if + + unlock screen + + return theReturnValue +end _SetHilitedIndexes + + +## Lines/Sequences are synonymous +getprop dgHilitedLines + return _GetHilitedSequences() +end dgHilitedLines + + +getprop dgHilitedLine + return _GetHilitedSequences() +end dgHilitedLine + + +private function _GetHilitedSequences + local theHilitedSequences,theIndex,theItemNo + + set the wholeMatches to true + repeat for each item theIndex in sHilitedIndexes + put itemOffset(theIndex, sIndexSequencing ) into theItemNo + if theItemNo > 0 then + put theItemNo & comma after theHilitedSequences + end if + end repeat + delete the last char of theHilitedSequences + return theHilitedSequences +end _GetHilitedSequences + + +## Lines/Sequences are synonymous +setprop dgHilitedLine pSequences + _SetHilitedSequences pSequences + return the result +end dgHilitedLine + + +setprop dgHilitedLines pSequences + _SetHilitedSequences pSequences + return the result +end dgHilitedLines + + +private command _SetHilitedSequences pSequences + local theIndex,theSequence + local theHilitedIndexes + local theMaxSequence + + ## We want indexes to be in order of selection + sort items of pSequences numeric + put the number of items of sIndexSequencing into theMaxSequence + + repeat for each item theSequence in pSequences + put item min(theSequence, theMaxSequence) of sIndexSequencing into theIndex + if theIndex is not empty then + put theIndex & comma after theHilitedIndexes + end if + end repeat + delete the last char of theHilitedIndexes + + set the dgHilitedIndexes of me to theHilitedIndexes + return the result +end _SetHilitedSequences + + +--> Private + + +private function _CardOf + local theCharNo,theControl + + put the long ID of me into theControl + + put offset(" of card ", theControl) into theCharNo + delete char 1 to (theCharNo - 1) of theControl + + put offset(" of stack ", theControl) into theCharNo + delete char theCharNo to -1 of theControl + + return theControl +end _CardOf + + +private command _RefreshIndexes pIndexes + local redrawTheList, theVScroll, theVisibleIndexes + put false into redrawTheList + + lock screen + put _GetVScrollPercent() into theVScroll + put _VisibleIndexes() into theVisibleIndexes + + repeat for each item theIndex in pIndexes + _UpdateIndexWithNewData theIndex + + set the wholeMatches to true + + if theIndex is among the items of theVisibleIndexes then + _ResetControlsOfIndex theIndex + put true into redrawTheList + end if + + end repeat + + if redrawTheList then + _RedrawList theVScroll + end if + + unlock screen +end _RefreshIndexes + + +private function _ColorToRGB pColor + if pColor is a color then + if the number of items of pColor is not 3 then + lock screen + local theGraphic, theOrigColor + put the long ID of graphic "dgBackground" of me into theGraphic + put the backColor of theGraphic into theOrigColor + set the backColor of theGraphic to pColor + set the backpixel of theGraphic to the effective backpixel of theGraphic + put the backColor of theGraphic into pColor + set the backColor of theGraphic to theOrigColor + unlock screen + end if + end if + + return pColor +end _ColorToRGB + + +private command _SetGraphicGradient pGraphic, pStartColor, pEndColor + local theRect, theX, theY + put the rect of pGraphic into theRect + set the backgroundColor of pGraphic to empty + set the fillgradient["quality"] of pGraphic to "normal" + set the fillgradient["repeat"] of pGraphic to 1 + set the fillgradient["mirror"] of pGraphic to false + set the fillgradient["wrap"] of pGraphic to true + set the fillgradient["type"] of pGraphic to "linear" + set the fillGradient["ramp"] of pGraphic to "0.00000," & pStartColor & cr & "1.00000," & pEndColor + put item 1 of theRect into theX + put item 2 of theRect into theY + ## take gradient from the top to the bottom. + ## Spread it out via the X + set the fillgradient["from"] of pGraphic to theX, theY + set the fillgradient["to"] of pGraphic to theX, theY + (item 4 of theRect - item 2 of theRect) + set the fillGradient["via"] of pGraphic to theX + 40, theY + + return empty +end _SetGraphicGradient + +on scrollerBeginDrag + _UserStartedVScrolling + pass scrollerBeginDrag +end scrollerBeginDrag + +on scrollerEndDrag + _UserStoppedVScrolling + pass scrollerEndDrag +end scrollerEndDrag + +on scrollerDidScroll pHScroll, pVScroll + dgScrollbarDragV max(0,pVScroll) + dgScrollbarDragH max(0,pHScroll) + pass scrollerDidScroll +end scrollerDidScroll + +## This handler is called from the vscroll bar when user releases mouse. +## It draws any columns not currently visible within the mask area. +## Note that we do not currently take into account whether or not the vscroll changed +## so if the user clicked an released without scrolling we would still redraw. If this becomes +## a problem then add a flag in mouseDown. +command _UserStoppedVScrolling + put false into sRunningActionsA["user is vscrolling"] + local theColumnsA + if _ControlType() is "table" then + put _table.AreColumnsVisibleWithinMask() into theColumnsA + _table.DrawColumns theColumnsA["hidden"] + end if +end _UserStoppedVScrolling + + +command _UserStartedVScrolling + put true into sRunningActionsA["user is vscrolling"] +end _UserStartedVScrolling + + +command PrintKeys pArray + if pArray is not an array then put sDataArray into pArray + put _PrintKeys(pArray) +end PrintKeys + + +private function _ResourceStack + local theStack, theCharNo + put the behavior of me into theStack + if theStack is not empty then + put offset(" of stack", theStack) into theCharNo + delete char 1 to (theCharNo + 3) of theStack + end if + + return theStack +end _ResourceStack + +private function _TemplateControl + -- Attempt to find the card of the datagrid template stack. + -- Used to house template controls. + -- Base this off the row template. If the row template is not in the template stack then keep our template controls in the DataGrid itself. + if the dgProps["row template"] of me contains ("stack" && quote & "Data Grid Templates") then + return the long id of the owner of the dgProps["row template"] of me + else + return the long id of me + end if +end _TemplateControl + +private function _PrintKeys @pArray, pDimension + if pDimension is empty then put 0 into pDimension + + local theKeys, theText, theTempArray + put the keys of pArray into theKeys + sort theKeys numeric + + repeat for each line theKey in theKeys + if pArray[theKey] is an array then + put _printCharXTimes(space, pDimension * 5) & theKey & cr after theText + put pArray[theKey] into theTempArray + put _PrintKeys(theTempArray, pDimension + 1) after theText + else + put _printCharXTimes(space, pDimension * 5) & theKey & ":" && "`" & pArray[theKey] & "`" & cr after theText + end if + end repeat + + return theText +end _PrintKeys + + +private function _printCharXTimes pChar, pTimes + local theStr + + repeat with i = 1 to pTimes + put pChar after theStr + end repeat + return theStr +end _printCharXTimes + + +function _CustomControlReference pControl + ----- + local theFirstCharToDelete + local theLastCharToDelete + local theOffset + local theStack + ----- + put the long ID of pControl into pControl + ## Get id without hierarchy + if word 1 of pControl is not among the items of "card,stack" then + ## Strip any nested refs + if pControl contains "of group id" then + put length(word 1 to 4 of pControl) + 1 into theFirstCharToDelete + put offset(" card id", pControl) - 1 into theLastCharToDelete + delete char theFirstCharToDelete to theLastCharToDelete of pControl + end if + + local theStackOffset, theSecondStackOffset + put offset(" of stack ", pControl) into theStackOffset + put offset(" of stack ", pControl, theStackOffset) into theSecondStackOffset + if theSecondStackOffset > 0 then + ## Strip mainstack ref if substack. + ## We want user to move stacks around. + add theSecondStackOffset to theStackOffset + delete char theStackOffset to -1 of pControl + else + ## Shorten stack name + put char (theStackOffset + 4) to -1 of pControl into theStack + put the short name of theStack into theStack # get stack short name + put quote & theStack & quote into char (theStackOffset + 10) to -1 of pControl + end if + + ## Strip card ref + ## Taken out so that one can locate the card of a stack that a reference is on + ## without looping through every card on the stack. + -- put offset(" of card ", pControl) into theFirstCharToDelete + -- put offset(" of stack ", pControl) into theLastCharToDelete + -- delete char theFirstCharToDelete + 1 to theLastCharToDelete of pControl + end if + + return pControl +end _CustomControlReference + + +private function _TopIsVisible pRect, pMaskRect + return item 2 of pRect < item 4 of pMaskRect and item 2 of pRect > item 2 of pMaskRect +end _TopIsVisible + + +private function _BottomIsVisible pRect, pMaskRect + return item 4 of pRect > item 2 of pMaskRect and item 4 of pRect < item 4 of pMaskRect +end _BottomIsVisible + + +private function _RectIsAtLeastAsTallAsMask pRect, pMaskRect + return item 4 of pRect - item 2 of pRect >= item 4 of pMaskRect - item 2 of pMaskRect +end _RectIsAtLeastAsTallAsMask + + +private function _RectCoversMask pRect, pMaskRect + return _RectIsAtLeastAsTallAsMask(pRect, pMaskRect) and \ + item 2 of pRect <= item 2 of pMaskRect and \ + item 4 of pRect >= item 4 of pMaskRect +end _RectCoversMask + + +private function _TopIsClipped pRect, pMaskRect + return item 4 of pRect > item 2 of pMaskRect and item 2 of pRect < item 2 of pMaskRect +end _TopIsClipped + + +private function _BottomIsClipped pRect, pMaskRect + return item 2 of pRect < item 4 of pMaskRect and item 4 of pRect > item 4 of pMaskRect +end _BottomIsClipped + +private function _TopAndBottomAreClipped pRect, pMaskRect + return item 2 of pRect >= item 4 of pMaskRect or item 4 of pRect <= item 2 of pMaskRect +end _TopAndBottomAreClipped + + +private command _SelectTargetControl pControl + ----- + local theControl + local theIndex + local thePreviouslyHilitedIndexes + ----- + if pControl is empty then put the dgDataControl of the target into pControl + if pControl is not empty then + put the dgIndex of pControl into theIndex + put sHilitedIndexes into thePreviouslyHilitedIndexes + + ## single click always inserts index into first index var + put theIndex into sFirstIndexClickedWithShiftKeyDown + set the dgHilitedIndexes of me to the dgIndex of pControl + + ## Clicked on a control + if the long ID of me is not in the long ID of the focusedObject then + focus on graphic "dgBackground" of me + end if + + _SelectionChanged thePreviouslyHilitedIndexes + end if +end _SelectTargetControl + + +private function _KeyedParametersToArray pString + split pString by comma and ":" + return pString +end _KeyedParametersToArray + + +private function _SortIndexesSequentially pIndexes + local theIndex + local theItemNo + local theIndexes + ----- + set the wholeMatches to true + + ## Algorithm: Inserts indexes into same line as sequence then strips + ## empty lines. Seems like it would be faster then creating table of sequences/indexes, + ## performing a sort and then extracting the index column. Haven't timed though. + repeat for each item theIndex in pIndexes + put itemOffset(theIndex, sIndexSequencing) into theItemNo + if theItemNo > 0 then + put theIndex into line theItemNo of theIndexes + end if + end repeat + + filter theIndexes without empty ## Get rid of empty lines + replace cr with comma in theIndexes + + return theIndexes +end _SortIndexesSequentially + + +private command _ProcessNewIndexData pIndex + ----- + local theControl + local theTemplateGroup + local msgsAreLocked + ----- + + put the lockMessages into msgsAreLocked + + ## Create cached control as needed + if the dgProps["cache controls"] of me and _ControlType() is "form" then + put the dgProps["row template"] of me into theTemplateGroup + lock messages + copy theTemplateGroup to group "dgList" of me + put it into theControl + put "control id" && word 3 of theControl && "of me" into sControlOfIndexA[pIndex] + set the visible of theControl to false + set the dgIndex of theControl to pIndex + set the layerMode of theControl to "dynamic" + unlock messages + + put sControlOfIndexA[pIndex] into line (the number of lines of sTableObjectsA["all row controls"] + 1) of sTableObjectsA["all row controls"] + end if + + ## Since number of records has changed we need to redraw alternating rows + _DrawAlternatingRows + + _UpdateIndexWithNewData pIndex + + ## We only need to update formattedheight when working with fixed control heights. + ## Otherwise the formatted height is adjusted when new data is updated. + if sFormattedHeight is not empty then + if the dgProps["fixed row height"] of me then + add sControlHeights to sFormattedHeight + _ConfigureScrollbar + else + _ConfigureScrollbar + _AutoHideVScrollbar ## this only works for fixed height + end if + end if + + set the lockMessages to msgsAreLocked + + return theControl +end _ProcessNewIndexData + + +private command _UpdateIndexWithNewData pIndex + ----- + local deleteTheControl, theControl, theLine, theRect + local theListGroupRect + local theTemplateGroup + local theFocusedControl + local msgsAreLocked + local heightIsFixed + ----- + put the long ID of the focusedObject into theFocusedControl + + put the dgDataControlOfIndex[pIndex] of me into theControl + + put the lockMessages into msgsAreLocked + put the dgProps["fixed row height"] of me into heightIsFixed + + ## If not fixed height and no control exists then create one + ## and mark it for deletion + if theControl is empty and not heightIsFixed then + put true into deleteTheControl + put the dgProps["row template"] of me into theTemplateGroup + lock messages + copy theTemplateGroup to group "dgList" of me + put it into theControl + set the layerMode of theControl to "dynamic" + end if + + ## Insert data into control + if theControl is not empty then + unlock messages + + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put the dgLine of theControl into theLine ## passing this param is deprecated + put the rect of theControl into theRect + put item 1 of theRect + (item 3 of theListGroupRect - item 1 of theListGroupRect) into item 3 of theRect + + dispatch "FillInData" to theControl with sDataArray[pIndex] + lock messages + set the rect of theControl to theRect ## FillInData could possibly extend elements outside of the original rect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + + lock messages + if not heightIsFixed then + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + set the rect of theControl to theRect + end if + end if + + ## Now update formatted height if we are not dealing with fixed control heights + if not the dgProps["fixed row height"] of me and sFormattedHeight is not empty then + ## First we need to subtract existing height from cached + if sControlHeights[pIndex] is an integer and sFormattedHeight is not empty then + subtract sControlHeights[pIndex] from sFormattedHeight + end if + + ## Now cache control height + put the height of theControl into sControlHeights[pIndex] + add sControlHeights[pIndex] to sFormattedHeight + + _ConfigureScrollbar + end if + + ## Note: fixed control height does NOT need formattedheight updated. + + ## Cleanup if not caching and not fixed control height + if deleteTheControl then + lock messages + delete theControl + end if + + ## Make sure focus stays with us + if the long ID of me is in theFocusedControl then + + lock messages + if there is not a theFocusedControl then + focus on graphic "dgBackground" of me + else + focus on theFocusedControl + end if + unlock messages + end if + + set the lockMessages to msgsAreLocked + + return empty +end _UpdateIndexWithNewData + + +private function _VisibleIndexes + ----- + local theControl + local theIndexes + ----- + switch _ControlType() + case "table" + put item sTableObjectsA["base sequence for visible controls"] to \ + (sTableObjectsA["base sequence for visible controls"] + sTableObjectsA["row control count"]) of sIndexSequencing into theIndexes + break + default + repeat for each line theControl in sTableObjectsA["visible row controls"] + put the dgIndex of theControl & comma after theIndexes + end repeat + delete the last char of theIndexes + end switch + + return theIndexes +end _VisibleIndexes + + +private command _ConfigureScrollbar + local theEndValue + if sFormattedHeight > 0 then + put sFormattedHeight into theEndValue + else + put the height of group "dgList" of me into theEndValue + end if + + lock screen + + ## If messages are not locked then scrollbarDrag is sent when group height is increased. + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local thePercent + put _GetVScrollPercent() into thePercent + + ## Setting thumbsize 2nd is important because engine limits thumbsize based on endValue + set the endValue of scrollbar "dgScrollbar" of me to max(the height of group "dgList" of me, theEndValue) + set the thumbSize of scrollbar "dgScrollbar" of me to the height of group "dgList" of me + + local thePageIncrement + put the thumbSize of scrollbar "dgScrollbar" of me into thePageIncrement + if sControlHeights is an integer then subtract sControlHeights from thePageIncrement + else subtract 16 from thePageIncrement ## Why 16? Why not. + set the pageIncrement of scrollbar "dgScrollbar" of me to thePageIncrement + + if the dgProps["fixed row height"] of me and sControlHeights is an integer then + set the lineIncrement of scrollbar "dgScrollbar" of me to sControlHeights + else + set the lineIncrement of scrollbar "dgScrollbar" of me to round(the pageIncrement of scrollbar "dgScrollbar" of me / 16) + end if + + if __HasMobileScroller() then + local tContentRect + put mobileControlGet(sScrollerId, "contentrect") into tContentRect + put max(the height of group "dgList" of me, theEndValue) into item 4 of tContentRect + mobileControlSet sScrollerId, "contentrect", tContentRect + end if + + ## in lock messages so no redrawing occurs + _SetVScrollPercent thePercent + + set the lockMessages to msgsAreLocked + unlock screen +end _ConfigureScrollbar + + +private command _ConfigureHScrollbar + if _ControlType() is "table" then + local theScrollBar + put the long ID of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me into theScrollBar + local theRect + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theRect + local theViewWidth + if the visible of scrollbar "dgScrollbar" of me then + put the left of scrollbar "dgScrollbar" of me - item 1 of theRect into theViewWidth + else + put the right of group "dgListMask" of me - item 1 of theRect into theViewWidth + end if + + set the endValue of theScrollBar to max(sFormattedWidth, theViewWidth) + set the thumbSize of theScrollBar to theViewWidth + set the pageIncrement of theScrollBar to the thumbSize of theScrollBar + + if __HasMobileScroller() then + local tContentRect + put mobileControlGet(sScrollerId, "contentrect") into tContentRect + put max(sFormattedWidth, theViewWidth) into item 3 of tContentRect + mobileControlSet sScrollerId, "contentrect", tContentRect + end if + + ## Show/hide last column divider shadow + _SetVisibilityOfColumnDividers + end if +end _ConfigureHScrollbar + + +private command _SetVisibilityOfColumnDividers + local theRect, theViewWidth, theColumns, theColCount, i, theControl + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theRect + put the left of scrollbar "dgScrollbar" of me - item 1 of theRect into theViewWidth + + ## Show/hide last column divider shadow + put _table.VisibleColumns() into theColumns + put the number of lines of theColumns into theColCount + repeat for each line theColumn in theColumns + add 1 to i + put sTableObjectsA["columns"][theColumn]["divider control"] into theControl + if there is not a theControl then next repeat + + if i < theColCount then + set the visible of theControl to true + else + ## Special rules for last one + if the width of group "dgHeader" of group "dgHeaderMask" of me < theViewWidth - 1 then + ## Show + set the visible of theControl to true + else + ## Hide + set the visible of theControl to false + end if + end if + end repeat +end _SetVisibilityOfColumnDividers + + +private command _AutoHideVScrollbar + if the environment is "mobile" then + return empty + end if + + ## Determine scrollbars + ## Doesn't work without fixed control height. We trap for this when setting prop but developer + ## could lock messages and set dgProps["autohide scrollbar"]. + if the dgProps["show vscrollbar"] of me is "auto" and the dgProps["fixed row height"] of me then + set the visible of scrollbar "dgScrollbar" of me to sFormattedHeight > the height of group "dgList" of me + local theRect + put the rect of group "dgList" of me into theRect + if the visible of scrollbar "dgScrollbar" of me then + put the left of scrollbar "dgScrollbar" of me into item 3 of theRect + else + put the right of scrollbar "dgScrollbar" of me into item 3 of theRect + end if + + set the rect of group "dgListMask" of me to theRect + + if _ControlType() is "table" then + _table.ResizeList + else + set the rect of group "dgList" of me to theRect + end if + end if +end _AutoHideVScrollbar + + +## Call whenever width of all columns changes +private command _AutoHideHScrollbar + if the environment is "mobile" then + return empty + end if + + if _ControlType() is "table" then + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + if the dgProps["show hscrollbar"] of me is "auto" then + local theWidth + put sFormattedWidth into theWidth + ## list mask extends behind scrollbar so negate that space in calculation + if the visible of scrollbar "dgScrollbar" of me then + add the width of scrollbar "dgScrollbar" of me to theWidth + end if + set the visible of group "dgHorizontalComponents" of me to theWidth > the width of group "dgListMask" of me + end if + set the lockMessages to msgsAreLocked + end if +end _AutoHideHScrollbar + + +-- returns the rect where you can draw content in a group without making scrollbars appear +private function _WorkingGroupRect pGroup + local theRect, theWidth + put the rect of pGroup into theRect + add the leftMargin of pGroup to item 1 of theRect + add the topMargin of pGroup to item 2 of theRect + subtract the rightMargin of pGroup from item 3 of theRect + subtract the bottomMargin of pGroup from item 4 of theRect + if the hScrollbar of pGroup then subtract the scrollbarWidth of pGroup from item 4 of theRect + if the vScrollbar of pGroup then subtract the scrollbarWidth of pGroup from item 3 of theRect + if the showBorder of pGroup then + put the borderWidth of pGroup into theWidth + add theWidth to item 1 of theRect + add theWidth to item 2 of theRect + subtract theWidth from item 3 of theRect + subtract theWidth from item 4 of theRect + end if + return theRect +end _WorkingGroupRect + + +private function _MaxStartingSequence + local theListGroupRect, theListGroupHeight, theMaxStartingSequence, theRequiredControlCount, theIndex + if the dgProps["fixed row height"] of me then + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theListGroupRect + put item 4 of theListGroupRect - item 2 of theListGroupRect into theListGroupHeight + put max(1, ((theListGroupHeight / sControlHeights) div 1)) into theMaxStartingSequence ## floor + ## This was returning one number too low in tests with tables. (0.9.8.5) + put _ControlsRequiredToFillSpace() into theRequiredControlCount + else + ## Start from the back and work our way down + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theListGroupRect + put item 4 of theListGroupRect - item 2 of theListGroupRect into theListGroupHeight + + ## Add controls until we exceed the list group height + repeat with theItemNo = the number of items of sIndexSequencing down to 1 + put item theItemNo of sIndexSequencing into theIndex + add 1 to theRequiredControlCount + local theNecessaryHeight + add sControlHeights[theIndex] to theNecessaryHeight + if theNecessaryHeight >= theListGroupHeight then + exit repeat + end if + end repeat + local theFirstControlHeight, theHeight + ## Get height of first control in list + put sControlHeights[theIndex] into theFirstControlHeight + + ## The list group should be able to scroll the first control in the list out of view + ## Add additional controls until we get to that number + repeat with theItemNo = theItemNo - 1 down to 1 + -- answer theItemNo + -- repeat for each item theIndex in (item theRequiredControlCount + 1 to -1 of theIndexList) + add 1 to theRequiredControlCount + add sControlHeights[theIndex] to theHeight + if theHeight >= theFirstControlHeight then + exit repeat + end if + end repeat + end if + + local theNumberOfRecords + put max(0, the number of elements of sDataArray) into theNumberOfRecords + put theNumberOfRecords - theRequiredControlCount + 1 into theMaxStartingSequence + return max(1, theMaxStartingSequence) +end _MaxStartingSequence + + +-- sTableObjectsA["base sequence for visible controls"] is only necessary if controls are not a fixed height +private function _ControlsRequiredToFillSpace + local theFirstControlHeight,theIndex,theIndexList,theListGroupRect + local theNecessaryHeight,theRequiredControlCount + + ## Cached for performance + ## Reset when resized + put empty into sControlsRequiredToFillSpace + if sControlsRequiredToFillSpace is empty then + put _WorkingGroupRect(the long ID of group "dgListMask" of me) into theListGroupRect + + if the dgProps["fixed row height"] of me then + if _ControlType() is "table" then + ## Since tables scroll by row we only need number of controls to fill visible area. + ## Note: this could be updated if we add property for scrolling by row vs. pixel. + put item 4 of theListGroupRect - item 2 of theListGroupRect + sControlHeights into theNecessaryHeight + put ((theNecessaryHeight / sControlHeights) div 1) into sControlsRequiredToFillSpace ## floor + 1 + else + ## We want to fill with number of controls to fill visible space + 1 control + put item 4 of theListGroupRect - item 2 of theListGroupRect + sControlHeights into theNecessaryHeight + put ((theNecessaryHeight / sControlHeights) div 1) + 1 into sControlsRequiredToFillSpace ## floor + 1 + end if + else + ## Beginning from the starting index add up control heights until we reach height of list group + put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexList + put sControlHeights[item 1 of theIndexList] into theFirstControlHeight + local theListGroupHeight + put item 4 of theListGroupRect - item 2 of theListGroupRect into theListGroupHeight + + repeat for each item theIndex in theIndexList + add 1 to sControlsRequiredToFillSpace + add sControlHeights[theIndex] to theNecessaryHeight + if theNecessaryHeight >= theListGroupHeight then + exit repeat + end if + end repeat + + ## The list group should be able to scroll the first control in the list out of view + ## Add additional controls until we get to that number + repeat for each item theIndex in (item sControlsRequiredToFillSpace + 1 to -1 of theIndexList) + add 1 to sControlsRequiredToFillSpace + + local theHeight + add sControlHeights[theIndex] to theHeight + if theHeight >= theFirstControlHeight then + exit repeat + end if + end repeat + end if + end if + + return sControlsRequiredToFillSpace +end _ControlsRequiredToFillSpace + + +private command _ResizeCachedControls + local msgsAreLocked, theListGroupRect, theTopLeft + put the lockMessages into msgsAreLocked + + _AutoHideVScrollbar ## only works for fixed height + + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + + lock screen + if the dgProps["fixed row height"] of me then + ## Control heights and total height remain unchanged + repeat for each line theControl in sTableObjectsA["all row controls"] + local theIndex, theRect + put the dgIndex of theControl into theIndex + set the topLeft of theControl to theTopLeft ## This allows developer to always rely on top and left of controls in template code + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + end repeat + else + put empty into sControlHeights + put 0 into sFormattedHeight + + repeat for each line theControl in sTableObjectsA["all row controls"] + put the dgIndex of theControl into theIndex + set the topLeft of theControl to theTopLeft ## This allows developer to always rely on top and left of controls in template code + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + + lock messages + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + set the rect of theControl to theRect + + put item 4 of theRect - item 2 of theRect into sControlHeights[theIndex] + add sControlHeights[theIndex] to sFormattedHeight + end repeat + end if + unlock screen + + set the lockMessages to msgsAreLocked +end _ResizeCachedControls + + +private command _SetSequenceOfIndex pIndex, pSequence + local theCurrentSequence,theError + put min(max(1, pSequence), the number of items of sIndexSequencing) into pSequence + + set the wholeMatches to true + put itemOffset(pIndex, sIndexSequencing) into theCurrentSequence + if theCurrentSequence > 0 then + delete item theCurrentSequence of sIndexSequencing + end if + + put pIndex & comma before item pSequence of sIndexSequencing + if the last char of sIndexSequencing is comma then + delete the last char of sIndexSequencing + end if + + return theError +end _SetSequenceOfIndex + + +private command _SelectionChanged pPreviouslyHilitedIndexes + dispatch "selectionChanged" with sHilitedIndexes, pPreviouslyHilitedIndexes +end _SelectionChanged + + +command _ScrollListV pVScroll, pForceRefresh + local theFraction,theGroupVScroll,theSequence, theError + -- put the milliseconds & cr & the executioncontexts + + -- put false into sRunningActionsA["v scroll"] + if sRunningActionsA["v scroll"] then + put true into sRunningActionsA["resend _scrolllistv"] + return empty + end if + + put true into sRunningActionsA["v scroll"] + + try + if sFormattedHeight > 0 then + if pVScroll is not an integer then + put the dgVScroll of me into pVScroll + end if + + ## Sequence can't be too high + local theMaxStartingSequence + put _MaxStartingSequence() into theMaxStartingSequence + + if the dgProps["fixed row height"] of me then + put (pVScroll / sControlHeights) + 1 into theSequence + put theSequence mod 1 into theFraction + put theSequence div 1 into theSequence + put round(sControlHeights * theFraction) into theGroupVScroll + + ## If sequence is too high then adjust group vscroll accordingly + repeat with i = 1 to theSequence - theMaxStartingSequence + add sControlHeights to theGroupVScroll + end repeat + + -- put "max sequence:" && theMaxStartingSequence && \ + -- "sequence:" && theSequence && "total records:" && the dgNumberOfRecords of me && \ + -- "fraction:" && theFraction && "group vscroll:" && theGroupVScroll & cr after msg + put min(theMaxStartingSequence, theSequence) into theSequence + else + ## Random sized records + local theFormattedHeight + put 0 into theFormattedHeight + put 0 into theSequence + repeat for each item theIndex in sIndexSequencing + add 1 to theSequence + add sControlHeights[theIndex] to theFormattedHeight + + if theFormattedHeight >= pVScroll then + put pVScroll - (theFormattedHeight - sControlHeights[theIndex]) into theGroupVScroll + exit repeat + end if + end repeat + end if + + _DrawListWithProperties theSequence, theGroupVScroll, pForceRefresh + end if + + catch e + put e into theError + end try + + put false into sRunningActionsA["v scroll"] + + if theError is not empty then + put false into sRunningActionsA["resend _scrolllistv"] + _ReportBehaviorError theError + end if + + if sRunningActionsA["resend _scrolllistv"] then + -- put empty into pVScroll ## ?? Do we want the next round to determine where to go based on position of sb at time? + ## I don't think so as little tests show that scrolling when dragging scrollbar is smoother if we keep value + if the keys of the dragData is empty then ## messages don't go during drag opeations. Don't send. + send "_ScrollListV pVScroll, pForceRefresh" to me in 0 milliseconds + end if + put false into sRunningActionsA["resend _scrolllistv"] + end if +end _ScrollListV + + +private command _ReportBehaviorError pError + local theBehaviorType, theLastLineNo + -- put the executioncontexts & cr & cr & pError + if the environment is "development" and revAppVersion() is not 0 then + if _ControlType() is "table" then put "column" into theBehaviorType + else put "row" into theBehaviorType + answer "An error has occurred in behavior for the " & theBehaviorType & " template:" & cr & \ + revIDELookupError("execution", pError) with "OK" or "Edit Script" + if it is "Edit Script" then + repeat for each line theLine in pError + if there is a (item 4 of theLine) then + if theLastLineNo is not an integer then put item 2 of theLine into theLastLineNo + showLineOfScript item 4 of theLine, theLastLineNo + exit repeat + else + put item 2 of theLine into theLastLineNo + end if + end repeat + end if + + throw empty + else + throw pError + end if +end _ReportBehaviorError + + +# Parameters +# pObject : reference to the object owning the executing code +# pLine : the number of line about to be executed +# Description +# Called when the script editor may need to be updated because a new line +# of code is about to be executed in the debugger. If there is no script +# editor open for pObject then does nothing. +# Otherwise tells the script editor to display the appropriate line etc. +private command showLineOfScript pObject, pLine + local tScriptEditor + put revScriptEditor(the long ID of pObject) into tScriptEditor + if tScriptEditor is empty then + edit the script of pObject + end if + + put revScriptEditor(the long ID of pObject) into tScriptEditor + + if tScriptEditor is not empty then + local tState + put "edit" into tState + + local tMode + send "revSEGetMode" to stack tScriptEditor + put the result into tMode + if tState is not tMode then + # This must be sent in time to allow the script editor a chance to set its current object, + # otherwise an infinite loop could occur. + send "revSESetMode tState" to stack tScriptEditor in 0 milliseconds + end if + + local tFalseString + put "false" into tFalseString + + # These must be sent in time to allow the script editor a chance to set its current object, + # otherwise an infinite loop could occur. + send "revSEGoExecutionPoint pObject, pLine, true" to stack tScriptEditor in 0 milliseconds + send "revSEUpdate tFalseString" to stack tScriptEditor in 0 milliseconds + + # OK-2008-08-18 : Bug 6935 - Toplevel / uniconify the script editor here. + revGoScriptEditor the name of stack tScriptEditor + end if +end showLineOfScript + + +private command _CancelMessage pMsg + local theMessage,theMessages + + repeat until (comma & pMsg & comma) is not in the pendingMessages + put the pendingMessages into theMessages + filter theMessages with "*," & pMsg & ",*" + repeat for each line theMessage in theMessages + cancel item 1 of theMessage + end repeat + end repeat +end _CancelMessage + + +private command _CacheControls + ----- + local i + local msgsAreLocked + local theControl + local theIndex + local theExtraControls + local theListGroupRect + local theRecordCount + local theRect + local theSequence + local theTemplateGroup + local theTopLeft + local theControlHeight + ----- + lock screen + put the lockMessages into msgsAreLocked + + ## If auto hiding scrollbar then calculate height and hide scrollbar before + ## caching controls. + ## Double check in case developer locked messages and set + ## the dgProps["autohide scrollbar"] + if the dgProps["show vscrollbar"] of me is "auto" and the dgProps["fixed row height"] of me then + _CalculateFormattedHeight + _AutoHideVScrollbar + end if + + put empty into sControlHeights + put 0 into sFormattedHeight + + local controlHeightIsFixed + put the dgProps["fixed row height"] of me into controlHeightIsFixed + + ## Setup + put the dgProps["row template"] of me into theTemplateGroup + put max(0, the number of elements of sDataArray) into theRecordCount + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + + ## Delete any extra controls + put line (theRecordCount + 1) to -1 of sTableObjectsA["all row controls"] into theExtraControls + + lock messages + repeat for each line theControl in theExtraControls + delete theControl + end repeat + delete line (theRecordCount + 1) to -1 of sTableObjectsA["all row controls"] + + ## Create controls as needed + repeat with i = the number of lines of sTableObjectsA["all row controls"] + 1 to theRecordCount + copy theTemplateGroup to group "dgList" of me + put "control id" && word 3 of it && "of me" & cr after sTableObjectsA["all row controls"] + set the name of it to the short name of it && format("%04d", i) + set the layerMode of it to "dynamic" + + ## Take over geometry + set the lockloc of it to true + end repeat + if the last char of sTableObjectsA["all row controls"] is cr then delete the last char of sTableObjectsA["all row controls"] + unlock messages + + ## Link each index with a control + put 0 into theSequence + repeat for each line theControl in sTableObjectsA["all row controls"] + add 1 to theSequence + put theControl into sControlOfIndexA[item theSequence of sIndexSequencing] + end repeat + + ## Fill in control data and resize + put 0 into theSequence + repeat for each item theIndex in sIndexSequencing + add 1 to theSequence + put sControlOfIndexA[theIndex] into theControl + + ## Set geometry + if controlHeightIsFixed then + if theControlHeight is empty then + ## Cache to speed things up + put the height of theControl into theControlHeight + end if + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + theControlHeight into theRect + else + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect + end if + + lock messages + set the dgIndex of theControl to theIndex + unlock messages + + ## Get height + if sDataArray[theIndex] is NULL then + local theDataA + GetDataForLine theSequence, theDataA + dispatch "CalculateFormattedHeight" to theControl with theDataA + if it is "unhandled" then + dispatch "FillInData" to theControl with theDataA + + set the topLeft of theControl to theTopLeft ## After in case FillInData moves stuff around + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + + if not controlHeightIsFixed then + ## LockLoc = true so resize to fit height + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + lock messages + set the rect of theControl to theRect + unlock messages + end if + + put the height of theControl into sControlHeights[theIndex] + else + put the result into sControlHeights[theIndex] + end if + else + dispatch "CalculateFormattedHeight" to theControl with sDataArray[theIndex] + if it is "unhandled" then + dispatch "FillInData" to theControl with sDataArray[theIndex] + + set the topLeft of theControl to theTopLeft ## After in case FillInData moves stuff around + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + + if not controlHeightIsFixed then + ## LockLoc = true so resize to fit height + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + lock messages + set the rect of theControl to theRect + unlock messages + end if + + put the height of theControl into sControlHeights[theIndex] + else + put the result into sControlHeights[theIndex] + end if + end if + + ## Add to formattedheight + add sControlHeights[theIndex] to sFormattedHeight + + ## All controls start off hidden + set the visible of theControl to false + end repeat + + if the dgProps["fixed row height"] of me then + put sControlHeights[theIndex] into sControlHeights + end if + + _ConfigureScrollbar + + set the lockMessages to msgsAreLocked + + unlock screen +end _CacheControls + + +## Used when refreshing the list: call LayoutControl but nothing else. +## Code is modified version of _CacheControls +private command _LayoutCachedControls + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + + put empty into sControlHeights + put 0 into sFormattedHeight + + local controlHeightIsFixed, theListGroupRect, theTopLeft + put the dgProps["fixed row height"] of me into controlHeightIsFixed + put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect + put item 1 to 2 of theListGroupRect into theTopLeft + + repeat for each item theIndex in sIndexSequencing + local theControl, theControlHeight, theRect + put sControlOfIndexA[theIndex] into theControl + + ## Set geometry + if controlHeightIsFixed then + if theControlHeight is empty then + ## Cache to speed things up + put the height of theControl into theControlHeight + end if + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + theControlHeight into theRect + else + put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect + end if + + set the topLeft of theControl to theTopLeft ## After in case FillInData moves stuff around + lock messages + set the rect of theControl to theRect + unlock messages + dispatch "LayoutControl" to theControl with theRect, DG2_GetWorkingRectOfControlFromControlRect(theControl, theRect) + + if not controlHeightIsFixed then + ## LockLoc = true so resize to fit height + put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect + lock messages + set the rect of theControl to theRect + unlock messages + end if + + put item 4 of theRect - item 2 of theRect into sControlHeights[theIndex] + + ## Add to formattedheight + add sControlHeights[theIndex] to sFormattedHeight + end repeat + + if controlHeightIsFixed then + put sControlHeights[theIndex] into sControlHeights + end if + + _ConfigureScrollbar + + set the lockMessages to msgsAreLocked + + unlock screen +end _LayoutCachedControls + +private command _HiliteControl pControl, pBoolean + if there is a graphic "Background" of pControl then + ## Compute the new background color based on whether it is hilited and + ## if not hilited, whether alternating colors should be used. + local tNewBackgroundColor + if pBoolean then + put _GetHiliteColor() into tNewBackgroundColor + else + set the wholeMatches to true + local theLine + put itemOffset(the dgIndex of pControl, sIndexSequencing) into theLine + if theLine mod 2 is kAlternatingRowModValue then + put _GetEffectiveColor("alternate row color") into tNewBackgroundColor + else + put _GetEffectiveColor("row color") into tNewBackgroundColor + end if + end if + + ## [[ ColorRedraw ]] Only update the background color if it has actually + ## changed. + if the backgroundColor of graphic "Background" of pControl is not tNewBackgroundColor then + set the backgroundColor of graphic "Background" of pControl to tNewBackgroundColor + end if + end if + + local msgsAreLocked + put the lockMessages into msgsAreLocked + unlock messages + set the dgHilite of pControl to pBoolean + set the lockMessages to msgsAreLocked +end _HiliteControl + + +private function _GetEffectiveColor pProperty + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local theColor + put the dgProps[pProperty] of me into theColor + set the lockMessages to msgsAreLocked + + if theColor is not a color then + switch pProperty + case "column divider color" + return the effective borderColor of me + break + case "row color" + return kRowColor + break + case "alternate row color" + if the dgProps["alternate row colors"] of me then + return kAlternateRowColor + else + return _GetEffectiveColor("row color") + end if + break + case "dimmed hilite color" + return kDefaultDimmedHiliteColor + break + case "hilite color" + return the hiliteColor + break + case "hilited text color" + if sSystemA["hilited text color"] is a color and not (the long ID of me is not in the long ID of the focusedObject and the dgProps["dim on focusOut"] of me is not false) then + return sSystemA["hilited text color"] + else + -- Check the RGB values of the hiliteColor; add them + -- up and average them - if the result >128 then show black text, and if it's + -- <=128 then show white text. (Thanks Ken) + local theHiliteColor + put _GetHiliteColor("hilite color") into theHiliteColor + if the number of items of theHiliteColor is not 3 then put _ColorToRGB(theHiliteColor) into theHiliteColor + local theAvg + put item 1 of theHiliteColor + item 2 of theHiliteColor + item 3 of theHiliteColor into theAvg + put round(theAvg / 3) into theAvg + if theAvg > 128 then return "0,0,0" + else return "255,255,255" + end if + break + end switch + else + return theColor + end if +end _GetEffectiveColor + + +private function _GetHiliteColor + ## changed in 1.0.0 b4 + if the long ID of me is not in the long ID of the focusedObject and the dgProps["dim on focusOut"] of me is not false then + local theColor + put _GetEffectiveColor("dimmed hilite color") into theColor + put the dgProps["dimmed hilite color"] of me into theColor + if theColor is empty then + put kDefaultDimmedHiliteColor into theColor + end if + else + put the dgProps["hilite color"] of me into theColor + if theColor is empty then + put the hiliteColor into theColor + end if + end if + return theColor +end _GetHiliteColor + + +private function _IsThisModifierSetActive pModifiers + replace "alt" with "option" in pModifiers + + set the wholeMatches to true + + local theState + put the optionKey into theState + if "option" is among the items of pModifiers then + if theState is "up" then + return false + end if + else if theState is "down" then + return false + end if + + put the shiftKey into theState + if "shift" is among the items of pModifiers then + if theState is "up" then + return false + end if + else if theState is "down" then + return false + end if + + if the platform is "MacOS" then + put the commandKey into theState + if "command" is among the items of pModifiers then + if theState is "up" then + return false + end if + else if theState is "down" then + return false + end if + + put the controlKey into theState + if "control" is among the items of pModifiers then + if theState is "up" then + return false + end if + else if theState is "down" then + return false + end if + else + put the commandKey into theState + if "command" is among the items of pModifiers or "control" is among the items of pModifiers then + if theState is "up" then + return false + end if + else if theState is "down" then + return false + end if + end if + + return true +end _IsThisModifierSetActive + + +--> Animation + + +constant kFrameLength = 10 +constant kAnimationLength = 300 + +command StartScrollAnimation pScrollTo + if sPendingMsgsA["UpdateScrollAnimation"] is not empty then + cancel sPendingMsgsA["UpdateScrollAnimation"] + put empty into sPendingMsgsA["UpdateScrollAnimation"] + end if + + put true into sIsAnimating + local rightNow, scrollFrom + put the milliseconds into rightNow + put the dgVScroll of me into scrollFrom + + ScheduleScrollAnimation scrollFrom, pScrollTo, rightNow, "ease in out", rightNow, rightNow + kAnimationLength +end StartScrollAnimation + + +command CancelAnimation + put false into sIsAnimating + cancel sPendingMsgsA["UpdateScrollAnimation"] + put empty into sPendingMsgsA["UpdateScrollAnimation"] +end CancelAnimation + + +command ScheduleScrollAnimation pScrollFrom, pScrollTo, pLastTime, pPhase, pPhaseStart, pPhaseEnd + if not sIsAnimating then return empty + + local rightNow, theNextTime + put the milliseconds into rightNow + ## Synchronize to the system clock. + put (rightNow - (rightNow mod kFrameLength)) + kFrameLength into theNextTime + + send "UpdateScrollAnimation pScrollFrom, pScrollTo, pLastTime, pPhase, pPhaseStart, pPhaseEnd" to me in theNextTime - rightNow milliseconds + put the result into sPendingMsgsA["UpdateScrollAnimation"] +end ScheduleScrollAnimation + + +command UpdateScrollAnimation pScrollFrom, pScrollTo, pLastTime, pPhase, pPhaseStart, pPhaseEnd + put empty into sPendingMsgsA["UpdateScrollAnimation"] + if not sIsAnimating then return empty + + local rightNow, theExponent + put the milliseconds into rightNow + + put 2 into theExponent + + local theValue + switch pPhase + case "ease in" + put round(aeEaseIn(pScrollFrom, pScrollTo, kAnimationLength, pLastTime - pPhaseStart, theExponent)) into theValue + break + case "ease in out" + case "ease in and out" + put round(aeEaseInOUt(pScrollFrom, pScrollTo, kAnimationLength, pLastTime - pPhaseStart, theExponent)) into theValue + break + case "ease out" + default + put round(aeEaseOut(pScrollFrom, pScrollTo, kAnimationLength, pLastTime - pPhaseStart, theExponent)) into theValue + end switch + + lock screen + + local theControl + put the long ID of the focusedObject into theControl + + local msgsAreLocked + put the lockMessages into msgsAreLocked + + if not msgsAreLocked then lock messages + if __HasMobileScroller() then + mobileControlSet sScrollerId, "vScroll", theValue + end if + set the thumbPosition of scrollbar "dgScrollbar" of me to theValue + if not msgsAreLocked then unlock messages + + _ScrollListV theValue + + ## Make sure focus stays with us + if the long ID of me is in theControl and (there is not a theControl or the long ID of me is not in the long ID of the focusedobject) then + focus on graphic "dgBackground" of me + end if + + unlock screen + + ## Schedule next animation + if pScrollFrom > pScrollTo then + if theValue > pScrollTo then + ScheduleScrollAnimation pScrollFrom, pScrollTo, rightNow, pPhase, pPhaseStart, pPhaseEnd + else + put false into sIsAnimating + end if + else + if theValue < pScrollTo then + ScheduleScrollAnimation pScrollFrom, pScrollTo, rightNow, pPhase, pPhaseStart, pPhaseEnd + else + put false into sIsAnimating + end if + end if +end UpdateScrollAnimation + + +--> Errors (Private) + + +private command _ThrowError pErrNum, pMsg + ## error number, line number, col number, message + if pErrNum is empty then put 567 into pErrNum ## external error + + ## Build error to throw using executionContexts + local theContexts + put the executionContexts into theContexts + + ## don't want reference to self + delete the last line of theContexts + + local theContextsA, theCount, theError + put _ParseExecutionContexts(theContexts) into theContextsA + + put item 2 of line 1 of the extents of theContextsA into theCount + put format("%u,%u,%u,%s\n", pErrNum, theContextsA[theCount]["line number"], 0, pMsg) after theError + repeat with i = theCount down to 1 + put format("%u,%u,%u,%s\n", pErrNum, theContextsA[i]["line number"], 0, theContextsA[i]["handler"]) after theError + put format("%u,%u,%u,%s\n", pErrNum, theContextsA[i]["line number"], 0, theContextsA[i]["object"]) after theError + end repeat + delete the last char of theError + throw theError +end _ThrowError + + +private function _ParseExecutionContexts pContexts + ----- + local theContext + local theContextsA + local theItem + ----- + ## Each line has object-long-id,handler-name,line-number,[parent script object][,] + ## Beware of quotes and commas in stack path name. They will get you. + ## How to properly parse? + + ## How many entries? + repeat for each line theContext in pContexts + local theIndex, theItemNo + add 1 to theIndex + put 0 into theItemNo + repeat for each item theItem in theContext + add 1 to theItemNo + if theItem is an integer then + ## found the line number + put theItem into theContextsA[theIndex]["line number"] + put item (theItemNo - 1) of theContext into theContextsA[theIndex]["handler"] + put item 1 to (theItemNo - 2) of theContext into theContextsA[theIndex]["object"] + + put item (theItemNo + 1) to -1 of theContext into theContextsA[theIndex]["parents"] + end if + end repeat + end repeat + + return theContextsA +end _ParseExecutionContexts + + +--> Line Breaks + + +command TruncateTail pFieldId, pTrailer + if pTrailer is empty then + put "..." into pTrailer + end if + + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + local tMaxWidth + put the width of field ID pFieldId - the leftMargin of field ID pFieldId into tMaxWidth + + if the formattedWidth of char 1 to -1 of field ID pFieldId <= tMaxWidth then + set the lockMessages to msgsAreLocked + unlock screen + return false + end if + + local tCharCount + put the number of chars of the text of field ID pFieldId into tCharCount + + local tFieldText + put the HTMLText of field ID pFieldId into tFieldText + set the text of field ID pFieldId to pTrailer + + local tTrailerWidth + put the formattedWidth of char 1 to -1 of field ID pFieldId into tTrailerWidth + + set the HTMLText of field ID pFieldId to tFieldText + + -- The 'linear' version requires n steps, where n is the average number of characters + -- that will fit into the field up to tMaxWidth. That version will behave well for small + -- widths, but will degrade significantly as the width increases. + + -- This version requires log_2(n) steps, where n is the number of characters in the field + -- this will be much faster for larger widths, but slower for very small widths when the + -- line is very long. + + -- The maximum length of the string we want is tMaxWidth minus the trailer width + subtract tTrailerWidth from tMaxWidth + + -- These two vars store the number of characters before the string that is too small (tLow) + -- and the number of chars that makes the string too long (tHigh) + local tLow, tHigh + put 0 into tLow + put tCharCount into tHigh + + -- tMid contains the current number of characters we are 'guessing' will fit in tWidth. + -- We make a initial estimate based on the width of the trailer. This initial estimate should + -- virtually eliminate any advantage the linear algorithm has over the binary search in the + -- case of a long line fitting into a small width. + local tMid + put tMaxWidth div (tTrailerWidth div 2) into tMid + + -- We loop until they are one apart - in which case the char between positions tLow and tHigh + -- contains the break width. + repeat while tHigh - tLow > 1 + + -- Compute the width of tMid characters. + local tWidth + put (the formattedWidth of char 1 to tMid + 1 of field ID pFieldId) into tWidth + + if tWidth > tMaxWidth then + -- If the new width is too much, bring down the high point + put tMid into tHigh + else if tWidth < tMaxWidth then + -- If the new width is too little, bring up the low point + put tMid into tLow + else + -- If we have reached the target width then exit, adjusting by one (we want + -- the number of chars that goes from too small, to too much) + put tMid into tLow + put tMid + 1 into tHigh + exit repeat + end if + + if tHigh - tLow <= 1 then + exit repeat + end if + + put tLow + (tHigh - tLow) div 2 into tMid + end repeat + + -- At this point tMid will contain the number of chars that causes a transition from too + -- short to too long. + + put pTrailer into char tMid to -1 of field ID pFieldId + set the textFont of char tMid to -1 of field ID pFieldId to the effective textFont of field ID pFieldId + + set the lockMessages to msgsAreLocked + unlock screen + + return true +end TruncateTail + + +--> Field Editing + +local sTemplateFieldEditorA + + +private command _ResetTemplateFieldEditor + put "text" into sTemplateFieldEditorA["text type"] + put NULL into sTemplateFieldEditorA["text"] + put false into sTemplateFieldEditorA["select text"] +end _ResetTemplateFieldEditor + + +command DeleteFieldEditorAndOpenNext + local msgsAreLocked + put the lockMessages into msgsAreLocked + unlock messages + + local shiftKeyIsDown, theField, theColumn, theCurrentLineNo, theIndex + put _IsThisModifierSetActive("shift") into shiftKeyIsDown + + put the dgTargetField of sFieldEditor into theField + put the dgColumn of the dgDataControl of theField into theColumn + put the dgTargetIndex of sFieldEditor into theIndex + put the dgLine of the dgDataControl of theField into theCurrentLineNo + DeleteFieldEditor true + + ## theField might not be a correct reference at this point as DeleteFieldEditor saves and redraws + if the dgIndex of the dgDataControl of theField is not theIndex then + put ColumnControlOfIndex(theColumn, theIndex) into theField ## This might not actually be a field. But what to do... + end if + + local theDirection, theColumns, theLineNo + if shiftKeyIsDown then put "back" into theDirection + else put "forward" into theDirection + + dispatch "OpenNextFieldEditor" to theField with theDirection + + local theColNumList + if it is not "handled" then + ## For tables we cycle through columns in current row + if _ControlType() is "table" then + set the wholeMatches to true + put _table.VisibleColumns() into theColumns + put lineOffset(theColumn, theColumns) into theLineNo + + if the number of lines of theColumns > 1 and theLineNo > 0 then + ## Generate list of column numbers to try and open + if theDirection is "forward" then + if theLineNo is the number of lines of theColumns then + repeat with i = 1 to the number of lines of theColumns + put i & comma after theColNumList + end repeat + delete the last char of theColNumList + else + repeat with i = theLineNo + 1 to the number of lines of theColumns + put i & comma after theColNumList + end repeat + repeat with i = 1 to theLineNo + put i & comma after theColNumList + end repeat + delete the last char of theColNumList + end if + else + if theLineNo is 1 then + put the number of lines of theColumns & comma into theColNumList + repeat with i = the number of lines of theColumns - 1 down to 1 + put i & comma after theColNumList + end repeat + delete the last char of theColNumList + else + put theLineNo - 1 & comma into theColNumList + repeat with i = theLineNo - 2 down to 1 + put i & comma after theColNumList + end repeat + repeat with i = the number of lines of theColumns down to theLineNo + put i & comma after theColNumList + end repeat + delete the last char of theColNumList + end if + end if + + ## Look for next column that supports editing + local jumpOutOfRepeat + put false into jumpOutOfRepeat + repeat for each item theNextColNum in theColNumList + local theNextColumn + put line theNextColNum of theColumns into theNextColumn + + if the dgColumnIsEditable[theNextColumn] of me then + repeat for each line theControl in sTableObjectsA["columns"][theNextColumn]["row controls"] + if the dgLine of the dgDataControl of theControl is theCurrentLineNo then + + dispatch "EditValue" to theControl + + if it is "unhandled" then + ## Try next column + next repeat + else + put true into jumpOutOfRepeat + _table.ScrollColumnIntoView theNextColumn + exit repeat + end if + end if + end repeat + end if + + if jumpOutOfRepeat then exit repeat + end repeat + + end if + end if + end if + + unlock screen + + set the lockMessages to msgsAreLocked +end DeleteFieldEditorAndOpenNext + + +command DeleteFieldEditor pSaveContents + local msgsAreLocked + put the lockMessages into msgsAreLocked + + if there is not a sFieldEditor then + ## If error occurred when messages were broadcast below then you could end up with + ## empty sFieldEditor. We get rid of it here. + ## We clear out sFieldEditor so that if an error does occur we don't come back later + ## and save changes. + if there is a field kFieldEditorName of group "dgListMask" of me then + lock messages + delete field kFieldEditorName of group "dgListMask" of me + set the lockMessages to msgsAreLocked + end if + + return empty + end if + + put pSaveContents is not false into pSaveContents + + unlock messages + + local theEditor, theResult, theField, theError + put sFieldEditor into theEditor + put empty into sFieldEditor + put empty into theResult + + put the dgTargetField of theEditor into theField + + ## Keeps focus from getting messed up when dgDataOfIndex redraws + if theEditor is the long ID of the focusedObject then + lock messages + focus on graphic "dgBackground" of me ## Engine doesn't like deleting focused control in groups + unlock messages + end if + + if pSaveContents and there is a theField then + local theIndex, theKey, contentHasChanged + put the dgTargetIndex of theEditor into theIndex + put the dgTargetKey of theEditor into theKey ## might be an array index + + set the caseSensitive to true + put the HTMLText of theEditor is not the dgOriginalHTMLText of theEditor into contentHasChanged + set the caseSensitive to false + + ## Did user want us to automatically save? + if theIndex is an integer and (theKey is not empty and theKey is not an array) then + if contentHasChanged then + + ## Give the developer a chance to stop value from being set + try + dispatch "CloseFieldEditor" to theField with theEditor + if it is "handled" then + put the result into theResult + end if + + if theResult is not "cancel" then + local theDataA + put sDataArray[theIndex] into theDataA + + switch the dgTextType of theEditor + case "html" + put the HTMLText of theEditor into theDataA[theKey] + break + case "rtf" + put the RTFText of theEditor into theDataA[theKey] + break + case "unicode" + put the unicodeText of theEditor into theDataA[theKey] + break + case "utf8" + put the unicodeText of theEditor into theDataA[theKey] + put uniDecode(theDataA[theKey], "utf8") into theDataA[theKey] + break + default + put the text of theEditor into theDataA[theKey] + end switch + set the dgDataOfIndex [theIndex] of me to theDataA + end if + catch e + put e into theError + end try + else + try + dispatch "ExitFieldEditor" to theField with theEditor + if it is "handled" then + put the result into theResult + end if + catch e + put e into theError + end try + end if + else + ## Announce our closing to the world + try + if contentHasChanged then + dispatch "CloseFieldEditor" to theField with theEditor + else + dispatch "ExitFieldEditor" to theField with theEditor + end if + if it is "handled" then + put the result into theResult + end if + catch e + put e into theError + end try + end if + end if ## pSaveContents check + + lock screen + if there is a theEditor then delete theEditor + set the lockMessages to msgsAreLocked + + ## If user displayed an answer dialog in any callbacks we end + ## up with unbalanced focusOut/In messages. This causes hilites + ## to stay grey. Force update + put true into sFocusLeftMe + _UpdateHiliteColor + unlock screen + + if theError is not empty then throw theError + + return theResult +end DeleteFieldEditor + + +setprop dgTemplateFieldEditor [pProp] pValue + switch pProp + case "htmltext" + put "html" into sTemplateFieldEditorA["text type"] + put pValue into sTemplateFieldEditorA["text"] + break + case "rtftext" + put "rtf" into sTemplateFieldEditorA["text type"] + put pValue into sTemplateFieldEditorA["text"] + break + case "text" + put "text" into sTemplateFieldEditorA["text type"] + put pValue into sTemplateFieldEditorA["text"] + break + case "unicodetext" + put "unicode" into sTemplateFieldEditorA["text type"] + put pValue into sTemplateFieldEditorA["text"] + break + case "utf8text" + put "utf8" into sTemplateFieldEditorA["text type"] + put pValue into sTemplateFieldEditorA["text"] + break + case "select text" + if pValue is not a boolean then _ThrowError kErrInvalidBoolean, pValue && "is not a boolean" + put pValue into sTemplateFieldEditorA["select text"] + break + default + _ThrowError kErrInvalidProperty, pProp && "is an invalid property" + end switch + + return empty +end dgTemplateFieldEditor + + +## Pass in pIndex and pKey to automatically update a record +## in the data grid. Otherwise update by hand in closeFieldEditor message. +command EditFieldText pField, pIndex, pKey + ----- + local i + local theBorderWidth + local theClickChunk, theClickField, theClickLine + local theError + local theMargins + local theText + ----- + if there is not a pField then _ThrowError kErrCantFindObject, "could not find field to create field editor for" + lock screen + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + + ## Cache where the person clicked as this data will change if + ## OpenInlineEditor changes position of the target + if the clickField is not empty then put the long ID of the clickField into theClickField + else put empty into theClickField + put the clickCharChunk into theClickChunk + put the clickLine into theClickLine + + focus on nothing + + ## Delete existing + DeleteFieldEditor + + reset the templatefield + + put the margins of pField into theMargins + if the number of items of theMargins is 1 then + repeat with i = 1 to 3 + put "," & item 1 of theMargins after theMargins + end repeat + end if + put the borderWidth of pField into theBorderWidth + if sTemplateFieldEditorA["text"] is NULL then + put the text of pField into sTemplateFieldEditorA["text"] ## default + end if + + set the autoTab of the templatefield to the autoTab of pField + set the dontWrap of the templatefield to the dontWrap of pField + set the tabStops of the templatefield to the tabStops of pField + set the margins of the templatefield to theMargins + set the borderWidth of the templatefield to theBorderWidth + set the textAlign of the templatefield to the effective textAlign of pField + set the textFont of the templatefield to the effective textFont of pField + set the textSize of the templatefield to the effective textSize of pField + set the textStyle of the templatefield to the effective textStyle of pField + set the fixedLineHeight of the templatefield to the fixedLineHeight of pField + set the opaque of the templatefield to true + set the threeD of the templatefield to true + + create field kFieldEditorName in group "dgListMask" of me + put the long ID of it into sFieldEditor + + set the behavior of sFieldEditor to the long ID of button "Field Editor" of _ResourceStack() + + set the rect of sFieldEditor to the rect of pField ## so formattedHeight will be correct in _resizeFieldToFitContent + + switch sTemplateFieldEditorA["text type"] + case "rtf" + set the RTFText of sFieldEditor to sTemplateFieldEditorA["text"] + put the HTMLText of sFieldEditor into theText + break + case "unicode" + set the unicodeText of sFieldEditor to sTemplateFieldEditorA["text"] + put the HTMLText of sFieldEditor into theText + break + case "utf8" + set the unicodeText of sFieldEditor to uniEncode(sTemplateFieldEditorA["text"], "utf8") + put the HTMLText of sFieldEditor into theText + break + case "html" + put sTemplateFieldEditorA["text"] into theText + break + case "text" + set the text of sFieldEditor to sTemplateFieldEditorA["text"] + put the HTMLText of sFieldEditor into theText + break + end switch + + set the HTMLText of sFieldEditor to theText + set the dgIsFieldEditor of sFieldEditor to true + set the dgOriginalHTMLText of sFieldEditor to theText + set the dgTextType of sFieldEditor to sTemplateFieldEditorA["text type"] + set the dgTargetField of sFieldEditor to pField + set the dgTargetIndex of sFieldEditor to pIndex # hilited line can change on selectionchanged occasions + set the dgTargetKey of sFieldEditor to pKey + unlock messages + + ## Bug when editing right|center-aligned text that is wider than field. + if the textAlign of sFieldEditor is not "left" and the formattedWidth of sFieldEditor >= the width of sFieldEditor then + set the textAlign of sFieldEditor to "left" + end if + + ## Shout our existence out to the world + try + dispatch "preOpenFieldEditor" to pField with sFieldEditor + catch e + put e into theError + + lock messages + delete sFieldEditor + unlock messages + end try + + if theError is not empty then throw theError + + lock messages + focus on sFieldEditor + focus on sFieldEditor ## When tabbing through table cells engine would not focus on sFieldEditor without 2nd call + -- put sFieldEditor & cr && the long id of the focusedobject + unlock messages + + if sTemplateFieldEditorA["select text"] is not false then + select char 1 to -1 of sFieldEditor + else + if theClickField is not empty and theClickField is the long ID of pField then + if theClickChunk is not empty then + select after char (word 2 of theClickChunk) of sFieldEditor + else if theClickLine is not empty then + select after line (word 2 of theClickLine) of sFieldEditor + else + select after char -1 of sFieldEditor + end if + else + select after char -1 of sFieldEditor + end if + end if + + reset the templatefield + _ResetTemplateFieldEditor + + set the lockMessages to msgsAreLocked + + unlock screen + + return empty +end EditFieldText + + +--> Private (Persistent Data) + + +## updates data and sequence +private command _StorePersistentData + if the dgProps["persistent data"] of me then + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + set the dgCache["data"] of me to sDataArray + set the dgCache["sequencing"] of me to sIndexSequencing + set the lockMessages to msgsAreLocked + end if +end _StorePersistentData + + +## Just updates the sequence +private command _StorePersistentSequence + if the dgProps["persistent data"] of me then + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + set the dgCache["sequencing"] of me to sIndexSequencing + set the lockMessages to msgsAreLocked + end if +end _StorePersistentSequence + + +private command _RestorePersistentData + if the dgProps["persistent data"] of me then + local msgsAreLocked + put the lockMessages into msgsAreLocked + lock messages + put the dgCache["data"] of me into sDataArray + put the dgCache["sequencing"] of me into sIndexSequencing + set the lockMessages to msgsAreLocked + end if +end _RestorePersistentData + + +--> Private (Alternating Row Colors) + + +private command _ShowAlternatingRows + lock screen + + local theRect, theStartSequence + switch _ControlType() + case "table" + put the rect of group "dgListMask" of me into theRect + add sControlHeights to item 4 of theRect + set the rect of graphic "dgAlternatingRows" of me to theRect + put sTableObjectsA["base sequence for visible controls"] into theStartSequence + if theStartSequence is not an integer then put 1 into theStartSequence + + if theStartSequence mod 2 is kAlternatingRowModValue then + set the top of graphic "dgAlternatingRows" of me to the top of group "dgAlternatingRowsMask" of me - sControlHeights + else + set the top of graphic "dgAlternatingRows" of me to the top of group "dgAlternatingRowsMask" of me + end if + set the visible of graphic "dgAlternatingRows" of me to the dgProps["alternate row colors"] of me + break + + case "form" + default + if the dgProps["alternate row colors"] of me and sFormattedHeight < the height of group "dgList" of me then + put the rect of group "dgListMask" of me into theRect + put item 2 of theRect + sFormattedHeight into item 2 of theRect + set the rect of graphic "dgAlternatingRows" of me to theRect + show graphic "dgAlternatingRows" of me + else + hide graphic "dgAlternatingRows" of me + end if + end switch + + unlock screen + + return empty +end _ShowAlternatingRows + + +private command _FillInEmptyRowHeight + ## Fill in default row height if empty + if the dgProps["alternate row colors"] of me and the dgProps["row height"] of me is empty then + if sControlHeights is an integer then + set the dgProps["row height"] of me to sControlHeights + else if the keys of sControlHeights is not empty then + set the dgProps["row height"] of me to sControlHeights[1] + end if + end if + return empty +end _FillInEmptyRowHeight + + +private command _DrawAlternatingRows + ----- + local theOffset + local theOtherColor + local theRowColor, theRowHeight + local theTemplateGroup + local theStartSequence + ----- + put sTableObjectsA["base sequence for visible controls"] into theStartSequence + if _ControlType() is "form" then + ## For forms the alternating lines draw from the bottom of displayed rows down. + ## That means we need to determine alternating row color from last record down. + ## Since the rows only show up if there aren't enough controls to fill the space + ## we can just use the extents of the data array. If it is too high then no big deal. + put max(1, the number of elements of sDataArray + 1) into theStartSequence + else + if theStartSequence is not an integer then + put 1 into theStartSequence + end if + end if + + _FillInEmptyRowHeight + local alternateTheColors + put the dgProps["alternate row colors"] of me into alternateTheColors + + set the visible of graphic "dgAlternatingRows" of me to alternateTheColors + if alternateTheColors then + local theAlternateRowColor, theWidth, theFirstColor, theSecondColor + put _GetEffectiveColor("alternate row color") into theAlternateRowColor + put _GetEffectiveColor("row color") into theRowColor + put the dgProps["row height"] of me into theRowHeight + if theRowHeight is not an integer then put kDefaultRowHeight into theRowHeight + put 0 into theOffset + put 1 into theWidth + + if theStartSequence mod 2 is kAlternatingRowModValue then + put theAlternateRowColor into theFirstColor + put theRowColor into theSecondColor + else + put theRowColor into theFirstColor + put theAlternateRowColor into theSecondColor + end if + + _CreateAlternatingColorImage the long ID of image "dgAlternatingRows" of me, theFirstColor, theSecondColor, \ + theRowHeight, theWidth, theOffset + set the backgroundPattern of graphic "dgAlternatingRows" of me to empty + set the backgroundPattern of graphic "dgAlternatingRows" of me to the ID of image "dgAlternatingRows" of me + else + set the backgroundPattern of graphic "dgAlternatingRows" of me to empty + set the text of image "dgAlternatingRows" of me to empty + end if + + return empty +end _DrawAlternatingRows + + +private command _CreateAlternatingColorImage pDestImg, pColor1, pColor2, pRowHeight, pWidth, pOffset + ----- + local theColor1Pixel, theColor2Pixel + local theColor1Row, theColor1RowImgData, theColor2Row, theColor2RowImgData, theRow + local theOffsetRow + local thePixel + local theRect + ----- + if pRowHeight is empty then put 18 into pRowHeight + if pWidth is empty then put 500 into pWidth + put max(0, pOffset) into pOffset + + ## turn strings into arrays + split pColor1 by comma + split pColor2 by comma + + ## Create a pixel for color 1 and 2 + put numToChar(0) into theColor1Pixel + put numToChar(pColor1[1]) after theColor1Pixel + put numToChar(pColor1[2]) after theColor1Pixel + put numToChar(pColor1[3]) after theColor1Pixel + + put numToChar(0) into theColor2Pixel + put numToChar(pColor2[1]) after theColor2Pixel + put numToChar(pColor2[2]) after theColor2Pixel + put numToChar(pColor2[3]) after theColor2Pixel + + ## build 1 complete row of using pixel + repeat with thePixel = 1 to pWidth + put theColor1Pixel after theColor1RowImgData + put theColor2Pixel after theColor2RowImgData + end REPEAT + + ## if pOffset is set then build sliver of row 2 color + repeat with theRow = 1 to pOffset + put theColor2RowImgData after theOffsetRow + end repeat + + ## build color 1 row + repeat with theRow = 1 to pRowHeight + put theColor1RowImgData after theColor1Row + end REPEAT + + ## finish building row 2 color + repeat with theRow = 1 to pRowHeight - pOffset + put theColor2RowImgData after theColor2Row + end repeat + + put the rect of pDestImg into theRect + put item 1 of theRect + pWidth into item 3 of theRect + put item 2 of theRect + pRowHeight * 2 into item 4 of theRect + + ## Worka round crash bug when "jpeg" + local theOrigCompr + put the paintCompression into theOrigCompr + set the paintCompression to "rle" + + lock screen + set the rect of pDestImg to theRect + set the imageData of pDestImg to theOffsetRow & theColor1Row & theColor2Row + unlock screen + + set the paintCompression to theOrigCompr + + return empty +end _CreateAlternatingColorImage + +private function __HasMobileScroller + return the environment is "mobile" and \ + sScrollerId is not empty and \ + sScrollerId is among the lines of mobileControls() +end __HasMobileScroller + +command __EnableMobileScroller + if __HasMobileScroller() then + mobileControlSet sScrollerId, "scrollingEnabled", "true" + end if +end __EnableMobileScroller + +command __DisableMobileScroller + if __HasMobileScroller() then + mobileControlSet sScrollerId, "scrollingEnabled", "false" + end if +end __DisableMobileScroller + +-------------------------------------------------------------------------------- +-- DataGrid 2 +-------------------------------------------------------------------------------- + +private command DG2_ClearVars + put false into sEditMode + + put false into sReorderInProgress + put empty into sReorderControl + put empty into sReorderStartIndex + put empty into sReorderStartLine + put empty into sReorderLastHoverLine + put false into sReorderMouseMoveInProgress + + cancel sReorderMoveMsgId + put empty into sReorderMoveMsgId + + cancel sAnimationsPulseMsgID + put empty into sAnimationsPulseMsgID + put empty into sAnimationsA + put empty into sAnimationsLastID + + cancel sReorderScrollPollMsgID + put empty into sReorderScrollPollMsgID + + DG2_CustomisableControlsClear + return the result +end DG2_ClearVars + +private command DG2_EnsureRowChainedBehavior + -- DataGrid 2 uses a behavior for each row to detect swipes and such. + -- Make sure this behavior is applied to the end of the template row's behavior + -- chain. + if the dgProps["row template"] of me is not empty and there is a the dgProps["row template"] of me then + local tChainedBehavior + put the long ID of button "Row Chained Behavior" of group "Behaviors" of _ResourceStack() into tChainedBehavior + + local tControl + put the behavior of the dgProps["row template"] of me into tControl + + -- Repeat through to the end of the behavior chain, exiting the loop if the + -- template behavior already set. + repeat while tControl is not empty and the behavior of tControl is not empty and the long id of the behavior of tControl is not tChainedBehavior + put the behavior of tControl into tControl + end repeat + + if tControl is not empty and the behavior of tControl is empty then + set the behavior of tControl to tChainedBehavior + end if + end if + + return empty +end DG2_EnsureRowChainedBehavior + +function DG2_GetMessageNameForTag pTag + switch pTag + case "EditModeReorderStarted" + return kEditModeEditModeReorderStarted + case "EditModeReorderCompleted" + return kEditModeEditModeReorderCompleted + case "EditModeActionSelectControlClicked" + return kMessageEditModeActionSelectControlClicked + case "EditModeActionControlClicked" + return kMessageEditModeActionControlClicked + case "EditModeActionControlHidden" + return kMessageEditModeActionControlHidden + case "RowSwipedRight" + return kMessageRowSwipedRight + case "RowSwipedLeft" + return kMessageRowSwipedLeft + case "RowLeftSwipeControlClicked" + return kMessageRowLeftSwipeControlClicked + case "RowRightSwipeControlClicked" + return kMessageRowRightSwipeControlClicked + case "RowLeftSwipeControlHidden" + return kMessageRowLeftSwipeControlHidden + case "RowRightSwipeControlHidden" + return kMessageRowRightSwipeControlHidden + end switch +end DG2_GetMessageNameForTag + +-------------------------------------------------------------------------------- +-- DataGrid2 Public Commands + +-- RowSwipeShowControlForIndexAndSide +-- +-- Fully slide in the swipe control from the specified side for the row with +-- the specified index. +-- This command is typically used after a swipe gesture to fully reveal the swipe +-- control for the row. +-- +-- pIndex - The index of the row we want the swipe control to appear on. +-- pSide - The side want the control to appear. "left" or "right" +-- +command RowSwipeShowControlForIndexAndSide pIndex, pSide + if not the dgProps["enable swipe"] of me then + return "Enable swipe is not set" + end if + + if pSide is not among the words of "left right" then + return "Unknown side" && pSide + end if + + set the wholeMatches to true + if pIndex is not among the items of the dgIndexes of me then + return "Unknown index" && pIndex + end if + + -- The swipe control is housed in a holder group that is overlaid on top + -- of the list. This is used to block/catch all mouse events when the control + -- is visible. + local tSwipeControlHolder + put DG2_SwipeControlHolderGet() into tSwipeControlHolder + if tSwipeControlHolder is empty then + return "Could not find swipre control holder" + end if + + set the dgSwipeControlSide of tSwipeControlHolder to pSide + set the dgSwipeControlRowIndex of tSwipeControlHolder to pIndex + return the result +end RowSwipeShowControlForIndexAndSide + +-- RowSwipeHideControl +-- +-- Hide any visible swipe control. +-- Don't animate is typically set if we are about to perform a subsequent +-- animation. For example, when deleting a row. +-- +-- pDontAnimate - Set to true to not animate the hide. +-- +command RowSwipeHideControl pDontAnimate + if not the dgProps["enable swipe"] of me then + return "Enable swipe is not set" + end if + + local tSwipeControlHolder + put DG2_SwipeControlHolderGet() into tSwipeControlHolder + if tSwipeControlHolder is empty then + return "Could not find swipre control holder" + end if + + if not the visible of tSwipeControlHolder then + return empty + end if + + -- If we don't want to animate, hide the holder. + -- This will instantly hide the swipe control. + -- The holder will then take care of any tidying up. + lock screen + if pDontAnimate then + set the visible of tSwipeControlHolder to false + end if + set the dgSwipeControlRowIndex of tSwipeControlHolder to empty + get the result + unlock screen + + return it +end RowSwipeHideControl + +-- EditModeShowActionControlForIndex +-- +-- Slide in the action control from the left hand side of the row with +-- the specified index. +-- +-- pIndex - The index of the row we want the action control to appear for. +-- +command EditModeShowActionControlForIndex pIndex + if not sEditMode then + return "Action control can only be shown in edit mode" + end if + + set the wholeMatches to true + if pIndex is not among the items of the dgIndexes of me then + return "Unknown index" && pIndex + end if + + -- The action control is housed in a holder group that is overlaid on top + -- of the list. This is used to block/catch all mouse events when the control + -- is visible. + local tActionControlHolder + put DG2_EditModeActionControlHolderGet() into tActionControlHolder + if tActionControlHolder is empty then + return "Could not find action control holder" + end if + + set the dgActionControlRowIndex of tActionControlHolder to pIndex + return the result +end EditModeShowActionControlForIndex + +-- EditModeHideActionControl +-- +-- Hide any visible action control. +-- Don't animate is typically set if we are about to perform a subsequent +-- animation. For example, when deleting a row. +-- +-- pDontAnimate - Set to true to not animate the hide. +-- +command EditModeHideActionControl pDontAnimate + if not sEditMode then + return empty + end if + + local tActionControlHolder + put DG2_EditModeActionControlHolderGet() into tActionControlHolder + if tActionControlHolder is empty then + return "Could not find action control holder" + end if + if not the visible of tActionControlHolder then + return empty + end if + + -- If we don't want to animate, hide the holder. + -- This will instantly hide the swipe control. + -- The holder will then take care of any tidying up. + lock screen + if pDontAnimate then + set the visible of tActionControlHolder to false + end if + set the dgActionControlRowIndex of tActionControlHolder to empty + get the result + unlock screen + + return it +end EditModeHideActionControl + +---------------------------------------------------------------------- +-- DataGrid 2 default implementations of swipe and edit mode actions. +-- +-- By default we don't handle RowSwipedLeft and RowSwipedRight. This results in +-- the swipe control being fully revealed allowing the user to click it. If the +-- swipe control is clicked, delete this row. +-- +-- By default, when the action select control is clicked, reveal the action +-- control. +-- +-- By default, when the action control is clicked, delete the row. +-- +-- These behaviors can be overriden by handling these messages in the user +-- scripts. +-- +-- These messages are handled at this point of the message path to allow +-- users to potentially handle them at group level. + +on RowLeftSwipeControlClicked pTarget + DeleteIndex the dgIndex of the target +end RowLeftSwipeControlClicked + +on RowRightSwipeControlClicked pTarget + DeleteIndex the dgIndex of the target +end RowRightSwipeControlClicked + +on EditModeActionSelectControlClicked pTarget + EditModeShowActionControlForIndex the dgIndex of the target +end EditModeActionSelectControlClicked + +on EditModeActionControlClicked pTarget + DeleteIndex the dgIndex of the target +end EditModeActionControlClicked + +-------------------------------------------------------------------------------- +-- DataGrid 2 Edit Mode Handlers + +setProp dgEditMode pMode + if pMode then + if the dgProps["style"] of me is not "form" then + throw "Edit mode can only be applied to form controls" + end if + if not the dgProps["fixed row height"] of me then + return "Edit mode can only be to controls with fixed row heights" + end if + end if + + local tResult + if pMode and not sEditMode then + DG2_EditModeEnter + put the result into tResult + else if not pMode and sEditMode then + DG2_EditModeLeave + put the result into tResult + end if + + if tResult is empty then + put pMode into sEditMode + end if + + return tResult +end dgEditMode + +getProp dgEditMode + return sEditMode +end dgEditMode + +private command DG2_EditModeEnter + -- We set sEditMode here to ensure all subsequent redraws include the edit + -- mode controls. + put true into sEditMode + + -- If any swipes are in progress, tidy them up. + RowSwipeHideControl true + + -- We use callbacks within the standard draw procedure to handle the + -- animating in. + _DrawListWithProperties sTableObjectsA["base sequence for visible controls"], the vScroll of group "dgList" of me, true, "DG2_EditModeEnterDrawCallback" + return empty +end DG2_EditModeEnter + +private command DG2_EditModeLeave + -- If an edit mode action control is visible, tidy it up. + EditModeHideActionControl true + _DrawListWithProperties sTableObjectsA["base sequence for visible controls"], the vScroll of group "dgList" of me, true, "DG2_EditModeLeaveDrawCallback" + return empty +end DG2_EditModeLeave + +on DG2_EditModeEnterDrawCallbackStart @pContextA, pTopLeft + put empty into pContextA["animations"] + put 0 into pContextA["animation count"] +end DG2_EditModeEnterDrawCallbackStart + +on DG2_EditModeEnterDrawCallback @pContextA, pControl, pLineNo, @pControlRect, @pControlTopLeft + -- We are about to animate in. If there is an action control, it will appear + -- on the left hand side of the row control. + -- Therefore we need to extend the row control's left the accomodate the action control. + -- The rect is passed by reference, meaning all future layouts in standard drawing loop + -- will be effected also. + local tActionSelectControl + put DG2_CustomisableControlsGetEditModeActionSelectControlForControl(the long id of pControl) into tActionSelectControl + if tActionSelectControl is not empty then + subtract the width of tActionSelectControl from item 1 of pControlRect + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(pControl, "left", item 1 of pControlRect, item 1 of pControlRect + the width of tActionSelectControl, the dgAnimationProp["EditModeEnterExitDuration"] of me, the dgAnimationProp["EditModeEnterExitActionSelectControlControlEasing"] of me) into pContextA["animations"][pContextA["animation count"]] + end if + + -- Fade in the reorder control. + -- + local tReorderControl + put DG2_CustomisableControlsGetEditModeReorderControlForControl(the long id of pControl) into tReorderControl + if tReorderControl is not empty then + set the right of tReorderControl to item 3 of pControlRect + set the visible of tReorderControl to true + set the blendLevel of tReorderControl to 100 + + -- Continually setting the left of the reorder control during the animation ensures + -- that it is always in the same position (at the right hand side of the list) and + -- thus not effected by the control sliding in from the right (which would naturally + -- move the roerder control right). + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(tReorderControl, "left", the left of tReorderControl, the left of tReorderControl, the dgAnimationProp["EditModeEnterExitDuration"] of me, "linear") into pContextA["animations"][pContextA["animation count"]] + + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(tReorderControl, "blendLevel", 100, 0, the dgAnimationProp["EditModeEnterExitDuration"] of me, the dgAnimationProp["EditModeEnterExitReorderControlEasing"] of me) into pContextA["animations"][pContextA["animation count"]] + end if + + -- If the controls are cached, "LayoutControl" won't be called by the standard draw loop. + -- But we need it to be called to reposition everying inside the row to take account of + -- any edit mode controls, so do dispatch "LayoutControl" here. + if the dgProps["cache controls"] of me then + set the rect of pControl to pControlRect + dispatch "LayoutControl" to pControl with pControlRect, DG2_GetWorkingRectOfControlFromControlRect(pControl, pControlRect) + end if +end DG2_EditModeEnterDrawCallback + +on DG2_EditModeEnterDrawCallbackEnd @pContextA + -- Queue all the animations and add an end callback to the final animation. + -- The end callback will tidy everything up. + if pContextA["animation count"] is not 0 then + DG2_AnimationsAnimationSetCompletionMessage pContextA["animations"][pContextA["animation count"]], "DG2_EditModeAnimateComplete" + DG2_AnimationsAnimationSetMessageTarget pContextA["animations"][pContextA["animation count"]], the long id of me + DG2_AnimationsBatchAddWithArray pContextA["animations"] + else + send "DG2_EditModeAnimateComplete" to me in 0 seconds + end if +end DG2_EditModeEnterDrawCallbackEnd + +on DG2_EditModeLeaveDrawCallbackStart @pContextA, pTopLeft + put empty into pContextA["animations"] + put 0 into pContextA["animation count"] +end DG2_EditModeLeaveDrawCallbackStart + +on DG2_EditModeLeaveDrawCallback @pContextA, pControl, pLineNo, @pControlRect, @pControlTopLeft + local tRight + put item 3 of pControlRect into tRight + + -- We will be sliding the row to the right to hide the action select control. + -- Extend the right of the row's rect to ensure that now blank space is present + -- on the right hand side as a result of the animation. + -- Therefore we need to extend the row control's left the accomodate the action control. + -- standard drawing loop will be effected also. + local tActionSelectControl + put DG2_CustomisableControlsGetEditModeActionSelectControlForControl(the long id of pControl) into tActionSelectControl + if tActionSelectControl is not empty then + add the width of tActionSelectControl to item 3 of pControlRect + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(pControl, "left", item 1 of pControlRect, item 1 of pControlRect - the width of tActionSelectControl, the dgAnimationProp["EditModeEnterExitDuration"] of me, the dgAnimationProp["EditModeEnterExitActionSelectControlControlEasing"] of me) into pContextA["animations"][pContextA["animation count"]] + end if + + -- Fade out the reorder control. + local tReorderControl + put DG2_CustomisableControlsGetEditModeReorderControlForControl(the long id of pControl) into tReorderControl + if tReorderControl is not empty then + set the right of tReorderControl to tRight + set the visible of tReorderControl to true + set the blendLevel of tReorderControl to 0 + + -- Continually setting the left of the reorder control during the animation ensures + -- that it is always in the same position (at the right hand side of the list) and + -- thus not effected by the control sliding out to the right (which would naturally + -- move the roerder control left). + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(tReorderControl, "left", the left of tReorderControl, the left of tReorderControl, the dgAnimationProp["EditModeEnterExitDuration"] of me, "linear") into pContextA["animations"][pContextA["animation count"]] + add 1 to pContextA["animation count"] + + put DG2_AnimationsAnimationCreate(tReorderControl, "blendLevel", 0, 100, the dgAnimationProp["EditModeEnterExitDuration"] of me, the dgAnimationProp["EditModeEnterExitReorderControlEasing"] of me) into pContextA["animations"][pContextA["animation count"]] + end if + + -- If the controls are cached, "LayoutControl" won't be called by the standard draw loop. + -- But we need it to be called to reposition everying inside the row to take account of + -- any edit mode controls, so do dispatch "LayoutControl" here. + if the dgProps["cache controls"] of me then + set the rect of pControl to pControlRect + dispatch "LayoutControl" to pControl with pControlRect, DG2_GetWorkingRectOfControlFromControlRect(pControl, pControlRect) + end if +end DG2_EditModeLeaveDrawCallback + +on DG2_EditModeLeaveDrawCallbackEnd @pContextA + -- Queue all the animations and add an end callback to the final animation. + -- The end callback will tidy everything up. + if pContextA["animation count"] is not 0 then + DG2_AnimationsAnimationSetCompletionMessage pContextA["animations"][pContextA["animation count"]], "DG2_EditModeAnimateComplete" + DG2_AnimationsAnimationSetMessageTarget pContextA["animations"][pContextA["animation count"]], the long id of me + DG2_AnimationsBatchAddWithArray pContextA["animations"] + else + send "DG2_EditModeAnimateComplete" to me in 0 seconds + end if +end DG2_EditModeLeaveDrawCallbackEnd + +on DG2_EditModeAnimateComplete + -- Force a redraw after edit mode enter/exit. This will resize the rows correctly + -- reseting any bounds extending that has occured as a result of the slide in animation. + -- If the controls aren't cached, we can use _RedrawList, which is slightly quicker than + -- RefreshList. + if the dgProps["cache controls"] of me then + RefreshList + else + _RedrawList + end if +end DG2_EditModeAnimateComplete + +-------------------------------------------------------------------------------- +-- DataGrid 2 Reorder Handlers + +command DG2_ReorderStart + if not sEditMode then + return "Can only reorder in edit mode" + end if + if sReorderInProgress then + return "Reorder already in progress" + end if + + local tControl + put the the dgDataControl of the target into tControl + if tControl is empty or not (there is a tControl) then + return "Could not find control to reorder" + end if + + local tIndex + put the dgIndex of tControl into tIndex + if tIndex is empty then + return "Could not find index of control" + end if + + local tLine + put the dgLineOfIndex[tIndex] of me into tLine + if tLine is empty then + return "Could not find line of control" + end if + + -- Make sure any scroller doesn't interfere with drag reorders. + __DisableMobileScroller + + put tControl into sReorderControl + put tIndex into sReorderStartIndex + put tLine into sReorderStartLine + put tLine into sReorderLastHoverLine + put true into sReorderInProgress + + -- Bring the control we want to reorder to the front and apply an effect to it. + lock screen + relayer tControl to front of owner + set the blendLevel of tControl to 30 + set the outerGlow["color"] of tControl to kReorderDragControlGlowColor + set the outerGlow["size"] of tControl to kReorderDragControlGlowSize + set the outerGlow["spread"] of tControl to kReorderDragControlGlowSpread + unlock screen + + -- ScrollPoll checks to see if the mouse is at the top or bottom of the list + -- and adjusts the scroll accodingly. + send "DG2_ReorderScrollPoll" to me in 0 seconds + + -- Check for mouse moves. We do this manually rather than using mouse move + -- as mouse move for a couple of reasons: + -- Mouse move is sent to regularly, which can cometimes mean handling it + -- interferes with animations. Polling like this acts as the equivelant of + -- throttling mouse move. + -- Also, widgets don't pass mouse move, so need to post it directly. This + -- message can sometimes not get posted until the vent loop is cleared, + -- meaning it can be held up behind any pending animations. + send "DG2_ReorderMove" to me in 0 seconds + + -- Tell the user a reorder has started. + dispatch DG2_GetMessageNameForTag("EditModeReorderStarted") to me with sReorderStartIndex, sReorderStartLine + + return empty +end DG2_ReorderStart + +command DG2_ReorderMove pNewMouseH, pNewMouseV + cancel sReorderMoveMsgId + + if not sReorderInProgress then + return "No reorder currently in progress" + end if + + if sReorderMouseMoveInProgress then + return empty + end if + + if the mouse is not "down" then + return empty + end if + + put true into sReorderMouseMoveInProgress + + if pNewMouseV is empty then + put item 2 of the mouseLoc into pNewMouseV + end if + + -- Don't extend the reorder beyond the rect of the DataGrid! + if pNewMouseV < the top of group "dgListMask" of me then + put the top of group "dgListMask" of me into pNewMouseV + else if pNewMouseV > bottom of group "dgListMask" of me then + put the bottom of group "dgListMask" of me into pNewMouseV + end if + + local tHoverLine + put DG2_VerticalLocToLineNo(pNewMouseV) into tHoverLine + put max(tHoverLine, 1) into tHoverLine + put min(tHoverLine, the dgNumberOfLines of me) into tHoverLine + + -- If the mouse is over a new line. + -- This means we need to reorder. + if sReorderLastHoverLine is not tHoverLine then + local tMouseMoveDirection + if sReorderLastHoverLine > tHoverLine then + put 1 into tMouseMoveDirection + else if sReorderLastHoverLine < tHoverLine then + put -1 into tMouseMoveDirection + end if + + local tLineToMove + put tHoverLine into tLineToMove + + local tAnimationsA, tAnimationID + put 1 into tAnimationID + + -- It's possible the mouse has moved over several controls since the last reorder. + -- Make sure we animate each of those controls to their new position resulting from the reorder. + repeat while tLineToMove is not sReorderLastHoverLine + local tControlToMove + put the dgDataControlOfLine[tLineToMove] of me into tControlToMove + if tControlToMove is empty or there is not a tControlToMove then + next repeat + end if + + put DG2_AnimationsAnimationCreate(tControlToMove, "top", the top of tControlToMove, DG2_TopOfControlWithLineNo(tLineToMove + tMouseMoveDirection), the dgAnimationProp["ReorderAnimationDuration"] of me, the dgAnimationProp["ReorderAnimationEasing"] of me) into tAnimationsA[tAnimationID] + add 1 to tAnimationID + + add tMouseMoveDirection to tLineToMove + end repeat + + DG2_AnimationsBatchAddWithArray tAnimationsA + + -- Update the DataGrid's internal sequence to take account of the reorder. + SetLineOfIndex the dgIndexOfLine[sReorderLastHoverLine] of me, tHoverLine + + put tHoverLine into sReorderLastHoverLine + end if + + -- Make sure the control we're reordering is always tracking the mouse. + set the loc of sReorderControl to item 1 of the loc sReorderControl, pNewMouseV + + send "DG2_ReorderMove" to me in sReorderMovePollRate milliseconds + put the result into sReorderMoveMsgId + + put false into sReorderMouseMoveInProgress + + return empty +end DG2_ReorderMove + +command DG2_ReorderEnd + if not sReorderInProgress then + return "No reorder currently in progress" + end if + + __EnableMobileScroller + + -- Animate the control we are reordering into its new slot. + DG2_AnimationsAdd sReorderControl, "top", the top of sReorderControl, DG2_TopOfControlWithLineNo(sReorderLastHoverLine) + 1, the dgAnimationProp["ReorderHomingDuration"] of me, the dgAnimationProp["ReorderHomingEasing"] of me, "DG2_ReorderControlHomed", empty, the long id of me + put false into sReorderInProgress + + -- Tell the user the reorder has completed. + dispatch DG2_GetMessageNameForTag("EditModeReorderCompleted") to me with sReorderStartIndex, sReorderStartLine, sReorderLastHoverLine + + return empty +end DG2_ReorderEnd + +on DG2_ReorderControlHomed + -- Once the control is in its new slot, remove any effects and redraw the + -- list to tidy everything up. + set the blendLevel of sReorderControl to 0 + set the outerGlow of sReorderControl to empty + put empty into sReorderControl + _RedrawList +end DG2_ReorderControlHomed + +on DG2_ReorderScrollPoll + cancel sReorderScrollPollMsgID + + if not sReorderInProgress then + put empty into sReorderScrollPollMsgID + exit DG2_ReorderScrollPoll + end if + + local tMaxVScroll + put the dgFormattedHeight of me - the height of group "dgList" of me into tMaxVScroll + + -- If the mouse is sitting at the top of the list, scroll the list up. + -- If the mouse is sitting at teh bottom of the list, scroll the list down. + -- This allows users to scroll the list while reordering. + if item 2 of the mouseLoc - the top of me <= kReorderScrollPollMargin and the dgVScroll of me >= 0 then + set the dgVScroll of me to max(the dgVScroll of me - kReorderScollPollIncrement, 0) + else if the bottom of me - item 2 of the mouseLoc <= kReorderScrollPollMargin and the dgVScroll of me <= tMaxVScroll then + set the dgVScroll of me to min(the dgVScroll of me + kReorderScollPollIncrement, tMaxVScroll) + end if + + send "DG2_ReorderScrollPoll" to me in kReorderScrollPollRate milliseconds + put the result into sReorderScrollPollMsgID +end DG2_ReorderScrollPoll + +-------------------------------------------------------------------------------- +-- DataGrid 2 Delete Animation Handlers + +command DG2_DeleteIndex pIndex + set the wholeMatches to true + if pIndex is not among the items of the dgIndexes of me then + return "Unknown index" && pIndex + end if + + -- Store the vscroll before the delete. We want to preserve this. + local tVScroll + put the dgVScroll of me into tVScroll + + local tOffset + put itemOffset(pIndex, sHilitedIndexes) into tOffset + if tOffset > 0 then + delete item tOffset of sHilitedIndexes + end if + + if the dgProps["cache controls"] of me then + if there is a sControlOfIndexA[pIndex] then + put lineOffset(sControlOfIndexA[pIndex], sTableObjectsA["all row controls"]) into tOffset + if tOffset > 0 then + delete line tOffset of sTableObjectsA["all row controls"] + subtract 1 from sTableObjectsA["row control count"] + end if + + put lineOffset(sControlOfIndexA[pIndex], sTableObjectsA["visible row controls"]) into tOffset + if tOffset > 0 then + delete line tOffset of sTableObjectsA["visible row controls"] + end if + + delete sControlOfIndexA[pIndex] + end if + end if + + local tControlHeight + if the dgProps["fixed row height"] of me then + put sControlHeights into tControlHeight + else + put sControlHeights[pIndex] into tControlHeight + end if + + if sFormattedHeight is not empty then + subtract tControlHeight from sFormattedHeight + end if + + put itemOffset(pIndex, sIndexSequencing) into tOffset + if tOffset > 0 then + delete item tOffset of sIndexSequencing + end if + + local tLineNo + put tOffSet into tLineNo + + delete local sDataArray[pIndex] + _StorePersistentData + + lock screen + + -- Hide any swipe and action controls that are present for the current row. + local tActionControlHolder + put DG2_EditModeActionControlHolderGet() into tActionControlHolder + if tActionControlHolder is not empty and the visible of tActionControlHolder and the dgActionControlRowIndex of tActionControlHolder is pIndex then + set the visible of tActionControlHolder to false + set the dgActionControlRowIndex of tActionControlHolder to empty + end if + + local tSwipeControlHolder + put DG2_SwipeControlHolderGet() into tSwipeControlHolder + if tSwipeControlHolder is not empty and the visible of tSwipeControlHolder and the dgSwipeControlRowIndex of tSwipeControlHolder is pIndex then + set the visible of tSwipeControlHolder to false + set the dgSwipeControlRowIndex of tSwipeControlHolder to empty + end if + + if sFormattedHeight is not empty then + _ConfigureScrollbar + _AutoHideVScrollbar + end if + + -- Redraw the list. + if the keys of sDataArray is not empty then + -- If there is a line number then this indicated we've found a control so + -- we need to animate the delete. + if tLineNo > 0 then + -- Decide the direction of the animation. + -- If there is enough scroll space above the deleted line, then pull in + -- the controls from above. i.e. animate all controls before the + -- deleted row downward. + -- Otherwise animate the controls up from below. + -- + -- Setting the vScroll here lays the controls out as they should be + -- after the delete, ensuring all layout claculations are correct. This + -- also sets the vScroll of the list group which we need to use to + -- offset the y values of our animations. + local tCallbackContextA + if tVScroll >= tControlHeight then + set the dgVScroll of me to tVScroll - tControlHeight + put "above" into tCallbackContextA["animate from direction"] + else + set the dgVScroll of me to tVScroll + put "below" into tCallbackContextA["animate from direction"] + end if + + put tControlHeight into tCallbackContextA["deleted line height"] + put tLineNo into tCallbackContextA["deleted line no"] + put pIndex into tCallbackContextA["deleted line index"] + put -1 * the vScroll of group "dgList" of me into tCallbackContextA["v scroll offset"] + + -- Use the draw loop callbacks to animate the delete. + _DrawListWithProperties sTableObjectsA["base sequence for visible controls"], the vScroll of group "dgList" of me, true, "DG2_DeleteIndexDrawCallback", tCallbackContextA + else + _DrawAlternatingRows + _RedrawList + end if + else + _ResetData + end if + + unlock screen + + return empty +end DG2_DeleteIndex + +on DG2_DeleteIndexDrawCallbackStart @pContextA, @pTopLeft + put empty into pContextA["animations"] + put 0 into pContextA["animation count"] + + -- If we're pulling in the controls from above, then we want to start animating immediately. + -- Flag this to the draw callback by setting the animate flag of the context. + -- We also need to offset the initial top value the draw loop uses to take into account that + -- all the controls above the deleted line will be animated downward. + if pContextA["animate from direction"] is "above" then + put true into pContextA["animate"] + subtract pContextA["deleted line height"] from item 2 of pTopLeft + put pContextA["deleted line height"] into pContextA["animation increment"] + else + put false into pContextA["animate"] + put -1 * pContextA["deleted line height"] into pContextA["animation increment"] + end if +end DG2_DeleteIndexDrawCallbackStart + +on DG2_DeleteIndexDrawCallback @pContextA, pControl, pLineNo, @pControlRect, @pControlTopLeft + -- We've reached the line number of the deleted control. + -- If we were already animating, then stop (i.e. stop pulling controls down from above). + -- If we are not animating, then start (i.e. start pulling up controls from below). + -- All controls following this point need to be shifted down, so set the rect and top accordingly. + -- i.e. if we've been pulling controls from above, the top will have been initially offset to take + -- the animation into account. Undo this offset. If we're pulling up from below, the controls will + -- need to be moved down to take into account the animate up. + if pLineNo is pContextA["deleted line no"] then + put not pContextA["animate"] into pContextA["animate"] + add pContextA["deleted line height"] to item 2 of pControlTopLeft + put item 1 of pControlRect, item 2 of pControlRect + pContextA["deleted line height"], item 3 of pControlRect, item 4 of pControlRect + pContextA["deleted line height"] into pControlRect + end if + + -- Animate the control either up or down, based on pContextA["animation increment"]. + -- We need to take into account the scroll offset of the list. This is how the DataGrid partially + -- shows/hides rows at the top and bottom. + if pContextA["animate"] then + add 1 to pContextA["animation count"] + put DG2_AnimationsAnimationCreate(pControl, "top", item 2 of pControlTopLeft + pContextA["v scroll offset"], item 2 of pControlTopLeft + pContextA["animation increment"] + pContextA["v scroll offset"], the dgAnimationProp["DeleteIndexAnimationDuration"] of me, the dgAnimationProp["DeleteIndexAnimationEasing"] of me) into pContextA["animations"][pContextA["animation count"]] + end if +end DG2_DeleteIndexDrawCallback + +on DG2_DeleteIndexDrawCallbackEnd @pContextA + -- Tidy up at the end of the delete animation. + if pContextA["animation count"] is not 0 then + DG2_AnimationsAnimationSetCompletionMessage pContextA["animations"][pContextA["animation count"]], "DG2_DeleteIndexAnimateComplete" + DG2_AnimationsAnimationSetMessageTarget pContextA["animations"][pContextA["animation count"]], the long id of me + DG2_AnimationsBatchAddWithArray pContextA["animations"] + else + send "DG2_DeleteIndexAnimateComplete" to me in 0 seconds + end if +end DG2_DeleteIndexDrawCallbackEnd + +on DG2_DeleteIndexAnimateComplete + lock screen + _DrawAlternatingRows + _RedrawList + unlock screen +end DG2_DeleteIndexAnimateComplete + +-------------------------------------------------------------------------------- +-- DataGrid 2 Control Holder Handlers + +private function DG2_SwipeControlHolderGet + -- Create a group to house the swipe control and catch any messages. + -- When swipe buttons are visible, they take over the whole DataGrid. + if there is a group "dgList" of me then + if there is no group "DG2 Swipe Control Holder" of group "dgList" of me then + lock screen + + local tRect + put the rect of group "dgListMask" of me into tRect + + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + lock messages + + reset the templateGroup + create invisible group "DG2 Swipe Control Holder" in group "dgList" of me + set the margins of it to 0 + set the dgControl of it to the dgControl of me + set the behavior of it to the long ID of button "Swipe Control Holder" of group "Behaviors" of stack _ResourceStack() + + reset the templateGraphic + create graphic "Message Catcher" in it + set the rect of it to tRect + set the style of it to "rectangle" + set the linesize of it to 0 + set the opaque of it to true + set the blendLevel of it to 100 + + set the lockMessages to tMsgsAreLocked + unlock screen + end if + + return the long id of group "DG2 Swipe Control Holder" of group "dgList" of me + end if + + return empty +end DG2_SwipeControlHolderGet + +-- Called after scrolling the list. +private command DG2_SwipeControlHolderReposition + local tControlHolder + put DG2_SwipeControlHolderGet() into tControlHolder + if tControlHolder is empty or there is not a tControlHolder then + return empty + end if + + if the visible of tControlHolder then + set the rect of tControlHolder to the rect of group "dgList" of me + dispatch "DG2_SwipeControlHolderReposition" to tControlHolder + return the result + end if + + return empty +end DG2_SwipeControlHolderReposition + +private function DG2_EditModeActionControlHolderGet + -- Create a group to house the action control and catch any messages. + -- When the action control is visible, it takes over the whole DataGrid. + if there is a group "dgList" of me then + if there is no group "DG2 Edit Mode Action Control Holder" of group "dgList" of me then + lock screen + + local tRect + put the rect of group "dgListMask" of me into tRect + + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + lock messages + + reset the templateGroup + create invisible group "DG2 Edit Mode Action Control Holder" in group "dgList" of me + set the margins of it to 0 + set the dgControl of it to the dgControl of me + set the behavior of it to the long ID of button "Action Control Holder" of group "Behaviors" of stack _ResourceStack() + + reset the templateGraphic + create graphic "message catcher" in it + set the rect of it to tRect + set the style of it to "rectangle" + set the linesize of it to 0 + set the opaque of it to true + set the blendLevel of it to 100 + + set the lockMessages to tMsgsAreLocked + unlock screen + end if + + return the long id of group "DG2 Edit Mode Action Control Holder" of group "dgList" of me + end if + + return empty +end DG2_EditModeActionControlHolderGet + +-- Called after scrolling the list. +private command DG2_EditModeActionControlHolderReposition + if not sEditMode then + return empty + end if + + local tControlHolder + put DG2_EditModeActionControlHolderGet() into tControlHolder + if tControlHolder is empty or there is not a tControlHolder then + return empty + end if + + if the visible of tControlHolder then + set the rect of tControlHolder to the rect of group "dgList" of me + dispatch "DG2_EditModeActionControlHolderReposition" to tControlHolder + return the result + end if + + return empty +end DG2_EditModeActionControlHolderReposition + +-------------------------------------------------------------------------------- +-- DataGrid 2 Customisable Controls Handlers +-- +-- Customisable controls refer to the swipe, action, action select and reorder +-- controls: The set of controls that can be specified by the user. +-- We have default implementations of the controls which can be overidden by +-- setting the dgProps or handling the appropriate messages. +-- The following handlers take care of cloning and managing the controls appropriately. + +private command DG2_CustomisableControlsInit + local tPropertyNames + get the customProperties["dgProps"] of me + put the keys of it into tPropertyNames + + lock screen + repeat for each item tControlName in kCustomisableControlNames + -- Get the default implemetation of the control by calling the appropriate funciton. + -- e.g. DG2_CustomisableControlsGetDefaultEditModeActionSelectControl() + local tFunctionName + put tControlName into tFunctionName + replace space with empty in tFunctionName + put "DG2_CustomisableControlsGetDefault" before tFunctionName + + local tControl + dispatch function tFunctionName to me + put the result into tControl + if it is not "handled" then + return "Unable to create default for control" && tControlName + end if + + if tControl is not empty and there is a tControl then + -- Use the default control if: A property hasn't already been set for this control type, + -- or one has been set but the control no longer exists. + if tControlName is not among lines of tPropertyNames or (the dgProps[tControlName] of me is not empty and there is not a (the dgProps[tControlName] of me)) then + set the dgProps[tControlName] of me to the long id tControl + end if + end if + end repeat + unlock screen + + put true into sCustomisableControlsInitialised + + return empty +end DG2_CustomisableControlsInit + +-- Returns the id of the customisable control of the given name for the given row. +private function DG2_CustomisableControlsGetForControlByName pRowControl, pControlName + if not sCustomisableControlsInitialised then + DG2_CustomisableControlsInit + end if + + set the wholeMatches to true + if pControlName is not among the items of kCustomisableControlNames then + return empty + end if + + -- If we haven't already fetched the given control for the row. + if sCustomisableControlsA[pRowControl][pControlName] is not an array then + -- Singleton controls are controls of which we only requre one per DataGrid - not one per row. + local tIsSingleton + put pControlName is among the items of kCustomisableControlSingletons into tIsSingleton + + -- Attempt to find the control to use. First of all send a message to the row. (e.g. + -- GetEditModeReorderControl) + -- If this message is handled, then use the control returend. If not, use the control specified + -- in the dgProps. + local tMessage + put pControlName into tMessage + replace space with empty in tMessage + put "Get" before tMessage + + local tControl + dispatch tMessage to pRowControl + if it is "handled" then + put the result into tControl + else + put the dgProps[pControlName] of me into tControl + end if + + -- Set up the data array for the control + if tControl is not empty and there is a tControl then + local tControlA + put the long id of tControl into tControlA["original"] + put tIsSingleton into tControlA["singleton"] + + -- Check to see if the control we've found is the default implementation. + -- This is needed for tidying up later. + local tFunctionName + put pControlName into tFunctionName + replace space with empty in tFunctionName + put "DG2_CustomisableControlsGetDefault" before tFunctionName + dispatch function tFunctionName to me + put the long id of the result is the long id of tControl into tControlA["default"] + + -- If this is a singleton control and we've already got a version of it present, then use that version. + if tIsSingleton and sCustomisableControlsSingletonCopyMapA[tControlA["original"]] is not empty and there is sCustomisableControlsSingletonCopyMapA[tControlA["original"]] then + put sCustomisableControlsSingletonCopyMapA[tControlA["original"]] into tControl + else + -- Otherwise we need to potentially copy the control to the datagrid. + -- Singleton controls need to be copied to the DataGrid itself. + -- Per row controls need tobe copied into the row. + local tParent + if tIsSingleton then + put the long id of me into tParent + else + put the long id of pRowControl into tParent + end if + + -- Only copy if the control is not already present in the target. + -- i.e. the control is part of the row template. + if not (the long id of tControl contains tParent) then + lock screen + copy tControl to tParent + set the visible of it to false + unlock screen + put it into tControl + end if + + -- Store the control in the list of singletons so that it can be reused. + if tIsSingleton then + put the long id of tControl into sCustomisableControlsSingletonCopyMapA[tControlA["original"]] + if not tControlA["default"] then + put the long id of tControl into sCustomisableControlsSingletonsA[the long id of tControl] + end if + end if + end if + + put the long id of tControl into tControlA["id"] + put tControlA into sCustomisableControlsA[pRowControl][pControlName] + else + put empty into sCustomisableControlsA[pRowControl][pControlName]["id"] + end if + end if + + return sCustomisableControlsA[pRowControl][pControlName]["id"] +end DG2_CustomisableControlsGetForControlByName + +function DG2_CustomisableControlsGetEditModeReorderControlForControl pControl + return DG2_CustomisableControlsGetForControlByName(pControl, "edit mode reorder control") +end DG2_CustomisableControlsGetEditModeReorderControlForControl + +function DG2_CustomisableControlsGetEditModeActionSelectControlForControl pControl + return DG2_CustomisableControlsGetForControlByName(pControl, "edit mode action select control") +end DG2_CustomisableControlsGetEditModeActionSelectControlForControl + +function DG2_CustomisableControlsGetEditModeActionControlForControl pControl + return DG2_CustomisableControlsGetForControlByName(pControl, "edit mode action control") +end DG2_CustomisableControlsGetEditModeActionControlForControl + +function DG2_CustomisableControlsGetLeftSwipeControlForControl pControl + return DG2_CustomisableControlsGetForControlByName(pControl, "left swipe control") +end DG2_CustomisableControlsGetLeftSwipeControlForControl + +function DG2_CustomisableControlsGetRightSwipeControlForControl pControl + return DG2_CustomisableControlsGetForControlByName(pControl, "right swipe control") +end DG2_CustomisableControlsGetRightSwipeControlForControl + +private command DG2_CustomisableControlsClear + repeat for each element tControlA in sCustomisableControlsA + repeat for each element tCustomisableControlA in tControlA + if tCustomisableControlA["id"] is not empty and there is a tCustomisableControlA["id"] then + -- Force remove every control we have made a copy of. + if not tCustomisableControlA["original"] is not tCustomisableControlA["id"] then + delete tCustomisableControlA["id"] + end if + end if + end repeat + end repeat + + put empty into sCustomisableControlsA + DG2_CustomisableControlsClearSingletons + return the result +end DG2_CustomisableControlsClear + +private command DG2_CustomisableControlsClearForControlByName pRowControl, pControlName + -- Control doesn't exist - just tidy up the cache. + if sCustomisableControlsA[pRowControl][pControlName]["id"] is empty or there is no sCustomisableControlsA[pRowControl][pControlName]["id"] then + delete variable sCustomisableControlsA[pRowControl][pControlName] + return empty + end if + + -- If it is a default control, the we want keep the control around for future reuse. + if sCustomisableControlsA[pRowControl][pControlName]["default"] then + set the visible of sCustomisableControlsA[pRowControl][pControlName]["id"] to false + delete variable sCustomisableControlsA[pRowControl][pControlName] + return empty + end if + + -- Keep singletons around - other rows might be using them. + -- Delete all other controls. + if not sCustomisableControlsA[pRowControl][pControlName]["singleton"] and sCustomisableControlsA[pRowControl][pControlName]["original"] is not sCustomisableControlsA[pRowControl][pControlName]["id"] then + delete sCustomisableControlsA[pRowControl][pControlName]["id"] + else + set the visible of sCustomisableControlsA[pRowControl][pControlName]["id"] to false + end if + delete variable sCustomisableControlsA[pRowControl][pControlName] + + return empty +end DG2_CustomisableControlsClearForControlByName + +command DG2_CustomisableControlsClearForControl pRowControl + repeat for each key tControlName in sCustomisableControlsA[pRowControl] + DG2_CustomisableControlsClearForControlByName pRowControl, tControlName + end repeat + + return empty +end DG2_CustomisableControlsClearForControl + +private command DG2_CustomisableControlsClearByName pControlName + repeat for each key tRowControl in sCustomisableControlsA + DG2_CustomisableControlsClearForControlByName tRowControl, pControlName + end repeat + + return empty +end DG2_CustomisableControlsClearByName + +private command DG2_CustomisableControlsClearSingletons + repeat for each element tControl in sCustomisableControlsSingletonsA + if there is a tControl then + delete tControl + end if + end repeat + + put empty into sCustomisableControlsSingletonCopyMapA + put empty into sCustomisableControlsSingletonsA + + return empty +end DG2_CustomisableControlsClearSingletons + +-------------------------------------------------------------------------------- +-- DataGrid 2 Default Customisable Control Implentations +-- +-- The default implementations will be created in the template stack (if they +-- don't already exist). + +function DG2_CustomisableControlsGetDefaultEditModeReorderControl + if there is not a group "DG2 Default Edit Mode Reorder Control"of _TemplateControl() then + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + unlock messages + + reset the templateGroup + create invisible group "DG2 Default Edit Mode Reorder Control" in _TemplateControl() + set the margins of it to kEditModeReorderControlMargins + set the layerMode of it to "dynamic" + + create widget as "com.livecode.widget.svgpath" in it + set the iconPresetName of it to kEditModeReorderControlIcon + set the width of it to kEditModeReorderControlWidth + set the foregroundColor of it to kEditModeReorderControlColor + + set the lockMessages to tMsgsAreLocked + end if + + return the long id of group "DG2 Default Edit Mode Reorder Control" of _TemplateControl() +end DG2_CustomisableControlsGetDefaultEditModeReorderControl + +function DG2_CustomisableControlsGetDefaultEditModeActionSelectControl + if there is not a group "DG2 Default Edit Mode Action Select Control" of _TemplateControl() then + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + unlock messages + + reset the templateGroup + create invisible group "DG2 Default Edit Mode Action Select Control" in _TemplateControl() + set the margins of it to kEditModeActionSelectControlMargins + set the layerMode of it to "dynamic" + + create widget as "com.livecode.widget.svgpath" in it + set the iconPresetName of it to kEditModeActionSelectControlIcon + set the width of it to kEditModeActionSelectControlWidth + set the foregroundColor of it to kEditModeActionSelectControlIconColor + + set the lockMessages to tMsgsAreLocked + end if + + return the long id of group "DG2 Default Edit Mode Action Select Control" of _TemplateControl() +end DG2_CustomisableControlsGetDefaultEditModeActionSelectControl + +function DG2_CustomisableControlsGetDefaultEditModeActionControl + if there is not a group "DG2 Default Action Control" of _TemplateControl() then + local tHeight + put the dgProps["row height"] of me into tHeight + + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + unlock messages + + reset the templateGroup + create invisible group "DG2 Default Action Control" in _TemplateControl() + set the margins of it to 0 + set the layerMode of it to "dynamic" + + reset the templateButton + create button "DG2 Default Action Control" in it + set the style of it to "opaque" + set the label of it to kEditModeActionControlText + set the autoHilite of it to false + set the foregroundColor of it to kEditModeActionControlTextColor + set the backgroundColor of it to kEditModeActionControlBGColor + set the width of it to kEditModeActionControlWidth + set the height of it to tHeight + set the margins of it to 0 + + set the lockMessages to tMsgsAreLocked + end if + + return the long id of group "DG2 Default Action Control" of _TemplateControl() +end DG2_CustomisableControlsGetDefaultEditModeActionControl + +private function DG2_CustomisableControlsGetDefaultSwipeControl pName + if there is not a group pName of _TemplateControl() then + local tHeight + put the dgProps["row height"] of me into tHeight + + local tMsgsAreLocked + put the lockMessages into tMsgsAreLocked + unlock messages + + local tGroup + reset the templateGroup + create invisible group pName in _TemplateControl() + set the margins of it to 0 + set the layerMode of it to "dynamic" + put it into tGroup + + reset the templateGraphic + create graphic in tGroup + set the style of it to "rectangle" + set the width of it to kSwipeControlWidth + set the height of it to tHeight + set the linesize of it to 0 + set the opaque of it to true + set the backgroundColor of it to kSwipeControlBGColor + + create widget as "com.livecode.widget.svgpath" in tGroup + set the iconPresetName of it to kSwipeControlIcon + set the width of it to kSwipeControlIconWidth + set the foregroundColor of it to kSwipeControlIconColor + + set the lockMessages to tMsgsAreLocked + end if + + return the long id of group pName of _TemplateControl() +end DG2_CustomisableControlsGetDefaultSwipeControl + +function DG2_CustomisableControlsGetDefaultLeftSwipeControl + return DG2_CustomisableControlsGetDefaultSwipeControl("DG2 Default Left Swipe Control") +end DG2_CustomisableControlsGetDefaultLeftSwipeControl + +function DG2_CustomisableControlsGetDefaultRightSwipeControl + return DG2_CustomisableControlsGetDefaultSwipeControl("DG2 Default Right Swipe Control") +end DG2_CustomisableControlsGetDefaultRightSwipeControl + +private command DG2_CustomisableControlsResizeDefaults + if not sCustomisableControlsInitialised then + DG2_CustomisableControlsInit + end if + + -- The singleton controls need to be resized to take into account the line height. + lock screen + repeat for each item tControlName in kCustomisableControlSingletons + local tFunctionName + put tControlName into tFunctionName + replace space with empty in tFunctionName + put "DG2_CustomisableControlsGetDefault" before tFunctionName + + local tControl + dispatch function tFunctionName to me + put the result into tControl + + if tControl is not empty and there is a tControl then + -- Assume the first control in the group is the background. + -- All other controls should be centered. + repeat with tControlNo = 1 to the number of controls in tControl + if tControlNo is 1 then + set the height of control tControlNo of tControl to the dgProps["row height"] of me + else + set the loc of control tControlNo of tControl to the loc of tControl + end if + end repeat + end if + end repeat + unlock screen + + return empty +end DG2_CustomisableControlsResizeDefaults + +-------------------------------------------------------------------------------- +-- DataGrid 2 Animation Handlers +-- +-- All animations have the following properties +-- +-- pControl - The control to animate. +-- pProperty - The property to effect (e.g. top, width etc). +-- pStartValue - The start value of the poperty. +-- pEndValue - The end value of the property. +-- pDuration - The duration of the animation +-- pEasing - The easing function to use for the animation. Default to "linear". +-- pCompleteMsg - The message to send on completion of the animation. +-- pStepMsg - The message to send after each redraw. +-- pMsgTarget - The control to send the messages to. Defaults to the control we are animating. +-- +-- The redrawing occurs in handler "DG2_AnimationsPulse", which executes every +-- kAnimationsPulseRate milliseconds, while there are amnimations to handle. + +setProp dgAnimationProp[pTag] pValue + if pTag is not among the lines of the keys of sAnimationProps then + return "Unknown animation property" && pTag + end if + + put pValue into sAnimationProps[pTag] + return empty +end dgAnimationProp + +getProp dgAnimationProp[pTag] + return sAnimationProps[pTag] +end dgAnimationProp + +private command DG2_AnimationsInitProps + put kEditModeEnterExitDuration into sAnimationProps["EditModeEnterExitDuration"] + put kEditModeEnterExitActionSelectControlControlEasing into sAnimationProps["EditModeEnterExitActionSelectControlControlEasing"] + put kEditModeEnterExitReorderControlEasing into sAnimationProps["EditModeEnterExitReorderControlEasing"] + put kEditModeActionControlAnimationDuration into sAnimationProps["EditModeActionControlAnimationDuration"] + put kEditModeActionControlAnimationEasing into sAnimationProps["EditModeActionControlAnimationEasing"] + put kReorderAnimationDuration into sAnimationProps[ "ReorderAnimationDuration"] + put kReorderAnimationEasing into sAnimationProps["ReorderAnimationEasing"] + put kReorderHomingDuration into sAnimationProps["ReorderHomingDuration"] + put kReorderHomingEasing into sAnimationProps["kReorderHomingEasing"] + put kDeleteIndexAnimationDuration into sAnimationProps["DeleteIndexAnimationDuration"] + put kDeleteIndexAnimationEasing into sAnimationProps["DeleteIndexAnimationEasing"] + put kSwipeCompleteDuration into sAnimationProps["SwipeCompleteDuration"] + put kSwipeCompleteEasing into sAnimationProps["SwipeCompleteEasing"] + put kSwipeReturnDuration into sAnimationProps["SwipeReturnDuration"] + put kSwipeReturnEasing into sAnimationProps["SwipeReturnEasing"] + + return empty +end DG2_AnimationsInitProps + +function DG2_AnimationsAnimationCreate pControl, pProperty, pStartValue, pEndValue, pDuration, pEasing, pCompleteMsg, pStepMsg, pMsgTarget + local tAnimationA + put pControl into tAnimationA["control"] + put pProperty into tAnimationA["property"] + put pStartValue into tAnimationA["start"] + put pEndValue into tAnimationA["end"] + put pDuration into tAnimationA["duration"] + put pEasing into tAnimationA["easing"] + put pCompleteMsg into tAnimationA["completion message"] + put pStepMsg into tAnimationA["step message"] + if pMsgTarget is not empty then + put pMsgTarget into tAnimationA["message target"] + else + put pControl into tAnimationA["message target"] + end if + return tAnimationA +end DG2_AnimationsAnimationCreate + +command DG2_AnimationsAnimationSetControl @self, pControl + put pControl into self["control"] +end DG2_AnimationsAnimationSetControl + +command DG2_AnimationsAnimationSetProperty @self, pProperty + put pProperty into self["property"] +end DG2_AnimationsAnimationSetProperty + +command DG2_AnimationsAnimationSetStart @self, pStart + put pStart into self["start"] +end DG2_AnimationsAnimationSetStart + +command DG2_AnimationsAnimationSetEnd @self, pEnd + put pEnd into self["end"] +end DG2_AnimationsAnimationSetEnd + +command DG2_AnimationsAnimationSetDuration @self, pDuration + put pDuration into self["duration"] +end DG2_AnimationsAnimationSetDuration + +command DG2_AnimationsAnimationSetEasing @self, pEasing + put pEasing into self["easing"] +end DG2_AnimationsAnimationSetEasing + +command DG2_AnimationsAnimationSetCompletionMessage @self, pMsg + put pMsg into self["completion message"] +end DG2_AnimationsAnimationSetCompletionMessage + +command DG2_AnimationsAnimationSetStepMessage @self, pMsg + put pMsg into self["step message"] +end DG2_AnimationsAnimationSetStepMessage + +command DG2_AnimationsAnimationSetMessageTarget @self, pMsgTarget + put pMsgTarget into self["message target"] +end DG2_AnimationsAnimationSetMessageTarget + +command DG2_AnimationsAdd pControl, pProperty, pStartValue, pEndValue, pDuration, pEasing, pCompleteMsg, pStepMsg, pMsgTarget + local tAnimationA + put DG2_AnimationsAnimationCreate(pControl, pProperty, pStartValue, pEndValue, pDuration, pEasing, pCompleteMsg, pStepMsg, pMsgTarget) into tAnimationA + DG2_AnimationsAddWithArray tAnimationA + return the result +end DG2_AnimationsAdd + +command DG2_AnimationsAddWithArray pAnimationA + -- If animations are off, just set the property to the end value. + if not the dgProps["animate actions"] of me then + DG2_AnimationsFinaliseAnimation pAnimationA + return empty + end if + + put pAnimationA["end"] - pAnimationA["start"] into pAnimationA["change"] + put the milliseconds into pAnimationA["time"] + + put (sAnimationsLastID + 1) mod 1000 into sAnimationsLastID + put sAnimationsLastID into pAnimationA["id"] + put pAnimationA into sAnimationsA[sAnimationsLastID] + + if sAnimationsPulseMsgID is empty then + send "DG2_AnimationsPulse" to me in 0 seconds + put the result into sAnimationsPulseMsgID + end if + + return pAnimationA["id"] +end DG2_AnimationsAddWithArray + +command DG2_AnimationsBatchAddWithArray pAnimationsA + local tTime + put the milliseconds into tTime + + local tIDs + + repeat for each element tAnimationA in pAnimationsA + -- If animations are off, just set the property to the end value. + if not the dgProps["animate actions"] of me then + DG2_AnimationsFinaliseAnimation tAnimationA + next repeat + end if + + put tAnimationA["end"] - tAnimationA["start"] into tAnimationA["change"] + put tTime into tAnimationA["time"] + + put (sAnimationsLastID + 1) mod 1000 into sAnimationsLastID + put sAnimationsLastID into tAnimationA["id"] + put tAnimationA into sAnimationsA[sAnimationsLastID] + + if tIDs is not empty then + put comma after tIDs + end if + put sAnimationsLastID after tIDs + end repeat + + if not the dgProps["animate actions"] of me then + return empty + end if + + if sAnimationsPulseMsgID is empty then + send "DG2_AnimationsPulse" to me in 0 seconds + put the result into sAnimationsPulseMsgID + end if + + return tIDs +end DG2_AnimationsBatchAddWithArray + +function DG2_AnimationsGetPendingCount + if sAnimationsA is empty or sAnimationsA is not an array then + return 0 + else + return the number of lines in the keys of sAnimationsA + end if +end DG2_AnimationsGetPendingCount + +-- Set all current animations to their end value. +command DG2_AnimationsFinaliseAll + cancel sAnimationsPulseMsgID + repeat for each element tAnimationA in sAnimationsA + DG2_AnimationsFinaliseAnimation tAnimationA + end repeat + put empty into sAnimationsA + + return empty +end DG2_AnimationsFinaliseAll + +-- Stop all current animaitions, leaving the controls as they are. +command DG2_AnimationsStopAll + cancel sAnimationsPulseMsgID + put empty into sAnimationsA + return empty +end DG2_AnimationsStopAll + +command DG2_AnimationsFinaliseAnimationByID pAnimationID + local tAnimationA + put sAnimationsA[pAnimationID] into tAnimationA + if tAnimationA is an array then + DG2_AnimationsFinaliseAnimation tAnimationA + end if + return empty +end DG2_AnimationsFinaliseAnimationByID + +command DG2_AnimationsFinaliseStopByID pAnimationID + delete variable sAnimationsA[pAnimationID] + return empty +end DG2_AnimationsFinaliseStopByID + +private command DG2_AnimationsFinaliseAnimation pAnimationA + DG2_AnimationsSetPropertyOfControl pAnimationA["control"], pAnimationA["property"], pAnimationA["end"] + if pAnimationA["completion message"] is not empty then + send pAnimationA["completion message"] && pAnimationA["property"] & comma & pAnimationA["end"] to pAnimationA["message target"] in 0 seconds + end if + + if pAnimationA["id"] is not empty then + delete variable sAnimationsA[pAnimationA["id"]] + end if + + return empty +end DG2_AnimationsFinaliseAnimation + +private command DG2_AnimationsSetPropertyOfControl pControl, pProperty, pValue + switch pProperty + case "top" + set the top of pControl to pValue + break + case "left" + set the left of pControl to pValue + break + case "bottom" + set the bottom of pControl to pValue + break + case "right" + set the right of pControl to pValue + break + case "width" + set the width of pControl to pValue + break + case "heaight" + set the height of pControl to pValue + break + case "blendLevel" + set the blendLevel of pControl to pValue + break + end switch +end DG2_AnimationsSetPropertyOfControl + +on DG2_AnimationsPulse + cancel sAnimationsPulseMsgID + + local tCurrentTime + put the milliseconds into tCurrentTime + + lock screen + repeat for each element tAnimationA in sAnimationsA + if (the milliseconds - tAnimationA["time"]) >= tAnimationA["duration"] then + DG2_AnimationsFinaliseAnimation tAnimationA + else + switch tAnimationA["easing"] + case "in" + get _easeIn(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "out" + get _easeOut(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in out" + get _easeInOut(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in elastic" + get _easeInElastic(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "out elastic" + get _easeOutElastic(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in out elastic" + get _easeInOutElastic(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in bounce" + get _easeInBounce(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "out bounce" + get _easeOutBounce(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in out bounce" + get _easeInOutBounce(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in back" + get _easeInBack(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "out back" + get _easeOutBack(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in out back" + get _easeInOutBack(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "in back cubic" + get _easeInBackCubic(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "out back cubic" + get _easeOutBackCubic(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + case "linear" + default + get _easeLinear(tCurrentTime - tAnimationA["time"], tAnimationA["start"], tAnimationA["change"], tAnimationA["duration"]) + break + end switch + + DG2_AnimationsSetPropertyOfControl tAnimationA["control"], tAnimationA["property"], it + + if tAnimationA["step message"] is not empty then + send tAnimationA["step message"] && tAnimationA["property]"] & comma & it to tAnimationA["message target"] in 0 seconds + end if + end if + end repeat + unlock screen + + if sAnimationsA is not empty then + -- Redraw every kAnimationsPulseRate milliseconds. + -- Make sure we take into account how long this handler took when determing when next to redraw. + send "DG2_AnimationsPulse" to me in (kAnimationsPulseRate - (the milliseconds - tCurrentTime)) milliseconds + put the result into sAnimationsPulseMsgID + else + put empty into sAnimationsPulseMsgID + end if +end DG2_AnimationsPulse + +-------------------------------------------------------------------------------- +-- Easing functions - based on Robert Penner's easing functions. +-- http://robertpenner.com/easing/ + +private function _easeLinear t, b, c, d + return c * t / d + b +end _easeLinear + +private function _easeIn t, b, c, d + put t / d into t + return c * t * t + b +end _easeIn + +private function _easeOut t, b, c, d + put t / d into t + return -c * t * (t - 2) + b +end _easeOut + +private function _easeInOut t, b, c, d + put t / (d / 2) into t + if t < 1 then + return c / 2 * t * t + b + end if + subtract 1 from t + return -c / 2 * (t * (t - 2) - 1) + b +end _easeInOut + +private function _easeInElastic t, b, c, d + put t / d into t + if t is 1 then + return b + c + end if + + local p, s + put d * 0.3 into p + put p / 4 into s + + put t - 1 into t + return -(c * 2 ^ (10 * t) * sin((t * d - s) * (2 * PI) / p)) + b +end _easeInElastic + +private function _easeOutElastic t, b, c, d + put t / d into t + if t is 1 then + return b + c + end if + + local p, s + put d * 0.3 into p + put p / 4 into s + + return (c * (2 ^ (-10 * t)) * sin((t * d - s) * (2 * PI) / p) + c + b); +end _easeOutElastic + +private function _easeInOutElastic t, b, c, d + if t < (d / 2) then + return _easeOutElastic(t * 2, b, c / 2, d) + else + return _easeInElastic((t * 2) - d, b + c / 2, c / 2, d); + end if +end _easeInOutElastic + +private function _easeInBounce t, b, c, d + return c - _easeOutBounce(d - t, 0, c, d) + b +end _easeInBounce + +private function _easeOutBounce t, b, c, d + put t /d into t + if t < (1 / 2.75) then + return c * (7.5625 * t * t) + b + else if t < (2 / 2.75) then + put t - (1.5 / 2.75) into t + return c * (7.5625 * t * t + 0.75) + b + else if t < (2.5 / 2.75) then + put t - (2.25 / 2.75) into t + return c * (7.5625 * t * t + 0.9375) + b + else + put t - (2.625 / 2.75) into t + return c * (7.5625 * t * t + 0.984375) + b + end if +end _easeOutBounce + +private function _easeInOutBounce t, b, c, d + if t < (d / 2) then + return _easeInBounce(t * 2, 0, c, d) * 0.5 + b + else + return _easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b + end if +end _easeInOutBounce + +private function _easeInBack t, b, c, d + put t / d into t + return c * t * t * ((1.70158 + 1) * t - 1.70158) + b +end _easeInBack + +private function _easeOutBack t, b, c, d + put t / d into t + return c * ((t - 1) * t * ((1.70158 + 1) * t + 1.70158) + 1) + b +end _easeOutBack + +private function _easeInOutBack t, b, c, d + local s + put 1.70158 * 1.525 into s + put t / d into t + if (t / 2) < 1 then + return c / 2 * (t * t * ((s + 1) * t - s)) + b + else + put t - 2 into t + return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b + end if +end _easeInOutBack + +private function _easeInBackCubic t, b, c, d + put t / d into t + return b + c * (4 * t * t* t + -3 * t * t) +end _easeInBackCubic + +private function _easeOutBackCubic t, b, c, d + put t / d into t + return b + c * ( 4 * t * t * t + -9 * t * t + 6 * t) +end _easeOutBackCubic + +-------------------------------------------------------------------------------- +-- These handler convert vertical locations to and from line numbers. +-- This assumes the DataGrid is using rows of fixed height. + +private function DG2_MiddleOfControlWithLineNo pLineNo + return __topOfControlWithLineNo(pLineNo) + the dgProps["row height"] of me / 2 +end DG2_MiddleOfControlWithLineNo + +private function DG2_TopOfControlWithLineNo pLineNo + return (the top of group "dgListMask" of me + (pLineNo - 1) * the dgProps["row height"] of me) - the dgVScroll of me +end DG2_TopOfControlWithLineNo + +private function DG2_BottomOfControlWithLineNo pLineNo + return (the top of group "dgListMask" of me + (pLineNo) * the dgProps["row height"] of me) - the dgVScroll of me +end DG2_BottomOfControlWithLineNo + +private function DG2_LocOfControlWithLineNo pLineNo + return (item 1 of the loc of me, __middleOfControlWithLineNo(pLineNo)) +end DG2_LocOfControlWithLineNo + +private function DG2_VerticalLocToLineNo pPosV + return ceil((pPosV + the dgVScroll of me - the top of group "dgListMask" of me) / the dgProps["row height"] of me) +end DG2_verticalLocToLineNo + +-------------------------------------------------------------------------------- + +-- A row controls working rect takes into account any controls visible as part of +-- edit mode. i.e. it is reduced on the left hand side by the action select +-- control and on the right hand side by the reorder control. +private function DG2_GetWorkingRectOfControlFromControlRect pControl, pControlRect + if sEditMode then + local tActionSelectControl + put DG2_CustomisableControlsGetEditModeActionSelectControlForControl(the long id of pControl) into tActionSelectControl + if tActionSelectControl is not empty then + add the width of tActionSelectControl to item 1 of pControlRect + end if + + local tReorderControl + put DG2_CustomisableControlsGetEditModeReorderControlForControl(the long id of pControl) into tReorderControl + if tReorderControl is not empty then + subtract the width of tReorderControl from item 3 of pControlRect + end if + end if + + return pControlRect +end DG2_GetWorkingRectOfControlFromControlRect diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsdefaultcolumnbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsdefaultcolumnbuttonbehavior.livecodescript new file mode 100644 index 0000000000..eed383b15a --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsdefaultcolumnbuttonbehavior.livecodescript @@ -0,0 +1,60 @@ +script "RevDataGridLibraryBehaviorsDefaultColumnButtonBehavior" +--> all handlers + +on FillInData pData + -- This message is sent when the Data Grid needs to populate + -- this template with the column data. pData is the value to be displayed. + set the text of the long ID of me to pData ## temp workaround for +end FillInData + + +on LayoutControl pControlRect + -- A default column is just a field. Nothing to change here. +end LayoutControl + + +on ResetData + -- Sent when column data is being emptied because the control is no longer being used to display data + set the text me to empty +end ResetData + + +on PreFillInData + -- Sent right before new data is going to replace existing data in the column +end PreFillInData + + +setprop dgHilite pBoolean + -- This custom property is set when the highlight of your column template has + -- changed. You only add script here if you want to customize the highlight. + if pBoolean then + set the foregroundColor of me to the dgProp["hilited text color"] of the dgControl of me + else + set the foregroundColor of me to empty + end if +end dgHilite + + +getprop dgDataControl + -- Required by library so that it can locate the control. + return the long ID of me +end dgDataControl + + +-- Data grid will call this if a user action asks to edit cell content. +command EditValue + EditFieldText the long ID of me, the dgIndex of me, the dgColumn of me +end EditValue + + +on mouseDoubleUp pMouseBtnNum + if pMouseBtnNum is 1 then + if the dgProps["allow editing"] of the dgControl of me \ + and the dgColumnIsEditable[the dgColumn of me] of the dgControl of me then + -- Edit field contents if the user double-clicks + EditCellOfIndex the dgColumn of me, the dgIndex of me + exit mouseDoubleUp + end if + end if + pass mouseDoubleUp +end mouseDoubleUp diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsdefaultheaderbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsdefaultheaderbuttonbehavior.livecodescript new file mode 100644 index 0000000000..157aaa2ada --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsdefaultheaderbuttonbehavior.livecodescript @@ -0,0 +1,109 @@ +script "RevDataGridLibraryBehaviorsDefaultHeaderButtonBehavior" +--> all handlers + + +on LayoutControl pControlRect + -- Position all of the controls within the header + put the loc of me into theLoc + set the margins of field 1 of me to the dgProps["header margins"] of the dgControl of me + set the rect of graphic "Background" of me to pControlRect + set the rect of field 1 of me to pControlRect + set the left of graphic "LeftHilite" of me to item 1 of pControlRect + set the right of graphic "RightHilite" of me to item 3 of pControlRect + + -- Position field and sort arrow + put the width of button "SortArrow" of me into theArrowWidth + set the loc of button "SortArrow" of me to item 3 of pControlRect - (round(theArrowWidth / 2) + 5), item 2 of the loc of me + add 5 to theArrowWidth + if the textAlign of field 1 of me is "center" then + set the rect of field 1 of me to item 1 of pControlRect, item 2 of pControlRect, \ + item 1 of pControlRect + ( (item 3 of pControlRect - item 1 of pControlRect) - (theArrowWidth * 2) ), \ + item 4 of pControlRect + set the loc of field 1 of me to theLoc + else + if the visible of button "SortArrow" of me then + set the rect of field 1 of me to item 1 of pControlRect, item 2 of pControlRect, \ + item 1 of pControlRect + ( (item 3 of pControlRect - item 1 of pControlRect) - theArrowWidth ), \ + item 4 of pControlRect + else + set the rect of field 1 of me to item 1 of pControlRect, item 2 of pControlRect, \ + item 1 of pControlRect + ( (item 3 of pControlRect - item 1 of pControlRect) ), \ + item 4 of pControlRect + end if + end if +end LayoutControl + + +setprop dgHilite pBoolean + set the visible of button "SortArrow" of me to pBoolean + set the visible of graphic "Background" of me to pBoolean + if pBoolean then + if the dgColumnSortDirection[the short name of me] of the dgControl of me is "ascending" then + ## Ascending + set the icon of button "SortArrow" of me to the dgProps["ascending sort icon"] of the dgControl of me + else + ## Descending + set the icon of button "SortArrow" of me to the dgProps["descending sort icon"] of the dgControl of me + end if + end if +end dgHilite + + +getprop dgColumn + return the short name of me +end dgColumn + + +getprop dgHeaderControl + return the long ID of me +end dgHeaderControl + + +setprop dgLabel [pEncoding] pValue + switch pEncoding ## Added in 1.0.2 build 11 + case "mac" + if the platform is not "macos" then + put mactoiso(pValue) into pValue + end if + break + case "iso" + if the platform is "macos" then + put isotomac(pValue) into pValue + end if + break + default + end switch + + set the text of field 1 of me to pValue +end dgLabel + + +setprop dgTooltip pValue + set the toolTip of field 1 of me to pValue +end dgTooltip + + +setprop dgAlignment pValue + set the textAlign of field 1 of me to pValue +end dgAlignment + + +-- on mouseDown pMouseBtnNum + -- ## _HeaderMouseDown resides in parent group script. It will return true if click triggers a column resize. + -- ## Otherwise it returns false. + -- _HeaderMouseDown pMouseBtnNum + + -- pass mouseDown +-- end mouseDown + + +on mouseUp pMouseBtnNum + if pMouseBtnNum is 1 and not the dgHeaderColumnIsBeingResized of the dgHeader of me then + ## Change the sort of the column + ## _HeaderToggleSortOfColumn is a helper that resizes in the parent group script. + ## It toggles the sort of the column based on current state of column. + _HeaderToggleSortOfColumn the dgColumn of me + end if + + pass mouseUp +end mouseUp diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsdglistmessagecatcherbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsdglistmessagecatcherbuttonbehavior.livecodescript new file mode 100644 index 0000000000..f05e17a0ac --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsdglistmessagecatcherbuttonbehavior.livecodescript @@ -0,0 +1,32 @@ +script "RevDataGridLibraryBehaviorsDgListMessageCatcherButtonBehavior" +-- Catch messages sent to instances of templates +-- This insulates the outside world from these internal messages +on FillInData + +end FillInData + + +on PreFillInData + +end PreFillInData + + +on ResetData + +end ResetData + + +on LayoutControl + +end LayoutControl + + +setprop dgHilite + +end dgHilite + + +getprop dgDataControl + +end dgDataControl + diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsdropindicatorbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsdropindicatorbuttonbehavior.livecodescript new file mode 100644 index 0000000000..136042f32a --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsdropindicatorbuttonbehavior.livecodescript @@ -0,0 +1,13 @@ +script "RevDataGridLibraryBehaviorsDropIndicatorButtonBehavior" +--> all handlers + +on resizeControl + if the target is not me then pass resizeControl + + put the rect of group "dgListMask" of the dgControl of me into theParentRect + set the topLeft of me to item 1 to 2 of theParentRect + + put the rect of graphic 2 of me into theRect + put item 3 of theParentRect + 1 into item 3 of theRect ## +1 is because lines don't really fill up entire rect + set the rect of graphic 2 of me to theRect +end resizeControl diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsfieldeditorbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsfieldeditorbuttonbehavior.livecodescript new file mode 100644 index 0000000000..a60563bbec --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsfieldeditorbuttonbehavior.livecodescript @@ -0,0 +1,51 @@ +script "RevDataGridLibraryBehaviorsFieldEditorButtonBehavior" +--> all handlers + + +on escapeKey + send "DeleteFieldEditor false" to the dgControl of me in 0 seconds +end escapeKey + + +on closeField + ## Don't delete editor within same message + send "DeleteFieldEditor" to the dgControl of me in 0 seconds +end closeField + + +on exitField + send "DeleteFieldEditor" to the dgControl of me in 0 seconds +end exitField + + +on returnInField + if the autotab of me then + send "DeleteFieldEditor" to the dgControl of me in 0 seconds + else + pass returnInField + end if +end returnInField + + +on enterInField + if the autotab of me then + send "DeleteFieldEditor" to the dgControl of me in 0 seconds + else + pass enterInField + end if +end enterInField + + +on tabKey + if the autotab of me then + send "DeleteFieldEditorAndOpenNext" to the dgControl of me in 0 seconds + else + pass tabkey + end if +end tabKey + + +on selectionChanged + ## don't pass as selectionChanged is reserved for group + ## developer can override behavior to process selectionChanged +end selectionChanged diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsheaderbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsheaderbuttonbehavior.livecodescript new file mode 100644 index 0000000000..f83eb3c15b --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsheaderbuttonbehavior.livecodescript @@ -0,0 +1,190 @@ +script "RevDataGridLibraryBehaviorsHeaderButtonBehavior" +--> all handlers + +local sTargetColumn +local sResizing +local sClickHOffset +local sClickHOrigin +local sLastMouseH +local sRunningActions +local sTargetHeaderGroup + + +getprop dgHeader + return the long id of me +end dgHeader + + +getprop dgHeaderColumnIsBeingResized + return sResizing is true +end dgHeaderColumnIsBeingResized + + +on mouseMove pMouseH,pMouseV + if sResizing then + _UpdateCursor + + put empty into theError + if sRunningActions["resizing column"] then exit mouseMove + try + put the dgColumnWidth[sTargetColumn] of the dgControl of me into theWidth + put the dgColumnMinWidth[sTargetColumn] of the dgControl of me into theMinWidth + put the dgColumnMaxWidth[sTargetColumn] of the dgControl of me into theMaxWidth + put the rect of sTargetHeaderGroup into theMaskRect + + if theWidth is theMinWidth and pMouseH > item 3 of theMaskRect or \ + theWidth is theMaxWidth and pMouseH < item 3 of theMaskRect or \ + (theWidth is not theMinWidth and theWidth is not theMaxWidth) then + put true into sRunningActions["resizing column"] + if pMouseH > sLastMouseH then + put abs(pMouseH - sLastMouseH) into theChange + else + put abs(pMouseH - sLastMouseH) * -1 into theChange + end if + + add theChange to theWidth + set the dgColumnWidth[sTargetColumn] of the dgControl of me to theWidth + end if + catch e + put e into theError + put false into sResizing + end try + + put pMouseH into sLastMouseH + + put false into sRunningActions["resizing column"] + if theError is not empty then + throw theError + end if + + else if the dgProp["allow column resizing"] of the dgControl of me then + _SeeIfPointerIsOverDraggableRegion pMouseH, pMouseV + end if +end mouseMove + + +on mouseLeave + get the mouseloc + put item 1 of it into theMouseH + put item 2 of it into theMouseV + + ## Look for mouseLeaving header group + if the dgProp["allow column resizing"] of the dgControl of me then + send "_SeeIfPointerIsOverDraggableRegion theMouseH, theMouseV" to me in 0 seconds + end if +end mouseLeave + + +command _SeeIfPointerIsOverDraggableRegion pMouseH, pMouseV + put empty into sTargetColumn + put 0 into theLeftColNum + if the mousecontrol is not empty and pMouseH,pMouseV is within the rect of me then + put the dgHeaderControl of the mousecontrol into theTarget + + if theTarget is not empty then + put the dgControl of me into theDataGroup + put the dgColumnNumber of the mousecontrol into theColNum + put the dgProps["visible columns"] of theDataGroup into theColumns + put the number of lines of theColumns into theColCount + + put the rect of theTarget into theRect + if theColNum > 1 and pMouseH <= item 1 of theRect + 2 then + ## resize previous column + put theColNum - 1 into theLeftColNum + else if theColNum <= theColCount and pMouseH >= item 3 of theRect - 4 then + ## resize this column + put theColNum into theLeftColNum + end if + + if theLeftColNum > 0 then + put line theLeftColNum of theColumns into sTargetColumn + end if + + ## Determine if column is resizable + if not the dgColumnIsResizable[sTargetColumn] of theDataGroup then put empty into sTargetColumn + + ## Update cursor + if sTargetColumn is not empty then + _UpdateCursor + put _ColumnHeaderGroup(sTargetColumn) into sTargetHeaderGroup + else + set the defaultcursor to arrow + end if + else + set the defaultcursor to arrow + end if + else + set the defaultcursor to arrow + end if +end _SeeIfPointerIsOverDraggableRegion + + +private command _UpdateCursor + local theDataGroup + local theWidth + + put the dgControl of me into theDataGroup + put the dgColumnWidth[sTargetColumn] of theDataGroup into theWidth + if the dgColumnMinWidth[sTargetColumn] of theDataGroup is theWidth then + set the defaultcursor to 103002 + else if the dgColumnMaxWidth[sTargetColumn] of theDataGroup is theWidth then + set the defaultcursor to 103003 + else + set the defaultcursor to 103001 + end if + return empty +end _UpdateCursor + + +command _HeaderToggleSortOfColumn pColumn + put the dgColumnSortDirection[pColumn] of the dgControl of me into theDirection + if the dgProps["sort by column"] of the dgControl of me is pColumn then + if theDirection is "ascending" then put "descending" into theDirection + else put "ascending" into theDirection + + set the dgColumnSortDirection[pColumn] of the dgControl of me to theDirection + else + set the dgProps["sort by column"] of the dgControl of me to pColumn + end if + + return empty +end _HeaderToggleSortOfColumn + + +on mouseDown pMouseBtnNum + _HeaderMouseDown pMouseBtnNum + if not the result then pass mouseDown +end mouseDown + + +command _HeaderMouseDown pMouseBtnNum + if pMouseBtnNum is 1 then + if sTargetColumn is not empty then + put the dgHeaderControl of the mousecontrol into theTarget + put the rect of theTarget into theRect + put the clickh into sClickHOrigin + put sClickHOrigin into sLastMouseH + if sClickHOrigin <= item 1 of theRect + 2 then + put sClickHOrigin - item 1 of theRect into sClickHOffset + else if sClickHOrigin >= item 3 of theRect - 4 then + put sClickHOrigin - item 3 of theRect into sClickHOffset + end if + + put true into sResizing + return true + end if + end if + return false +end _HeaderMouseDown + + +on mouseUp pMouseBtnNum + put false into sResizing + set the defaultcursor to arrow +end mouseUp + + +on mouseRelease pMouseBtnNum + put false into sResizing + set the defaultcursor to arrow +end mouseRelease diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsheadermaskbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsheadermaskbuttonbehavior.livecodescript new file mode 100644 index 0000000000..044903d57e --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsheadermaskbuttonbehavior.livecodescript @@ -0,0 +1,6 @@ +script "RevDataGridLibraryBehaviorsHeaderMaskButtonBehavior" +--> all handlers + +getprop dgHeader + return the long id of group "dgHeader" of me +end dgHeader diff --git a/Toolset/palettes/revdatagridlibrary/behaviorshorizontalscrollbarbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorshorizontalscrollbarbuttonbehavior.livecodescript new file mode 100644 index 0000000000..0e0b219e00 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorshorizontalscrollbarbuttonbehavior.livecodescript @@ -0,0 +1,6 @@ +script "RevDataGridLibraryBehaviorsHorizontalScrollbarButtonBehavior" +--> all handlers + +on dragStart + ## Scrollbars don't need to send dragStart messages +end dragStart diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsrowchainedbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsrowchainedbehavior.livecodescript new file mode 100644 index 0000000000..68c7a6ba69 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsrowchainedbehavior.livecodescript @@ -0,0 +1,371 @@ +script "RevDataGridLibraryBehaviorsRowChainedBehavior" +---------------------------------------------------------------------- +-- This behavior sits at the back of a row's behavior chain and is used to +-- determine and handle edit mode and swipe actions. + +local sPreDragging +local sDragging +local sDragStart +local sDragLocs +local sControlLeft +local sControlRight + +-- A user is seen to be dragging a row if the mouse has moved kPreDragLocDiff +-- points within kPreDragTimeMargin milliseconds of the initial mouse click. +constant kPreDragLocDiff = 15 +constant kPreDragTimeMargin = 100 + +-- A swipe has occured if the mouse has moved kSwipeLocDiff points within +-- kSwipeTimeDiff milliseconds, plus or minus kSwipeTimeDiffMargin. +constant kSwipeTimeDiff = 100 +constant kSwipeTimeDiffMargin = 25 +constant kSwipeLocDiff = 50 + +---------------------------------------------------------------------- + +private command DG2_ClearVars + put false into sPreDragging + put false into sDragging + put empty into sDragStart + put empty into sDragLocs + put empty into sControlLeft + put empty into sControlRight + + DG2_CustomisableControlsClearForControl the long id of me +end DG2_ClearVars + +before PreFillInData + DG2_ClearVars +end PreFillInData + +before ResetData + DG2_ClearVars +end ResetData + +---------------------------------------------------------------------- + +before mouseDown + -- This prevents execution when editing the template stack + if the dgControl of me is empty then + pass mouseDown + end if + + if the dgEditMode of the dgControl of me then + -- If the reorder control has been clicked start a reorder. Exiting to top + -- at this point prevents the mouseDown message being sent to control. + local tReorderControl + put DG2_CustomisableControlsGetEditModeReorderControlForControl(the long id of me) into tReorderControl + if tReorderControl is not empty and the long id of target contains the long id of tReorderControl then + DG2_ReorderStart + exit to top + end if + else + -- Only track swipes if all previous swipe actions have completed - i.e. + -- there are no animations pending. This prevents situations like where a + -- user drags in one direction, but an animation is returning the row in + -- the oposite direction. + if the dgProps["enable swipe"] of the dgControl of me and DG2_AnimationsGetPendingCount() is 0 then + local tStartDrag + put false into tStartDrag + + -- Layer the swipe controls behind the current row so that they reveal + -- on swiping. Don't postion at this point as the left and right + -- controls might be the same object. + local tSwipeControl + put DG2_CustomisableControlsGetLeftSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + relayer tSwipeControl before me + put true into tStartDrag + end if + put DG2_CustomisableControlsGetRightSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + relayer tSwipeControl before me + put true into tStartDrag + end if + + if tStartDrag then + -- We store the start position in sSwipeStart to use as an offset + -- when repositioning the row control under the pointer on drag. + put item 1 of the mouseLoc into sDragStart + put the milliseconds && item 1 of the mouseLoc into sDragLocs + put true into sPreDragging + put false into sDragging + end if + + end if + end if + + pass mouseDown +end mouseDown + +before mouseMove pNewMouseH, pNewMouseV + -- This prevents execution when editing the template stack + if the dgControl of me is empty then + pass mouseMove + end if + + if not the dgEditMode of the dgControl of me then + -- If the user has just clicked (i.e. pre-dragging), attempt to determine + -- if the user is trying to drag the row. We do this by checking if the + -- horizontal position of the drag has changed sufficiently within a given + -- time frame. If so, we can turn the scroller off to prevent any + -- interference and begin tracking the drag. + if sPreDragging then + if abs(word 2 of the last line of sDragLocs - pNewMouseH) > kPreDragLocDiff then + put false into sPreDragging + put true into sDragging + __DisableMobileScroller + else if the milliseconds - word 1 of the last line of sDragLocs > kPreDragTimeMargin then + put false into sPreDragging + else + put the milliseconds && pNewMouseH & return before sDragLocs + end if + end if + + if sDragging then + put the milliseconds && pNewMouseH & return before sDragLocs + + -- Calculate the virtual left and right of the control if it were to + -- track the mouse's new horizontal position. + local tLeft, tRight + put sControlLeft - (sDragStart - pNewMouseH) into tLeft + put tLeft + the width of me into tRight + + -- If as a result of the new mouse position the row will move to + -- the right of its original location, check to see if there is a left + -- swipe control which we can reveal. If so, move the row and reveal + -- the left swipe contol. + -- Do the same for drags to the left. + local tSwipeControl + if tRight > sControlRight then + put DG2_CustomisableControlsGetLeftSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + lock screen + set the visible of tSwipeControl to true + set the rect of tSwipeControl to sControlLeft, the top of me, sControlLeft + the width of tSwipeControl, the bottom of me + set the left of me to min(tLeft, the right of tSwipeControl) + unlock screen + end if + else if tLeft < sControlLeft then + put DG2_CustomisableControlsGetRightSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + lock screen + set the visible of tSwipeControl to true + set the rect of tSwipeControl to sControlRight - the width of tSwipeControl, the top of me, sControlRight, the bottom of me + set the right of me to max(tRight, the left of tSwipeControl) + unlock screen + end if + end if + end if + end if + + pass mouseMove +end mouseMove + +before mouseUp + -- This prevents execution when editing the template control + if the dgControl of me is empty then + pass mouseUp + end if + + if the dgEditMode of the dgControl of me then + DG2_ReorderEnd + + -- If the action select control has been clicked, tell the user (by + -- sending the appropriate message) and exit to top to prevent any further + -- interaction. + local tActionSelectControl + put DG2_CustomisableControlsGetEditModeActionSelectControlForControl(the long id of me) into tActionSelectControl + if tActionSelectControl is not empty then + if the long id of the target contains the long id of tActionSelectControl then + dispatch DG2_GetMessageNameForTag("EditModeActionSelectControlClicked") to me with the target + exit to top + end if + end if + else + put false into sPreDragging + if sDragging then + DG2_DragFinished + end if + end if + + pass mouseUp +end mouseUp + +before mouseRelease + -- This prevents execution when editing the template control + if the dgControl of me is empty then + pass mouseRelease + end if + + if the dgEditMode of the dgControl of me then + DG2_ReorderEnd + else + put false into sPreDragging + if sDragging then + DG2_DragFinished + end if + end if + + pass mouseRelease +end mouseRelease + +---------------------------------------------------------------------- + +before LayoutControl pControlRect, pWorkingRect + local tActionSelectControl, tReorderControl + put DG2_CustomisableControlsGetEditModeActionSelectControlForControl(the long id of me) into tActionSelectControl + put DG2_CustomisableControlsGetEditModeReorderControlForControl(the long id of me) into tReorderControl + + -- If we're in edit mode, position the edit mode controls appropriately. + -- The action select control on the left, reorder on the right. + if the dgEditMode of the dgControl of me then + if tActionSelectControl is not empty then + set the visible tActionSelectControl to true + set the topLeft of tActionSelectControl to item 1 of pControlRect, item 2 of pControlRect + (item 4 of pControlRect - item 2 of pControlRect - the height of tActionSelectControl) / 2 + end if + + if tReorderControl is not empty then + -- We can't rely on the right of the control rect to be the right of + -- the list group: When animating out of edit mode, the control rect + -- can be extended to the right to make room for the animation. So, + -- use the right of the list group to postion the reorder control. + set the visible of tReorderControl to true + set the topRight of tReorderControl to min(item 3 of pControlRect, the right of group "dgList" of the dgControl of me), item 2 of pControlRect + (item 4 of pControlRect - item 2 of pControlRect - the height of tReorderControl) / 2 + end if + else + if tActionSelectControl is not empty then + set the visible tActionSelectControl to false + end if + if tReorderControl is not empty then + set the visible of tReorderControl to false + end if + end if +end LayoutControl + +after LayoutControl pControlRect, pWorkingRect + put the left of me into sControlLeft + put the right of me into sControlRight +end LayoutControl + +---------------------------------------------------------------------- + +private command DG2_DragFinished + __EnableMobileScroller + + -- first check if we are already there + get word 2 of the last line of sDragLocs + local tLocDiff + local tSwipeControl + + put item 1 of the mouseLoc - it into tLocDiff + if tLocDiff > 0 then + put DG2_CustomisableControlsGetLeftSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty and \ + the left of me is the right of tSwipeControl then + put false into sPreDragging + put false into sDragging + put empty into sDragLocs + RowSwipeShowControlForIndexAndSide the dgIndex of me, "left" + return the result + end if + else if tLocDiff < 0 then + put DG2_CustomisableControlsGetRightSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty and \ + the right of me is the left of tSwipeControl then + put false into sPreDragging + put false into sDragging + put empty into sDragLocs + RowSwipeShowControlForIndexAndSide the dgIndex of me, "right" + return the result + end if + end if + + local tNow + put the milliseconds into tNow + + -- Parse the list of swipe locations to find out where we were + -- kSwipeTimeDiff milliseconds ago (or as close as we have to + -- kSwipeTimeDiff milliseconds ago). + local tPrevDragLoc, tMatchedLoc + repeat for each line tDragLoc in sDragLocs + local tTimeDiff + put tNow - word 1 of tDragLoc into tTimeDiff + + if tTimeDiff >= kSwipeTimeDiff then + -- We've found a location that occured after kSwipeTimeDiff. + -- Chose the location which occured closet in time to kSwipeTimeDiff + -- milliseconds ago; the current location or the last location in + -- the list + if tPrevDragLoc is empty or tTimeDiff < (tNow - word 1 of tPrevDragLoc) then + get tDragLoc + else + get tPrevDragLoc + end if + + -- Make sure the location we have chosen occurred within a + -- reasonable margin of kSwipeTimeDiff. + if abs(kSwipeTimeDiff - (tNow - word 1 of it)) <= kSwipeTimeDiffMargin then + put word 2 of it into tMatchedLoc + end if + + exit repeat + end if + + put tDragLoc into tPrevDragLoc + end repeat + + put item 1 of the mouseLoc - tMatchedLoc into tLocDiff + if tMatchedLoc is not empty and abs(tLocDiff) > kSwipeLocDiff then + -- The mouse has moved sufficiently to instantiate a swipe. + -- Determine the direction of the swipe and make sure we are + -- currently showing the appropriate control for that swipe direcion. + if tLocDiff > 0 and the left of me > sControlLeft then + put false into sPreDragging + put false into sDragging + put empty into sDragLocs + RowSwipeShowControlForIndexAndSide the dgIndex of me, "left" + return the result + else if tLocDiff < 0 and the right of me < sControlRight then + put false into sPreDragging + put false into sDragging + put empty into sDragLocs + RowSwipeShowControlForIndexAndSide the dgIndex of me, "right" + return the result + end if + end if + + -- If we've reached this point, no swipe has been detected, so return + -- everything to as it were before dragging. + DG2_SwipeReturn + return the result +end DG2_DragFinished + +command DG2_SwipeReturn pDontAnimate + -- Return everything back to where it was before the dragging started. + put false into sPreDragging + put false into sDragging + put empty into sDragLocs + if pDontAnimate then + set the left of me to sControlLeft + DG2_SwipeReturnComplete + return the result + else + DG2_AnimationsAdd the long id of me, "left", the left of me, sControlLeft, the dgAnimationProp["SwipeReturnDuration"] of the dgControl of me, the dgAnimationProp["SwipeReturnEasing"] of the dgControl of me, "DG2_SwipeReturnComplete" + return empty + end if +end DG2_SwipeReturn + +on DG2_SwipeReturnComplete + local tSwipeControl + put DG2_CustomisableControlsGetLeftSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + set the visible of tSwipeControl to false + end if + put DG2_CustomisableControlsGetRightSwipeControlForControl(the long id of me) into tSwipeControl + if tSwipeControl is not empty then + set the visible of tSwipeControl to false + end if + + return empty +end DG2_SwipeReturnComplete diff --git a/Toolset/palettes/revdatagridlibrary/behaviorstrackdragdropbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorstrackdragdropbuttonbehavior.livecodescript new file mode 100644 index 0000000000..b72dd1174d --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorstrackdragdropbuttonbehavior.livecodescript @@ -0,0 +1,27 @@ +script "RevDataGridLibraryBehaviorsTrackDragDropButtonBehavior" +--> all handlers + +local sDataGridA + +setprop dgTargetControl pValue + put pValue into sDataGridA[the dgControl of the target] + -- put pValue into sDataGrid +end dgTargetControl + + +on dragDrop + send "dgDragDrop" to sDataGridA[the dgControl of the target] + pass dragDrop +end dragDrop + + +on dragEnd + send "dgDragEnd" to sDataGridA[the dgControl of the target] + pass dragEnd +end dragEnd + + +on dragMove pMouseH,pMouseV + send "dgDragMove pMouseH, pMouseV" to sDataGridA[the dgControl of the target] + pass dragMove +end dragMove diff --git a/Toolset/palettes/revdatagridlibrary/behaviorsverticalscrollbarbuttonbehavior.livecodescript b/Toolset/palettes/revdatagridlibrary/behaviorsverticalscrollbarbuttonbehavior.livecodescript new file mode 100644 index 0000000000..3aeca4d479 --- /dev/null +++ b/Toolset/palettes/revdatagridlibrary/behaviorsverticalscrollbarbuttonbehavior.livecodescript @@ -0,0 +1,30 @@ +script "RevDataGridLibraryBehaviorsVerticalScrollbarButtonBehavior" +--> all handlers + +on dragStart + ## Scrollbars don't need to send dragStart messages +end dragStart + + +on mouseDown pBtnNum + if pBtnNum is 1 then + _UserStartedVScrolling + end if + pass mouseDown +end mouseDown + + +command mouseUp pBtnNum + if pBtnNum is 1 then + _UserStoppedVScrolling + end if + pass mouseUp +end mouseUp + + +command mouseRelease pBtnNum + if pBtnNum is 1 then + _UserStoppedVScrolling + end if + pass mouseRelease +end mouseRelease diff --git a/Toolset/palettes/reverrordisplay.livecodescript b/Toolset/palettes/reverrordisplay.livecodescript index cf7578c30a..5d07d5c78e 100644 --- a/Toolset/palettes/reverrordisplay.livecodescript +++ b/Toolset/palettes/reverrordisplay.livecodescript @@ -1,14 +1,11 @@ script "revErrorDisplay" -# AL-2015-07-07: Ensure LCB error code matches that of the engine. -local sLCBErrorCode - on moveStack updateStoredRect end moveStack -on desktopChanged +on ideDesktopChanged revIDEEnsureOnScreen the short name of this stack -end desktopChanged +end ideDesktopChanged on resizeStack revUpdateGeometry @@ -28,12 +25,8 @@ private command updateStoredRect end updateStoredRect # OK-2007-07-02: Bug 5203 -constant kExtensionError = "extension: error occured with domain" on preOpenStack - if sLCBErrorCode is empty then - # AL-2015-07-07: Calculate LCB error code - put lineOffset(kExtensionError, the scriptExecutionErrors) into sLCBErrorCode - end if + revIDESubscribe "ideDesktopChanged" local tStoredRect put revIDEGetPreference("cErrorDisplayRect") into tStoredRect @@ -103,8 +96,14 @@ on openStack end openStack on closeStack - updateStoredRect - pass closeStack + if the enabled of btn "Ignore" of group "errorDisplay" of me then + set the traceAbort to true + set the traceReturn to true + end if + + revIDEUnsubscribeAll + updateStoredRect + pass closeStack end closeStack # OK-2007-11-26 @@ -118,16 +117,6 @@ end revCloseErrorDialogDo local lExit -on closeStack - if the enabled of btn "Ignore" of group "errorDisplay" of me then - set the traceAbort to true - set the traceReturn to true - end if - - # OK-2007-07-02: Bug 5203 - pass closeStack -end closeStack - on returnInField returnKey end returnInField @@ -152,6 +141,7 @@ constant kExternalHandlerError = 634 constant kErrorTextColor = "64,64,64" constant kErrorYellowIconID = 202696 constant kErrorGreyIconID = 202697 +constant kExtensionErrorCode = 863 on preOpenCard global gREVMovingPalette, gREVDevelopment, gRevExit @@ -255,14 +245,13 @@ on preOpenCard if tNumber is kExternalHandlerError then put item 4 to -1 of line 1 of tError after tErrorString else - put revIDELookupError("execution", tNumber) after tErrorString + put revIDELookupError("execution", tError) after tErrorString end if put return after tErrorString else if tScriptError is not empty then put tScriptError into tError - put item 1 of line 1 of tError into tNumber put " " & tab & "compiling at" && the long time & return into tErrorString - put "Type" & tab & revIDELookupError("compilation", tNumber) after tErrorString + put "Type" & tab & revIDELookupError("compilation", tError) after tErrorString put return after tErrorString end if @@ -282,7 +271,7 @@ on preOpenCard exit to top end if - if tNumber is sLCBErrorCode then + if tNumber is kExtensionErrorCode then put "LCB Error" & tab & item 4 to -1 of line 2 of tError into line 2 of tErrorString put "LCB File" & tab & item 4 to -1 of line 3 of tError & cr after tErrorString put "LCB Line" & tab & item 4 to -1 of line 4 of tError after tErrorString @@ -443,9 +432,9 @@ setProp cCurrentObject pWhat local tParsedData repeat for each line l in (line 1 to -2 of pWhat) if tScriptError then - put " " & tab & revIDELookupError("compilation", (item 1 of l)) after tParsedData + put " " & tab & revIDELookupError("compilation", l) after tParsedData else - put "Type" & tab & revIDELookupError("execution", (item 1 of l)) after tParsedData + put "Type" & tab & revIDELookupError("execution", l) after tParsedData end if put return after tParsedData put word 1 to -1 of line (item 2 of l) of the script of tObject & cr after tParsedData @@ -526,7 +515,7 @@ on mouseDoubleUp put the tKey of this stack into tError -- If it is an LCB Error there is no double-click behavior - if item 1 of line 1 of tError is sLCBErrorCode then + if item 1 of line 1 of tError is kExtensionErrorCode then exit mouseDoubleUp end if diff --git a/Toolset/palettes/revextensionbuilder.livecode b/Toolset/palettes/revextensionbuilder.livecode deleted file mode 100644 index fe278369a0..0000000000 Binary files a/Toolset/palettes/revextensionbuilder.livecode and /dev/null differ diff --git a/Toolset/palettes/revfileassociations.livecode b/Toolset/palettes/revfileassociations.livecode index 73681ab18c..d3262531d7 100644 Binary files a/Toolset/palettes/revfileassociations.livecode and b/Toolset/palettes/revfileassociations.livecode differ diff --git a/Toolset/palettes/revicons.rev b/Toolset/palettes/revicons.rev index eb8156a9dd..a51c3def2a 100644 Binary files a/Toolset/palettes/revicons.rev and b/Toolset/palettes/revicons.rev differ diff --git a/Toolset/palettes/revimagelibrary.rev b/Toolset/palettes/revimagelibrary.rev index e66ba1565b..2a366ad71b 100644 Binary files a/Toolset/palettes/revimagelibrary.rev and b/Toolset/palettes/revimagelibrary.rev differ diff --git a/Toolset/palettes/revlauncher.rev b/Toolset/palettes/revlauncher.rev deleted file mode 100644 index f7118c181d..0000000000 Binary files a/Toolset/palettes/revlauncher.rev and /dev/null differ diff --git a/Toolset/palettes/revmenumanager.rev b/Toolset/palettes/revmenumanager.rev index c6edc1e06b..b4d76015a5 100644 Binary files a/Toolset/palettes/revmenumanager.rev and b/Toolset/palettes/revmenumanager.rev differ diff --git a/Toolset/palettes/revonline.rev b/Toolset/palettes/revonline.rev index 78aee299c6..bb6313d0eb 100644 Binary files a/Toolset/palettes/revonline.rev and b/Toolset/palettes/revonline.rev differ diff --git a/Toolset/palettes/revpreferencesgui.rev b/Toolset/palettes/revpreferencesgui.rev index 6174500b0d..85ff47acb6 100644 Binary files a/Toolset/palettes/revpreferencesgui.rev and b/Toolset/palettes/revpreferencesgui.rev differ diff --git a/Toolset/palettes/revresourcecenter.rev b/Toolset/palettes/revresourcecenter.rev index e036a5d72f..2519ec678f 100644 Binary files a/Toolset/palettes/revresourcecenter.rev and b/Toolset/palettes/revresourcecenter.rev differ diff --git a/Toolset/palettes/revsearch.rev b/Toolset/palettes/revsearch.rev index 12d750ce12..eab4149588 100644 Binary files a/Toolset/palettes/revsearch.rev and b/Toolset/palettes/revsearch.rev differ diff --git a/Toolset/palettes/revtemplatechooser.rev b/Toolset/palettes/revtemplatechooser.rev deleted file mode 100644 index 8667d5ebfa..0000000000 Binary files a/Toolset/palettes/revtemplatechooser.rev and /dev/null differ diff --git a/Toolset/palettes/revupdatechecker.rev b/Toolset/palettes/revupdatechecker.rev deleted file mode 100644 index ac60d16d2a..0000000000 Binary files a/Toolset/palettes/revupdatechecker.rev and /dev/null differ diff --git a/Toolset/palettes/script editor/behaviors/revsecommoneditorbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsecommoneditorbehavior.livecodescript new file mode 100644 index 0000000000..f9eca8a84d --- /dev/null +++ b/Toolset/palettes/script editor/behaviors/revsecommoneditorbehavior.livecodescript @@ -0,0 +1,3964 @@ +script "com.livecode.scripteditor.behavior.editorcommon" +local sObjectId + +# The following variables store information used for the undo / redo system. +local sTextOperationOffsets +local sTextOperationNewTexts +local sTextOperationOldTexts +local sTextOperationIndex + +local sTextOperationTop + +local sTextGroupLabels +local sTextGroupLengths +local sTextGroupIndex +local sTextGroupTop +local sTextFormatKeywordMap + +local sTextMark +local sLastSelectedChunk +local sLastNonEmptySelection + +# Stores an array of cached object scripts for switching back to objects with unsaved changes +local sScriptCache + +# OK-2009-01-17 : Bug 7169 - Store whether scripts are "dirty" or not, i.e whether the user has actually +# modified them, as opposed to they were modified by the script editor. (This can happen in the case of template scripts) +local sDirty + +# Stores requests to update the script editor in reponse to a selection changed +local sSelectionUpdateRequest + +# Stores requests to update the script editor panes +local sPaneUpdateRequest + +# Stores the id of the last request to update the gutter, if there is one pending. +local sGutterUpdateRequest + +# We also need to store whether the last update request involved text changing and +# whether it required the compilation errors to be updated. This is because it may be +# cancelled by a subsequent request that didn't require these things, resulting in the update +# being lost. +local sGutterUpdateRequestDetails + +# Stores that an arrowKey is pressed from rawKeyDown +local sArrowKeyPressed + +local sPlaceholders +local sEditChunks +local sEditPlaceholder + +constant kPlaceholderDefaultSearchLines = 20 +constant kPlaceholderDefaultBackgroundColor = "240,240,240" + +# 2017-08-01 bhall2001 previous vScroll position of the Editor field +local sVScroll + +# 2017-08-01 bhall2001 Toggles between true/false on each up arrow key pressed +# Note: up arrow key sends 2 scrollBarDrag messages. Used as flag +# to process only 1 of the messages. +local sSkipUpArrow = false + +# OK-2009-01-17 : Bug 7169 +command setDirty pObject, pValue + put pValue into sDirty[pObject] +end setDirty + +command getDirty pObject + return sDirty[pObject] +end getDirty + +command setObjectID pObjectID + if pObjectID is not empty then + local tRuggedID + put revRuggedId(pObjectID) into tRuggedID + if tRuggedID is not sObjectID then + put tRuggedID into sObjectID + if exists(sObjectId) and \ + revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteIntrospectMessagePath sObjectId + end if + end if + else + put empty into sObjectID + end if + delete variable sPlaceholders + delete variable sEditChunks + delete variable sEditPlaceholder +end setObjectID + +function getObjectID + return sObjectID +end getObjectID + +command updateObjectID pOldObjectID, pNewObjectID + # If there was a previous object and we are changing its id, then we have to update all the script locals + # that may contain references to the old object. This is rather ugly, but it allows things like undo to work + # even when objects are moved. + + # Script cache, stores unapplied scripts when tabs are changed + updateArrayKey sScriptCache, pOldObjectID, pNewObjectID + + # Undo stuff + updateMultiItemArrayKey sTextOperationOffsets, pOldObjectID, pNewObjectID, 44, 1 + updateMultiItemArrayKey sTextOperationOldTexts, pOldObjectID, pNewObjectID, 44, 1 + updateMultiItemArrayKey sTextOperationNewTexts, pOldObjectID, pNewObjectID, 44, 1 + updateArrayKey sTextOperationTop, pOldObjectID, pNewObjectID + updateArrayKey sTextOperationIndex, pOldObjectID, pNewObjectID + + updateMultiItemArrayKey sTextGroupLabels, pOldObjectID, pNewObjectID, 44, 1 + updateMultiItemArrayKey sTextGroupLengths, pOldObjectID, pNewObjectID, 44, 1 + updateArrayKey sTextGroupIndex, pOldObjectID, pNewObjectID + updateArrayKey sTextGroupTop, pOldObjectID, pNewObjectID + updateArrayKey sTextMark, pOldObjectID, pNewObjectID +end updateObjectID + +# Parameters +# pObjectId : reference to the object to set the script to. Must be one of the target objects of the script editor. +# Description +# Clears the script cache for the specified object. This should be called when the object is being closed. The cache also +# includes selection information. +command clearCache pObject, pDontCheckId + local tObject + if pDontCheckId then + put pObject into tObject + else + put revRuggedId(pObject) into tObject + end if + delete variable sScriptCache[tObject] + + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteClearObjectCache tObject + end if +end clearCache + +# Parameters +# pArray : reference to an array. This gets modified +# pOldKey : one of the array keys +# pNewKey : the new key to replace pOldKey with +# Description +# Removes the element pOldKey from the array, and creates +# a new element pNewKey with the same data. Essentially renaming the key. +# If the element is empty, does nothing. +private command updateArrayKey @pArray, pOldKey, pNewKey + local tData + if pArray[pOldKey] is not empty then + put pArray[pOldKey] into tData + delete variable pArray[pOldKey] + put tData into pArray[pNewKey] + end if +end updateArrayKey + +# Parameters +# pArray : reference to an array. This gets modified +# pOldKey : one of the array keys +# pNewKey : the new key to replace pOldKey with +# pDelimiter : an ascii char code that delimits dimensions in the array's key. If empty, comma is assumed. +# pItemNumer : which item number of the key needs to match pOldKey +# Description +# Removes all keys with the specified dimension matching pOldKey from the array +# and replaces them with equivalent keys matching pNewKey. +private command updateMultiItemArrayKey @pArray, pOldKey, pNewKey, pDelimiter, pItemNumber + local tData + + if pDelimiter is not empty then + set the itemDelimiter to numToChar(pDelimiter) + end if + + # Create a list of keys that need to be modified + local tKeys + repeat for each line tKey in the keys of pArray + if item pItemNumber of tKey is pOldKey then + put tKey & return after tKeys + end if + end repeat + delete the last char of tKeys + + if tKeys is empty then + exit updateMultiItemArrayKey + end if + + # Apply the modification to the keys + repeat for each line tKey in tKeys + local tNewKey + put tKey into tNewKey + put pNewKey into item pItemNumber of tNewKey + put pArray[tKey] into pArray[tNewKey] + delete variable pArray[tKey] + end repeat +end updateMultiItemArrayKey + +command textInitialize + put empty into sTextOperationOffsets + put empty into sTextOperationNewTexts + put empty into sTextOperationOldTexts + put 0 into sTextOperationIndex + put 0 into sTextOperationTop + + put empty into sTextGroupLabels + put empty into sTextGroupLengths + put 0 into sTextGroupIndex + put 0 into sTextGroupTop + + put empty into sTextMark + + textFormatInitialize + + textMark "Insert" +end textInitialize + +command getLastSelection + return slastNonEmptySelection +end getLastSelection + +command setLastSelectedChunk pSelection + put pSelection into sLastSelectedChunk +end setLastSelectedChunk + +command getLastSelectedChunk + return sLastSelectedChunk +end getLastSelectedChunk + +command getLastSelectedWord + local tFrom, tTo + put item 1 of sLastSelectedChunk into tFrom + put item 2 of sLastSelectedChunk into tTo + + # If there is a non empty selection, just return that. + if tTo > tFrom then + return char tFrom to tTo of the text of getScriptField() + end if + + # If the selection is in the middle of a word, then return that. + # First loop back from the selected character to find the first part of the word. Keep going until we find a character + # that is either whitespace, or a bracket. + local tWordDivider + put merge("^[\[[quote]]|\[|\]\(|\)|\s]$") into tWordDivider + + local tBefore + repeat with x = tTo down to 1 + get char x of the text of getScriptField() + if matchText(it, tWordDivider) then + exit repeat + end if + put it before tBefore + end repeat + + local tAfter + repeat with x = tTo + 1 to the number of chars of the text of getScriptField() + get char x of the text of getScriptField() + if matchText(it, tWordDivider) then + exit repeat + end if + put it after tAfter + end repeat + + local tWord + put tBefore & tAfter into tWord + return tWord +end getLastSelectedWord + +# Description +# Returns whether or not undo is available in the current object. I.e. the script has been edited since it was opened in this +# instance of the script editor. +command undoAvailable + if sTextGroupIndex[sObjectId] is 0 then + return false + else + return true + end if +end undoAvailable + +# Description +# Returns whether or not redo is available in the current object. I.e. something has been undone since it was opened in +# this instance of the script editor. +command redoAvailable + if sTextGroupIndex[sObjectId] is sTextGroupTop[sObjectId] then + return false + else + return true + end if +end redoAvailable + +on textMark pLabel + put pLabel into sTextMark[sObjectId] +end textMark + +on textBeginGroup pLabel, pObject + local tObject + if pObject is empty then + put sObjectId into tObject + else + put pObject into tObject + end if + + add 1 to sTextGroupIndex[tObject] + + put pLabel into sTextGroupLabels[tObject,sTextGroupIndex[tObject]] + put 0 into sTextGroupLengths[tObject,sTextGroupIndex[tObject]] + + repeat with tIndex = sTextGroupIndex[tObject] + 1 to sTextGroupTop[tObject] + delete variable sTextGroupLabels[tObject,tIndex] + delete variable sTextGroupLengths[tObject,tIndex] + end repeat + + repeat with tIndex = sTextOperationIndex[tObject] + 1 to sTextOperationTop[tObject] + delete variable sTextOperationOffsets[tObject,tIndex] + delete variable sTextOperationNewTexts[tObject,tIndex] + delete variable sTextOperationOldTexts[tObject,tIndex] + end repeat + + put sTextOperationIndex[sObjectId] into sTextOperationTop[tObject] + put sTextGroupIndex[sObjectId] into sTextGroupTop[tObject] + + put empty into sTextMark[tObject] +end textBeginGroup + +on textEndGroup + if sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] = 0 then + throw "empty_text_group_inserted" + end if + textMark "Insert" +end textEndGroup + +private function __GetPreference pPreference, pDefault + try + dispatch function "sePrefGet" to stack "revNewScriptEditor" with pPreference + if the result is not empty then + return the result + end if + end try + + return pDefault +end __GetPreference + +-- Text Formatting Code +command textFormatInitialize + -- permit use in environment with no dependencies + local tTabDepth + put __GetPreference("editor,tabdepth", 3) into tTabDepth + + put "0," & tTabDepth into sTextFormatKeywordMap["try"] + put "0," & tTabDepth into sTextFormatKeywordMap["switch"] + put "0," & tTabDepth into sTextFormatKeywordMap["if"] + put -tTabDepth & ",0" into sTextFormatKeywordMap["endif"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["elseif"] + put "0," & tTabDepth into sTextFormatKeywordMap["repeat"] + + put "0," & tTabDepth into sTextFormatKeywordMap["on"] + put "0," & tTabDepth into sTextFormatKeywordMap["function"] + put "0," & tTabDepth into sTextFormatKeywordMap["setprop"] + put "0," & tTabDepth into sTextFormatKeywordMap["getprop"] + put "0," & tTabDepth into sTextFormatKeywordMap["command"] + put "0," & tTabDepth into sTextFormatKeywordMap["private"] + put "0," & tTabDepth into sTextFormatKeywordMap["before"] + put "0," & tTabDepth into sTextFormatKeywordMap["after"] + + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["else"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["case"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["default"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["catch"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["finally"] + put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["catch"] + --put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["break"] + put 0 & comma & 0 into sTextFormatKeywordMap["break"] + + put -tTabDepth & ",0" into sTextFormatKeywordMap["end"] +end textFormatInitialize + +private function textFormatIndentLineAdds pLine + local tToken + put token 1 of pLine into tToken + if tToken is "if" then + if "else" is among the words of pLine then + return 0 + else if token -1 of pLine is not "then" then + return 0 + else + return item 2 of sTextFormatKeywordMap["if"] + end if + + else if tToken is "else" then + if token 2 of pLine is "if" then + if "else" is among the words of word 3 to -1 of pLine then + return 0 + else if token -1 of pLine is not "then" then + return 0 + else + return item 2 of sTextFormatKeywordMap["elseif"] + end if + else if token 2 of pLine is not empty then + return 0 + else + return item 2 of sTextFormatKeywordMap["else"] + end if + + else if token 1 of pLine is empty then + return 0 + + else if token 1 of pLine is "then" and "else" is among the tokens of pline then + return 0 + + ## Bug 10467 - else in a comment was causing incorrect indentation + ## Check for "else" in line without comments + --else if token 1 of pLine is not "else" and "else" is among the words of pLine then + else if token 1 of pLine is not "else" and "else" is among the words of lineStripComments(pLine) then + -- permit use in environment witn no dependencies + local tTabDepth + put __GetPreference("editor,tabdepth", 3) into tTabDepth + return -tTabDepth + else if token -1 of pLine is "then" then + # Either a weirdly formatted if structure, or the condition of the if contained a line continuation character. + # In this case, behave as though pLine is a normal if. + return item 2 of sTextFormatKeywordMap["if"] + else + return item 2 of sTextFormatKeywordMap[tToken] + end if + return 0 +end textFormatIndentLineAdds + + +private function textFormatIndentLineRemoves pPreviousLine, pLine + local tToken + put token 1 of pLine into tToken + if tToken is "else" then + if token 2 of pLine is "if" then + if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" then + return 0 + else + return item 1 of sTextFormatKeywordMap["elseif"] + end if + + else + + if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" \ + and "else" is among the tokens of pPreviousLine and token 1 of pPreviousLine is "if" and token -1 of pLine is "else" then + return item 1 of sTextFormatKeywordMap["else"] + end if + + if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" \ + and token 1 of pPreviousLine is "if" and token -1 of pLine is "else" then + return 0 + end if + + if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" then + return 0 + else + return item 1 of sTextFormatKeywordMap["else"] + end if + end if + else if tToken is empty then + # Comments and empty lines do not remove any formatting + return 0 + else if tToken is "end" and token 2 of pLine is "switch" and token 1 of pPreviousLine is not "switch" then + # Special case for end switch if there is a preceeding "break", "default" or other statement, we need to remove + # double the normal indent. + return (2 * item 1 of sTextFormatKeywordMap["end"]) + else if tToken is "case" then + # A case statement removes indent from the previous line in all cases except if the + # previous line was the beginning of the parent switch structure. + if token 1 of pPreviousLine is "switch" then + return 0 + else + return item 1 of sTextFormatKeywordMap["case"] + end if + # OK-2009-04-28 : Bug 8016 - Special case required for "default" to make switches format correctly. + else if tToken is "default" then + if token 1 of pPreviousLine is "switch" then + return 0 + else + return item 1 of sTextFormatKeywordMap["default"] + end if + else if tToken is "end" and token 2 of pLine is not among the words of "if switch repeat try" and not lineIsContinued(pLine) then + # Handler ends always remove all indentation as they can't be nested + # OK-2009-02-16 : Bug 7707 - We can't assume the previous line was correctly formatted or script may be deleted. + # Instead we simplify this by simply chopping off whatever indentation it did have. + --return min(-(the number of chars of textFormatGetLineIndent(pPreviousLine)), item 1 of sTextFormatKeywordMap[tToken]) + return item 1 of sTextFormatKeywordMap["end"] + else + # We can't assume that the previous line was correctly indented + # because the script might have been edited from outside this script editor. Therefore + # we have to ensure that a line doesnt try to remove more formating than the previous + # line actually had. Otherwise non-whitespace chars may be deleted. + if the number of chars of textFormatGetLineIndent(pPreviousLine) + the number of chars of textFormatGetLineIndent(pLine) + textFormatIndentLineAdds(pPreviousLine) < abs(item 1 of sTextFormatKeywordMap[tToken]) then + return -(the number of chars of textFormatGetLineIndent(pPreviousLine)) + else + return item 1 of sTextFormatKeywordMap[tToken] + end if + end if +end textFormatIndentLineRemoves + +private function textFormatGetLineIndent pLine + local tResult + repeat for each char tChar in pLine + if tChar is space then + put space after tResult + else + return tResult + end if + end repeat + return tResult +end textFormatGetLineIndent + +-- all chars after a continuation are treated as a comment +-- this will work fine until someone uses format with multiple +-- \"\" but there's not much getting around that +private function lineIsContinued pLine + put lineStripComments(pLine) into pLine + split pLine by quote + repeat with tIndex = 1 to the number of elements of pLine step 2 + if pLine[tIndex] contains "\" then + return true + end if + end repeat + return false +end lineIsContinued + +private function textFormatGetContinuationIndent pLastLineNumber + # In order to calculate the indentation we need to loop back until we find the start of the continuation, + # constructing a string which is the equivalent of the continued line in a single line. We then use this to calculate + # the indent of the last line +end textFormatGetContinuationIndent + +private function combineContinuedLine pLastLineNumber, @pTextLines + local tContinuation + put lineStripComments(pTextLines[pLastLineNumber]) into tContinuation + + local tIndex + repeat with tIndex = (pLastLineNumber - 1) down to 1 + if not lineIsContinued( pTextLines[tIndex]) then + exit repeat + end if + + put lineStripComments(pTextLines[tIndex]) before tContinuation + end repeat + replace "\" with empty in tContinuation + return tContinuation +end combineContinuedLine + +constant kContinuationIndent = 6 + +private function textFormatLine pLine, pTextLines, @xPreviousLine + local tResult + + # OK-2009-01-30 : Bug 7051 - Deal better with continuation characters. + local tCurrentLineIsContinued + local tPreviousLineWasContinued + local tPreviousPreviousLineWasContinued + + # Continuations can only happen with consecutive lines, there can't be comments or empty lines in between, + # so we simply use the two previous lines to work out if they are continued or not. If these lines are empty + # or are comments, then the result will be that they are not continuations anyway which is correct. + put lineIsContinued(pTextLines[pLine - 1]) into tPreviousLineWasContinued + put lineIsContinued(pTextLines[pLine - 2]) into tPreviousPreviousLineWasContinued + + put lineIsContinued(pTextLines[pLine]) into tCurrentLineIsContinued + + # Get the previous non-empty line + if xPreviousLine is 0 and pLine > 1 then + put pLine into xPreviousLine + repeat while xPreviousLine > 1 + subtract 1 from xPreviousLine + if token 1 of pTextLines[xPreviousLine] is not empty then + exit repeat + end if + end repeat + end if + + local tPreviousLine + local tPreviousLineWasCombined = false + if xPreviousLine > 0 then + # This is the case where we have reached the end of a continued line. Here, we treat the continued line + # as a single entity in order to calculate its indentation properties correctly for the line after it. + if lineIsContinued(pTextLines[xPreviousLine - 1]) then + put true into tPreviousLineWasCombined + put combineContinuedLine(xPreviousLine, pTextLines) into tPreviousLine + else + put pTextLines[xPreviousLine] into tPreviousLine + end if + + # Get the current indent of the previous line + local tPreviousLineIndent + put textFormatGetLineIndent(tPreviousLine) into tPreviousLineIndent + end if + + # Get the current indent of the line + local tCurrentLineIndent + put textFormatGetLineIndent(pTextLines[pLine]) into tCurrentLineIndent + + # Work out how much indentation the current line should remove from the previous line + local tIndentCurrentLineRemoves + if tPreviousLineWasContinued then + put 0 into tIndentCurrentLineRemoves + else + put textFormatIndentLineRemoves(tPreviousLine, pTextLines[pLine]) into tIndentCurrentLineRemoves + end if + + # Work out how much indentation the previous line should add to the current line. + local tIndentPreviousLineAdds + if xPreviousLine is 0 then + put 0 into tIndentPreviousLineAdds + else if tPreviousLineWasContinued then + # we always add the continuation indent because we combined the continued lines + put kContinuationIndent into tIndentPreviousLineAdds + else + put textFormatIndentLineAdds(tPreviousLine) into tIndentPreviousLineAdds + end if + + local tCurrentIndent + repeat (the number of chars of tPreviousLineIndent + tIndentCurrentLineRemoves + tIndentPreviousLineAdds) + put space after tCurrentIndent + end repeat + + put ((the number of chars of tPreviousLineIndent + tIndentCurrentLineRemoves + tIndentPreviousLineAdds) - the number of chars of tCurrentLineIndent) into tResult + + -- Finally, calculate the expected next indent. + local tNewIndent + put tCurrentIndent into tNewIndent + + local tIndentCurrentLineAdds + if tCurrentLineIsContinued and tPreviousLineWasContinued then + put 0 into tIndentCurrentLineAdds + else if tCurrentLineIsContinued and (not tPreviousLineWasContinued) then + put kContinuationIndent into tIndentCurrentLineAdds + else if (not tCurrentLineIsContinued) and tPreviousLineWasContinued then + put -kContinuationIndent into tIndentCurrentLineAdds + else + put textFormatIndentLineAdds(pTextLines[pLine]) into tIndentCurrentLineAdds + end if + + if tPreviousLineWasContinued then + local tCombinedLine + put tPreviousLine && pTextLines[pLine] into tCombinedLine + replace "\" with empty in tCombinedLine + add textFormatIndentLineAdds(tCombinedLine) to tIndentCurrentLineAdds + end if + + if tIndentCurrentLineAdds < 0 then + repeat -tIndentCurrentLineAdds times + delete char 1 of tNewIndent + end repeat + else + repeat tIndentCurrentLineAdds times + put space after tNewIndent + end repeat + end if + + put comma & tNewIndent after tResult + + if token 1 of pTextLines[pLine] is not empty then + put pLine into xPreviousLine + end if + return tResult +end textFormatLine + +# Returns +# The chunk of pLine from the beginning of the first word to the end. +private function firstWordToEnd pLine + local tOffset + put offset(word 1 of pLine, pLine) into tOffset + return char tOffset to -1 of pLine +end firstWordToEnd + +# Formats the specified script snippet. +command scriptFormatSnippet pScript + textFormatInitialize + local tNewScript + put textFormatSelection(pScript) into tNewScript + return tNewScript +end scriptFormatSnippet + +# Parameters +# pText : the text to format +private function textFormatSelection pText + local tResult + local tPreviousLine = 0 + local tTextLines + put pText into tTextLines + split tTextLines by return + + get textFormatLine(1, tTextLines, tPreviousLine) + put firstWordToEnd(tTextLines[1]) into tTextLines[1] + put tTextLines[1] into tResult + local tIndex + repeat with tIndex = 2 to the number of elements of tTextLines + put item 2 of it & firstWordToEnd(tTextLines[tIndex]) into tTextLines[tIndex] + get textFormatLine(tIndex, tTextLines, tPreviousLine) + + if item 1 of it < 0 then + repeat -(item 1 of it) times + if char 1 of line -1 of tTextLines[tIndex] is space then + delete char 1 of tTextLines[tIndex] + end if + end repeat + else if item 1 of it > 0 then + repeat item 1 of it times + put space before tTextLines[tIndex] + end repeat + end if + + put return & tTextLines[tIndex] after tResult + end repeat + + if line -1 of pText = "" then put cr after tResult + + return tResult +end textFormatSelection + +private function handlerTypes + return "command,on,function,setprop,getprop,before,after" +end handlerTypes + +private function textFormat pLineNumber, pLineCount, pText + -- Find the range to format. + -- 1. Search down until we find a handler (a) or the end of one (b). + -- 2. Based on 1, in case a, search up until we find the end of any other handler, or the beginning of the script. + -- In case b we need to search for the start of that handler. + local tEnd + + local tText + put pText into tText + split tText by return + put pLineNumber into tEnd + + # Search down to find what the handler name is and whether pLineNumber is the first line of the handler. + local tHandler + local tFirstLine + put true into tFirstLine + + local tContinuation, tCurrentLineContinues + put lineIsContinued(tText[pLineNumber-1]) into tContinuation + + local tLineIndex + repeat with tLineIndex = pLineNumber to the number of elements of tText + put lineIsContinued(tText[tLineIndex]) into tCurrentLineContinues + if token 1 of tText[tLineIndex] is "end" and token 2 of tText[tLineIndex] is not among the items of "if,repeat,switch,try" and not tContinuation and not tCurrentLineContinues then + put true into tHandler[token 2 of tText[tLineIndex]] + if pLineCount < 0 then + exit repeat + end if + else if token 1 of tText[tLineIndex] is among the items of handlerTypes() and not tFirstLine then + if pLineCount < 0 then + exit repeat + end if + exit repeat + else if token 1 of tText[tLineIndex] is "private" and token 2 of tText[tLineIndex] is among the items of handlerTypes() and not tFirstLine then + if pLineCount < 0 then + exit repeat + end if + exit repeat + else + put tCurrentLineContinues into tContinuation + end if + if tFirstLine then put false into tFirstLine + subtract 1 from pLineCount + add 1 to tEnd + end repeat + + # Search up to find the beginning of the handler, or the beginning of the script if not found. + local tStart + repeat with tLineIndex = pLineNumber down to 1 + put tLineIndex into tStart + if tHandler is an array then + if token 1 of tText[tLineIndex] is among the items of handlerTypes() and tHandler[token 2 of tText[tLineIndex]] then + exit repeat + else if token 1 of tText[tLineIndex] is "private" and token 2 of tText[tLineIndex] is among the items of handlerTypes() and tHandler[token 3 of tText[tLineIndex]] then + exit repeat + end if + else if token 1 of tText[tLineIndex] is "end" and token 2 of tText[tLineIndex] is not among the items of "if,repeat,switch,catch" then + exit repeat + end if + end repeat + + if tHandler is not an array and tStart is not 1 then + add 1 to tStart + end if + if tEnd > the number of elements of tText then + put the number of elements of tText into tEnd + end if + + -- Now format lines tStart to tEnd of pText, and return the result. + local tStartChar + if tStart is 1 then + put 1 into tStartChar + else + put the number of chars of line 1 to (tStart - 1) of pText into tStartChar + add 2 to tStartChar + end if + + local tOldText + put line tStart to tEnd of pText into tOldText + + local tResult + put tStartChar into tResult["startchar"] + put tOldText into tResult["oldtext"] + put textFormatSelection(tOldText) into tResult["newtext"] + + return tResult +end textFormat + +function textGetScript + return the text of field "Script" of me +end textGetScript + +function getScriptField + return the long id of field "Script" of me +end getScriptField + +on textSetSelection pAfterChar + select after char pAfterChar of field "Script" of me +end textSetSelection + +# Parameters +# pOldText : the text replaced in an operation +# pNewText : the replacing text in an operation +# Returns +# Whether or not a new undo group is needed for the specified +# operation. +private function textReplaceNewGroupNeeded pOldText, pNewText + # If the invoker of the replacement operation has specified that an undo group + # is needed, always create one + if sTextMark[sObjectId] is not empty then + return true + end if + + # If the number of chars of either the string replaced or replacing string is above one + # this means it must be a deletion of a selection or a cut or paste. This should always + # require a new group + if the number of chars of pOldText > 1 or the number of chars of pNewText > 1 then + return true + end if + + # If either the text being replaced or the replacing text contain return chars, new group + if pOldText contains return or pNewText contains return then + return true + end if + + return false +end textReplaceNewGroupNeeded + +# Parameters +# pOffset : the char number of where the replacement should start +# pOldText : the text that is being replaced +# pNewText : the text that is being inserted +# pObject : the long id of the object to replace in. If not given, the current object is assumed. +# Description +# This is the point through which all standard editing operations on scripts are sent through. +# Any change made via this function will be added to the undo system. This is called when the +# user types keys, formats text, cuts, pastes etc. +command textReplace pOffset, pOldText, pNewText, pObject, pDontGroup, pDontSelect + lock screen + + local tObject + if pObject is empty then + put sObjectId into tObject + else + put pObject into tObject + end if + + local tBracketCompletionType + __BracketCompletion pOffset, pOldText, pNewText + put it into tBracketCompletionType + + local tSelection + if tBracketCompletionType is "wrap" then + put the selectedChunk into tSelection + add 1 to word 2 of tSelection + add 1 to word 4 of tSelection + end if + + if pDontGroup is not true and textReplaceNewGroupNeeded(pOldText, pNewText) then + textBeginGroup sTextMark[tObject], tObject + end if + + add 1 to sTextOperationIndex[tObject] + add 1 to sTextGroupLengths[tObject,sTextGroupIndex[tObject]] + + local tEditPlaceholder + put sEditChunks is an array and sEditPlaceholder is not empty and \ + pOffset >= sEditChunks[1]["start"] and \ + pOffset + length(pOldText) - 1 <= sEditChunks[1]["end"] and \ + return is not in pNewText into tEditPlaceholder + + if tEditPlaceholder and \ + sPlaceholders[sEditPlaceholder]["classes"][1] is "identifier" then + put comma is not in pNewText and \ + ";" is not in pNewText and \ + space is not in pNewText and \ + quote is not in pNewText into tEditPlaceholder + end if + + if not tEditPlaceholder then + put pOffset into sTextOperationOffsets[tObject,sTextOperationIndex[tObject]] + put pOldText into sTextOperationOldTexts[tObject,sTextOperationIndex[tObject]] + put pNewText into sTextOperationNewTexts[tObject,sTextOperationIndex[tObject]] + if sEditPlaceholder is not empty then + __ClearCurrentPlaceholder true + end if + end if + + # When the script has been edited, the breakpoints should be suspended until it is applied again. + # Because this command is called as the user types, we could a send in time for this, as its not that urgent. + try + revDebuggerSuspendBreakpoints tObject + end try + + # If the specified object to replace in is the current object being edited, we perform the replace + # directly on the script editing field using textReplaceRaw. Otherwise we perform it on the + # script cache stored for the object. + if tObject is empty or revRuggedId(tObject) is sObjectId then + local tSelectedLength, tNewLength + put length(pOldText) into tSelectedLength + put length(pNewText) into tNewLength + + if tEditPlaceholder then + local tFirstCharOffset, tLastCharOffset + + put pOffset-sEditChunks[1]["start"] into tFirstCharOffset + put sEditChunks[1]["end"]-pOffset + tSelectedLength into tLastCharOffset + + local tToAdd = 0 + local tIndex + repeat with tIndex = 1 to the number of elements of sEditChunks + add tToAdd to sEditChunks[tIndex]["start"] + add tToAdd to sEditChunks[tIndex]["end"] + + textReplaceRaw sEditChunks[tIndex]["start"]+tFirstCharOffset, pOldText, pNewText + + add tNewLength - tSelectedLength to tToAdd + add tNewLength - tSelectedLength to sEditChunks[tIndex]["end"] + set the metadata of char sEditChunks[tIndex]["start"] to sEditChunks[tIndex]["end"] of field "script" of me to sEditPlaceholder + if tIndex is 1 then + set the backgroundColor of char sEditChunks[tIndex]["start"] to sEditChunks[tIndex]["end"] of field "script" of me to empty + else + set the backgroundColor of char sEditChunks[tIndex]["start"] to sEditChunks[tIndex]["end"] of field "script" of me to \ + the effective hiliteColor of field "script" of me + end if + put sEditChunks[tIndex]["start"]+tFirstCharOffset into sTextOperationOffsets[tObject,sTextOperationIndex[tObject]] + put pOldText into sTextOperationOldTexts[tObject,sTextOperationIndex[tObject]] + put pNewText into sTextOperationNewTexts[tObject,sTextOperationIndex[tObject]] + + add 1 to sTextOperationIndex[tObject] + add 1 to sTextGroupLengths[tObject,sTextGroupIndex[tObject]] + end repeat + put true into sPlaceholders[sEditPlaceholder]["edited"] + + if not pDontSelect then + if tSelection is not empty then + select tSelection + else if pNewText is empty then + select char pOffset to pOffset-1 of field "script" of me + else if the length of pNewText is 1 then + select char pOffset+1 to pOffset of field "script" of me + else if tBracketCompletionType is "pair" then + select after char pOffset of field "script" of me + end if + end if + else + -- clear highlighted bracket background color + __ClearHighlights + textReplaceRaw pOffset, pOldText, pNewText + if not pDontSelect then + if tSelection is not empty then + select tSelection + else if tBracketCompletionType is "pair" then + select after char pOffset of field "script" of me + end if + end if + end if + + if not pDontSelect then + selectionUpdateRequest + end if + + -- when formatting or pasting we don't want autocomplete to pop up + if the number of lines of pNewText <= 1 then + __UpdateAutoCompleteList sEditPlaceholder + end if + else + local tCache + put sScriptCache[revRuggedId(tObject)] into tCache + if tCache is empty then + put the script of tObject into tCache + end if + textReplaceRawInVariable tCache, pOffset, pOldText, pNewText + put tCache into sScriptCache[revRuggedId(tObject)] + end if + + set the caseSensitive to true + if pOldText is not pNewText then + # OK-2009-01-17 : Bug 7169 - Flag the object as dirty when it is modifed by this method only. + # The textReplaceRaw etc functions should not do this as they do not represent a user modifying + # the script. + setDirty tObject, true + end if + unlock screen +end textReplace + +# Parameters +# pOffset : the char number to begin the replacement at +# @rScript : the text to perform the replacement in, gets mutated +# @pOldText : the text that is to be replaced. This is not mutated, its a reference for efficiency reasons +# @pNewText : the text to be inserted. This is not mutated, its a reference for efficiency reasons +# Description +# Performs a raw replace exactly as textReplaceRaw, except in a variable instead of directly in the editing field. +# This is used by replace-all, because it may need to replace text in the script of objects which are not open. +command textReplaceRawInVariable @rScript, pOffset, @pOldText, @pNewText + local tOldLength + put the length of pOldText into tOldLength + put pNewText into char pOffset to pOffset + tOldLength - 1 of rScript +end textReplaceRawInVariable + +# Parameters +# pOffset : the char number to begin the replacement at +# @pOldText : the text that is to be replaced. This is not mutated, its a reference for efficiency reasons +# @pNewText : the text to be inserted. This is not mutated, its a reference for efficiency reasons +# pDontUpdateBreakpoints : optional, defaults to false. If this is true, breakpoints in the gutter are not moved. +# Description +# This is the raw replacement operation that performs a mutation on the script field without +# saving any undo information. This should be called only from inside textReplace, when doing an undo or a redo +# and when setting the script when a new object is loaded. +private command textReplaceRaw pOffset, @pOldText, @pNewText, pDontUpdateBreakpoints, pUpdateBreakpointsNow + lock screen + lock messages + + local tSelectedLine + put word 2 of the selectedLine into tSelectedLine + + local tEndOffset + put max(0, pOffset + the length of pOldText - 1) into tEndOffset + + _internal script replace char pOffset to tEndOffset of field "Script" of me with pNewText + + --Do some work to update the gutter. + local tOldLines, tNewLines + put the number of lines of pOldText into tOldLines + if pOldText is not return and (char -1 of pOldText is return or pOldText is empty) then + add 1 to tOldLines + end if + if pNewText is empty and pOldText is return then + put 0 into tNewLines + else + put the number of lines of pNewText into tNewLines + if char -1 of pNewText is return or pNewText is return or pNewText is empty then + add 1 to tNewLines + end if + end if + unlock messages + + if pDontUpdateBreakpoints then + updateGutterRequest empty, empty, tOldLines, tNewLines, false, false, false, pUpdateBreakpointsNow + else + updateGutterRequest pOffset, tSelectedLine, tOldLines, tNewLines, true, false, false, pUpdateBreakpointsNow + end if + + # OK-2008-09-10 : Bug 7132 - Update the panes and handler list everytime the text of the field is changed. + # OK-2009-01-19 : Don't do this here as it slows down the script editor on OS X. Instead do it in the individual + # cases where it may be needed, cut, paste, return, delete, backspace, undo and redo + --selectionUpdateRequest + + unlock screen +end textReplaceRaw + +-- Sets the contents of the fields to pScript WITHOUT touching the undo queue. This should be done before any editing. +on textSetScriptRaw pScript + --put empty into field "Script" of me + local tOldText + put the text of field "Script" of me into tOldText + if tOldText is not pScript then + textReplaceRaw 1, tOldText, pScript, true + end if +end textSetScriptRaw + +-- Sets the script within the undo queue. +on textSetScript pScript + textReplace 1, the text of field "Script" of me, pScript +end textSetScript + +# Description +# Performs an undo operation on the current script +on textUndo + undoAvailable + if not the result then + exit textUndo + end if + + local tOperations + put sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] into tOperations + + lock screen + repeat with tIndex = sTextOperationIndex[sObjectId] down to sTextOperationIndex[sObjectId] - tOperations + 1 + local tNewText, tOldText + put sTextOperationNewTexts[sObjectId,tIndex] into tNewText + put sTextOperationOldTexts[sObjectId,tIndex] into tOldText + textReplaceRaw sTextOperationOffsets[sObjectId,tIndex], tNewText, tOldText, false, true + end repeat + unlock screen + + subtract tOperations from sTextOperationIndex[sObjectId] + subtract 1 from sTextGroupIndex[sObjectId] + + if there is a sObjectId then + revDebuggerSuspendBreakpoints sObjectId + seSetObjectState sObjectId, "edited" + end if + + textMark "Insert" +end textUndo + +# Description +# Performs a redo operation on the current script +on textRedo + redoAvailable + if not the result then + exit textRedo + end if + + add 1 to sTextGroupIndex[sObjectId] + + local tOperations + put sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] into tOperations + lock screen + repeat with tIndex = sTextOperationIndex[sObjectId] + 1 to sTextOperationIndex[sObjectId] + tOperations + local tNewText, tOldText + put sTextOperationOldTexts[sObjectId,tIndex] into tOldText + put sTextOperationNewTexts[sObjectId,tIndex] into tNewText + textReplaceRaw sTextOperationOffsets[sObjectId,tIndex], tOldText, tNewText, false, true + end repeat + unlock screen + + add tOperations to sTextOperationIndex[sObjectId] + if there is a sObjectId then + revDebuggerSuspendBreakpoints sObjectId + seSetObjectState sObjectId, "edited" + end if + textMark "Insert" +end textRedo + +# Description +# This is a debugging command used to print the status of the undo queue when investigating +# problems. It should not be called anywhere in the code. +on textPrint + lock screen + + local tOperation + put 1 into tOperation + repeat with x = 1 to sTextGroupTop[sObjectId] + + put "Group(" & x & "):" && sTextGroupLabels[sObjectId,x] & return after message + repeat sTextGroupLengths[sObjectId,x] times + + local tOldText, tNewText + put sTextOperationOldTexts[sObjectId,tOperation] into tOldText + put sTextOperationNewTexts[sObjectId,tOperation] into tNewText + replace return with "\n" in tOldText + replace return with "\n" in tNewText + + put tab & "[" & tOperation & "]:" && sTextOperationOffsets[tOperation], tOldText, tNewText & return after message + + if tOperation is sTextOperationIndex[sObjectId] then + put tab & "--------" & return after message + end if + + add 1 to tOperation + end repeat + + if x is sTextGroupIndex[sObjectId] then + put "--------" & return after message + end if + end repeat + + unlock screen +end textPrint + +command cancelPendingMessages + if sGutterUpdateRequest is not empty then + cancel sGutterUpdateRequest + end if + + if sSelectionUpdateRequest is not empty then + cancel sSelectionUpdateRequest + end if + + if sPaneUpdateRequest is not empty then + cancel sPaneUpdateRequest + end if +end cancelPendingMessages + + +private command updateGutterMergeRequestDetails pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw + # The offset and selected line are just overwritten providing they are not empty + if pOffset is not empty then + put pOffset into sGutterUpdateRequestDetails["offset"] + end if + + if pSelectedLine is not empty then + put pSelectedLine into sGutterUpdateRequestDetails["selectedLine"] + end if + + # The old number of lines is not changed, however if its empty, we put the new value in + if sGutterUpdateRequestDetails["oldLines"] is empty then + put pOldLines into sGutterUpdateRequestDetails["oldLines"] + end if + + # The new number of lines overwrites the previous setting, again providing that its not empty + if pNewLines is not empty then + put pNewLines into sGutterUpdateRequestDetails["newLines"] + end if + + # The new text changed value is the logical OR of the new and old values + # The same is done for the update compilation errors and the force breakpoint redraw + put (pTextChanged or sGutterUpdateRequestDetails["textChanged"]) into sGutterUpdateRequestDetails["textChanged"] + put (pUpdateCompilationErrors or sGutterUpdateRequestDetails["updateCompilationErrors"]) into sGutterUpdateRequestDetails["updateCompilationErrors"] + put (pForceBreakpointRedraw or sGutterUpdateRequestDetails["forceBreakpointRedraw"]) into sGutterUpdateRequestDetails["forceBreakpointRedraw"] +end updateGutterMergeRequestDetails + +command deleteUpdateGutterRequestDetails + delete variable sGutterUpdateRequestDetails +end deleteUpdateGutterRequestDetails + +function getUpdateGutterRequestDetails + return sGutterUpdateRequestDetails +end getUpdateGutterRequestDetails + +# Parameters +# pOffset : the offset of the last text change +# pSelectedLine : the selected line at the point of the last text change +# pOldLines : the old number of lines in the script field at the point of the last text change +# pNewLines : the new number of liens in the script field after the last text change +# pTextChanged : whether text was changed or not since the last gutter update. If this is false, all the previous parameters are ignored. +# pUpdateCompilationErrors : whether to update the gutter's compilation errors +# Description +# Sends a request to update the gutter. This is called whenever the current script is edited, or the field +# is scrolled etc. +# The gutter's scroll is updated immediately. Also a message is sent to the gutter to hide its +# mutable objects (the breakpoint / compilation error images). These are show again when the update is +# actually carried out. +command updateGutterRequest pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw, pNow + if sGutterUpdateRequestDetails["offset"] is not empty and \ + pOffset is not sGutterUpdateRequestDetails["offset"] then + -- if the offset is different we can't merge + updateGutterDo + end if + + updateGutterMergeRequestDetails pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw + if sGutterUpdateRequest is not empty then + cancel sGutterUpdateRequest + end if + + # BUGFIX-20140 + # 2017-JUL-28 bhall2001 + # We always update the gutter's scroll immediately, as otherwise it looks bad. + # For best scroll performance, we set the Gutter scroll directly. + if exists(field "Numbers" of group "Gutter") then + set the vScroll of field "Numbers" of group "Gutter" to the vScroll of field "Script" of me + end if + + if pNow or (pOldLines is not 1 or pNewLines is not 1) then + updateGutterDo + else + send "updateGutterDo" to me in 200 milliseconds + put the result into sGutterUpdateRequest + end if +end updateGutterRequest + +# update gutter stubs +on updateGutterDo +end updateGutterDo + +# Description +# Sends a request to the script editor to update the panes. Requests are sent +# only after a period of inactivity to prevent bombardment. +command paneUpdateRequest + if sPaneUpdateRequest is not empty then + cancel sPaneUpdateRequest + end if + + -- allow environment with no dependencies + local tDelay + put __GetPreference("editor,paneupdatedelay", 500) into tDelay + send "paneUpdate" to me in tDelay milliseconds + put the result into sPaneUpdateRequest +end paneUpdateRequest + +# pane update stubs +command paneUpdate +end paneUpdate + +-- This is sent by the engine +on selectionChanged + if not handleEvent("selectionChanged", the long id of the target) then + pass selectionChanged + end if + if not (sArrowKeyPressed) then + handleSelectionChanged + end if + -- Unmark found results when clicking on the SE + selectionUpdateRequest +end selectionChanged + +on selectionChangedByArrowKey pArrowKey + saveLastSelections + put false into sArrowKeyPressed + + -- [[ Bug 18595 ]] We need this here otherwise the "it" var in the if block below is empty + get the selectedChunk + + local tAt + if word 2 of it > word 4 of it then + put word 4 of it into tAt + else + -- It is a multiple selection, so we need to exit this. + exit selectionChangedByArrowKey + end if + + -- Single selection in the process of making a larger selection, so exit if shift is down. + if the shiftKey is "down" then + exit selectionChangedByArrowKey + end if + + local tLine + put word 2 of the selectedLine into tLine + + local tField + put the long id of the selectedField into tField + + local tScript + put the text of tField into tScript + + local tLineStart + switch pArrowKey + case "left" + put the number of chars of line 1 to (tLine - 1) of tScript + 1 into tLineStart + # OK-2008-03-03 : Only add offset of return if we are not on the first line of the script + if tLine is not 1 then + add 1 to tLineStart + end if + put caretPositionLeft(tLineStart, tAt + 1, tScript) into tAt + + lock messages + select after char tAt of tField + unlock messages + break + case "right" + caretUpdate tField, tScript + break + if char (tAt + 1) of tScript is return then + add 1 to tLine + end if + put the number of chars of line 1 to (tLine - 1) of tScript + 2 into tLineStart + get line tLine of tScript + put caretPositionRight(tLineStart, tAt + 1, it) into tAt + break + case "up" + case "down" + caretUpdate tField, tScript + break + case "empty" + default + caretUpdate tField, tScript + break + end switch + + textMark "Insert" + selectionUpdateRequest +end selectionChangedByArrowKey + +-- PM-2016-09-22: [[ Bug 15887 ]] Distinguish between "selectionChanged" sent by the engine and \ + -- "selectionChangedByArrowKey pArrowKey" +on handleSelectionChanged + caretUpdate +end handleSelectionChanged + +private command saveLastSelections + if the selectedText of field "Script" of me is not empty then + put the selectedText of field "Script" of me into sLastNonEmptySelection + end if + + -- [[ Bug 18528 ]] We need this here otherwise the "it" var in the if block below is empty + get the selectedChunk + + # OK-2008-10-22 : Bug 7343 - Must save the last selection point as its lost + # when the user begins typing into the search field. + if the long id of the focusedObject is the long id of field "Script" of me then + put word 2 of it & comma & word 4 of it into sLastSelectedChunk + end if +end saveLastSelections + +private command selectionUpdateRequest + if sSelectionUpdateRequest is not empty then + cancel sSelectionUpdateRequest + end if + + -- handled by child behavior + send "selectionUpdate" to me in 200 milliseconds + put the result into sSelectionUpdateRequest +end selectionUpdateRequest + +#selection update stubs +on selectionUpdate + lock screen + __CheckHighlights + __ClearCurrentPlaceholder + saveLastSelections + unlock screen +end selectionUpdate + +on mouseMove + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteCancelFind the long id of me + end if + pass mouseMove +end mouseMove + +on closeField + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteCancelFind the long id of me + end if + pass closeField +end closeField + +on exitField + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteCancelFind the long id of me + end if + pass exitField +end exitField + +on escapeKey + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteCancelFind the long id of me + end if + pass escapeKey +end escapeKey + +on help + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteHandleHelp the long id of me, sObjectId + if the result then + pass help + end if + else + pass help + end if +end help + +-- This calculates the position of the caret based on pPosition where the caret is (hypothetically). +private function caretPositionRight pLineStartChar, pProposedPosition, pLine + local tFirstPosition + put pLineStartChar - 1 into tFirstPosition + repeat for each char tChar in pLine + if tChar is space then + add 1 to tFirstPosition + else + exit repeat + end if + end repeat + + return max(tFirstPosition, pProposedPosition) +end caretPositionRight + +-- On moving the caret/backspace left, this returns the correct char position. +private function caretPositionLeft pLineStartChar, pCurrentPosition, pScript + repeat with x = pCurrentPosition down to pLineStartChar + if char x of pScript is not space then + return (pCurrentPosition-1) + break + end if + end repeat + return pLineStartChar - 2 +end caretPositionLeft + +private command caretUpdate pField, pScript + lock screen + local tChunk + put the selectedChunk into tChunk + + local tLine + put word 2 of the selectedLine into tLine + + local tSearchLines + put __GetPreference("editor,placeholdersearchlines", kPlaceholderDefaultSearchLines) into tSearchLines + + if tChunk is not empty and exists(tChunk) then + get the metadata of tChunk + if it is not empty then + __ClearCurrentPlaceholder true + __SelectPlaceholder \ + it, \ + tLine, \ + tLine + tSearchLines + unlock screen + exit caretUpdate + end if + end if + + -- a text selection + if word 2 of tChunk <= word 4 of tChunk then + exit caretUpdate + end if + + local tField + if pField is empty then + put the long id of the selectedField into tField + else + put pField into tField + end if + + local tScript + if pScript is empty then + put the text of the selectedField into tScript + else + put pScript into tScript + end if + + # The current line is the first then its first char is char 1, otherwise it is the number of + # chars of all previous lines + 1 char for the return char and 1 for the first char of the line. + local tLineStart + if tLine is 1 then + put 1 into tLineStart + else + put the number of chars of line 1 to (tLine - 1) of tScript + 2 into tLineStart + end if + + lock messages -- dont cause selectionChanged loop + + select after char caretPositionRight(tLineStart, word 4 of the selectedChunk, line tLine of tScript) of tField + + unlock messages + unlock screen +end caretUpdate + + +# Offset between a field's top margin and the start of the text +constant kFudge = "-4" + +# Parameters +# pLineNumber : a line number in the script of the current object +# Returns +# The vertical location of that line in the gutter or 0 if the line is not visible +function lineNumberToVerticalLoc pLineNumber + local tField + put getScriptField() into tField + + local tHeight + put (pLineNumber - 1) * the effective textHeight of getScriptField() into tHeight + + # If the breakpoint is on a line earlier than the first one in the visible area then don't render it + if tHeight < the vScroll of getScriptField() then + return 0 + end if + + # If the breakpoint is on a line after the last one in the visible area the don't render it + if tHeight > (the vScroll of getScriptField() + the height of getScriptField()) then + return 0 + end if + + # Adjust the height to take the vScroll into account + local tLoc + put tHeight - the vScroll of getScriptField() into tLoc + + # Adjust the height so its relative to the start of the gutter + add the top of me to tLoc + + # Adjust the the height to take the field's margins into account. This requires a little fudge... + if the number of items of the margins of getScriptField() = 4 then + add item 2 of the margins of getScriptField() + kFudge to tLoc + else + add the margins of getScriptField() + kFudge to tLoc + end if + + # Adjust to the middle of the line + add round(0.5 * the effective textHeight of getScriptField()) to tLoc + + return tLoc +end lineNumberToVerticalLoc + +# Parameters +# pVerticalLoc : a vertical location within the gutter's area +# Returns +# The line number in the current script that is associated with the specified location. +# If the location is beyond any lines in the script, or the line cannot have a breakpoint +# on it, then 0 is returned. +function verticalLocToLineNumber pVerticalLoc + # Add the vScroll of the script field so that the location is relative to the start of the text + local tHeight + put the vScroll of getScriptField() + pVerticalLoc into tHeight + + # Make it relative to 0 rather than the top of the gutter + subtract the top of me from tHeight + + # Adjust the the height to take the field's margins into account. This requires a little fudge... + if the number of items of the margins of getScriptField() = 4 then + subtract item 2 of the margins of getScriptField() + kFudge from tHeight + else + subtract the margins of getScriptField() + kFudge from tHeight + end if + + # Divide to calculate which line number it falls nearest. Always round up. + local tLineNumber + put (tHeight div the effective textHeight of getScriptField()) + 1 into tLineNumber + return tLineNumber +end verticalLocToLineNumber + +# Returns +# Whether or not the script is locked +function scriptLocked + return the lockText of field "Script" of me +end scriptLocked + +on returnInField + if the commandKey is "down" then + # Pass to prevent conflict with command + return keyboard shortcut + pass returnInField + end if + + if not handleEvent("returnInField", the long id of the target) then + pass returnInField + end if + + if scriptLocked() then + exit returnInField + end if + + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteCancelFind the long id of me + end if + + local tFrom, tTo + get the selectedChunk + put word 2 of it into tFrom + put word 4 of it into tTo + + local tLine + put word 2 of the selectedLine into tLine + + # Option+Return places a continuation char on the current line before the return. + local tContinuationRequired + put (optionKey() is "down") into tContinuationRequired + + local tAt, tLength, tReturn + calculateReturnFormatting tTo, tFrom, tLine, tContinuationRequired, tAt, tLength, tReturn + + local tCaretOffset + put tAt + the length of tReturn - 1 into tCaretOffset + + local tLineEnd + put the number of chars of line 1 to tLine of textGetScript() + 1 into tLineEnd + + local tFollowingChars + put char tAt to tLineEnd of textGetScript() into tFollowingChars + + local tWhitespaceAfter + put matchText(tFollowingChars, "^\s*$") into tWhitespaceAfter + + -- allow environment with no dependencies + local tAutoComplete + put __GetPreference("editor,autocomplete", true) into tAutoComplete + + if tAutoComplete and tWhitespaceAfter then + autoComplete tLine, tReturn + end if + + # The return character should be grouped separately from the line that was entered before it (if there was one) + # This copies the behavior of MS Visual Studio. + if sTextGroupIndex[sObjectId] is not 0 then + # OK-2008-07-29 : Bug 6825 + --textEndGroup + textMark "Insert" + end if + + textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, tReturn + select after char tCaretOffset of field "Script" of me + textEndGroup + + # OK-2009-01-19 : Update the handler list + selectionUpdateRequest +end returnInField + +# Parameters +# Description +# Returns the specification of replace operation that represents the inserting of a +# return character at the specified location in the current script. Includes formatting. +# This command will also remove indentation from the previous line. +private command calculateReturnFormatting pTo, pFrom, pLine, pContinuationRequired, @rAt, @rLength, @rString + local tReturnString + if pContinuationRequired then + put " \" & return into tReturnString + else + put return into tReturnString + end if + + # If there is a non-empty selection, the inserted return char will replace this + # and for now, no formatting is done. + if pFrom <= pTo then + put pFrom into rAt + put pTo - pFrom + (the length of tReturnString) into rLength + put tReturnString into rString + exit calculateReturnFormatting + end if + + # If the preference is not to use formatting, just return the specification of the basic + # insertion of a return character. + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + if not tAutoFormat then + put pFrom into rAt + put 0 into rLength + put tReturnString into rString + exit calculateReturnFormatting + end if + + local tScript + put textGetScript() into tScript + + local tPreviousChars + repeat with x = pFrom - 1 down to 1 + if char x of tScript is empty or char x of tScript is return then + exit repeat + end if + put char x of tScript after tPreviousChars + end repeat + + local tWhitespaceBefore + put matchText(tPreviousChars, "^\s*$") into tWhitespaceBefore + + if tWhitespaceBefore then + local tIndent + put textFormatGetLineIndent(line pLine of tScript) into tIndent + + # If the caret has somehow been placed in the middle of the indentation string we need to allow + # for this by subtracting from tIndent + local tCurrentChar + put pFrom into tCurrentChar + repeat until (char tCurrentChar of tScript is not space) or the number of chars of tIndent = 0 + delete char 1 of tIndent + add 1 to tCurrentChar + end repeat + + local tLength + put 0 into tLength + + local tAt + put pFrom into tAt + + local tReturn + put return & tIndent into tReturn + else + local tFormatting + local tPreviousLine = 0 + local tTextLines + put tScript into tTextLines + split tTextLines by return + + put textFormatLine(pLine, tTextLines, tPreviousLine) into tFormatting + + put (the number of chars of line 1 to (pLine - 1) of tScript) + 1 into tAt + if pLine <> 1 then + add 1 to tAt + end if + + if item 1 of tFormatting > 0 then + repeat item 1 of tFormatting times + put space after tIndent + end repeat + textReplace tAt, empty, tIndent + else if item 1 of tFormatting < 0 then + textReplace tAt, char tAt to (tAt - item 1 of tFormatting - 1) of tScript, empty + end if + + put 0 into tLength + put pFrom into tAt + add item 1 of tFormatting to tAt + put tReturnString & item 2 of tFormatting into tReturn + end if + + put tAt into rAt + put tLength into rLength + put tReturn into rString +end calculateReturnFormatting + +# Parameters +# pLine : the line number we are inserting at (i.e word 2 of the selectedLine at the point which the return was pressed which triggered the autocomplete) +# xString : the string to put the completion after. This is the string that is about to be appended to the script as a result of pressing return +# Description +# Calculates the correct completion according to what is already on line pLine, including formatting, and places it after xString, +# which can then be inserted into the script field. +private command autoComplete pLine, @xString + local tScript + put textGetScript() into tScript + + local tCurrentLine + put line pLine of tScript into tCurrentLine + + # From the text in the current line, calculate what kind of structure the user is typing the start of (if any) + local tStructureType, tStructureName + get autoCompleteGetStructure(tCurrentLine) + put line 1 of it into tStructureType + put line 2 of it into tStructureName + + # Once we know what the structure is, lookup what the correct completion is for that structure. + local tCompletion + put autoCompleteGetCompletion(tStructureType, tStructureName) into tCompletion + if tCompletion is empty then + exit autoComplete + end if + + if tCompletion is empty then + exit autoComplete + end if + + # Look down the script and work out if we actually need to complete this structure, i.e. find out if its + # already been completed or not. + if not autoCompleteCompletionRequired(pLine, tStructureType, tStructureName, tCompletion) then + exit autoComplete + end if + + # Format the completion, this is easy because the indentation of the complete will always match + # that of pLine. + local tIndent + put textFormatGetLineIndent(tCurrentLine) before tCompletion + put return & tCompletion after xString +end autoComplete + +private function autoCompleteSearchContext @pScript, pLineNumber, pStructureType, pStructureName, pCompletion + if pStructureName is not empty then + return 1 + end if + + -- case can't be nested except within another switch so return 0 + if pStructureType is "case" then + return 1 + end if + + local tDepth + put 0 into tDepth + repeat with x = pLineNumber down to 1 + local tLine + put line x of pScript into tLine + + if token 1 of tLine is "private" and token 2 of tLine is among the items of autoCompleteNamedStructures() then + exit repeat + else if token 1 of tLine is among the items of autoCompleteNamedStructures() then + exit repeat + end if + + if token 1 of tLine is pStructureType then + add 1 to tDepth + else if token 1 of tLine is "end" and token 2 of tLine is pStructureType then + subtract 1 from tDepth + end if + end repeat + + return tDepth +end autoCompleteSearchContext + +# Parameters +# pLineNumber : the line that the structure to be completed starts on +# pStructureType : the type of the structure to be completed this is either one of autoCompleteNamedStructures() or autoCompleteUnnamedStructures() +# pStructureName : the name of the structure. (May be empty, not all structures have names, basically only handlers do) +# pCompletion : what the completion of the structure would be (this is needed in order to see if its already there). +# Returns +# True if a completion is required for this specification, false otherwise. +function autoCompleteCompletionRequired pLineNumber, pStructureType, pStructureName, pCompletion + local tScript + put textGetScript() into tScript + + local tOutOfBounds + put autoCompleteInSlashCommentOrOutOfHandler(tScript, pLineNumber) into tOutOfBounds + if tOutOfBounds then + return false + end if + + if pStructureType is "if" then + local tRequired + put autoCompleteIFsAreBalanced(pLineNumber, tScript) into tRequired + return tRequired + end if + + local tInitialDepth + put autoCompleteSearchContext(tScript, pLineNumber, pStructureType, pStructureName, pCompletion) into tInitialDepth + put line pLineNumber + 1 to -1 of tScript into tScript + + # The nesting depth starts at 1 as we have just entered a structure + local tNestingDepth + put tInitialDepth into tNestingDepth + repeat for each line tLine in tScript + if token 1 of tLine is token 1 of pCompletion and token 2 of tLine is token 2 of pCompletion then + subtract 1 from tNestingDepth + if tNestingDepth = 0 then + # The structure is already completed + return false + end if + else if pStructureType is "case" then + # special case `case` so it behaves sensibly + if (token 1 of tLine is "end" and token 2 of tLine is "switch") or \ + token 1 of tLine is "case" or \ + token 1 of tLine is "default" then + # if the switch structure ends then we need a break + return true + else if token 1 of tLine is not empty then + # if there's existing code within the case then we + # can reasonably assume that they don't want to put a break + # above it + return false + end if + else if token 1 of tLine is "end" and token 2 of tLine is not among the items of autoCompleteUnnamedStructures() and token 2 of tLine is not "if" then + # If a named structure is ending, but it doesn't match the structure we are looking for + # then if the structure we're looking for is un-named, we return true + if pStructureName is empty then + return true + end if + + # Else if we are looking for a named structure, then don't do the completion, because + # its possible that the user is renaming a handler and we should be conservative here. + if pStructureName is not empty then + return false + end if + else + get autoCompleteGetStructure(tLine) + + # If we have a matching structure being opened, increment the nesting depth + if line 1 of it is pStructureType and line 2 of it is pStructureName then + add 1 to tNestingDepth + end if + + # If a new handler has started and we are completing an any structure then + # we should return true now. + if line 2 of it is not empty then + return true + end if + end if + end repeat + + return true +end autoCompleteCompletionRequired + +function autoCompleteInSlashCommentOrOutOfHandler @pScript, pLineNumber + local tScript, tSlashStart, tSlashEnd, tNumItems, tNumLines, tSelChar + + put slash & "*" into tSlashStart + put "*" & slash into tSlashEnd + + put word 2 of the selectedChunk into tSelChar + if tSelChar is empty then + return empty + end if + + set the lineDelimiter to tSlashStart + set the itemDelimiter to tSlashEnd + + put the number of lines of char 1 to tSelChar of pScript into tNumLines + put the number of items of char 1 to tSelChar of pScript into tNumItems + + set the lineDelimiter to return + set the itemDelimiter to comma + + if tNumLines is not tNumItems then + return true + end if + + local tLine, tHandlerStartsA, tUnNamedStructures + + put "on,function,command,setProp,getProp,after,before,private" into tHandlerStartsA + split tHandlerStartsA by comma as set + + put "if,repeat,try,switch,case" into tUnNamedStructures + + put line pLineNumber of pScript into tLine + if tHandlerStartsA[token 1 of tLine] then return false + + local tLineOffsetEnd, tLineOffsetEndSkip, tOffsetStartNameLine, tOffsetStartSkip, tLookFor, tHandlerName + put "end" into tLookFor + put empty into tHandlerName + put 0 into tOffsetStartSkip + + put pLineNumber into tLineOffsetEndSkip + + repeat + put lineOffset(tLookFor, pScript, tLineOffsetEndSkip) into tLineOffsetEnd + if tLineOffsetEnd = 0 then exit repeat + add tLineOffsetEnd to tLineOffsetEndSkip + + put line tLineOffsetEndSkip of pScript into tLine + if token 1 of tLine is not tLookFor then next repeat + if token 2 of tLine is among the items of tUnNamedStructures then + next repeat + else + put token 2 of tLine into tHandlerName + exit repeat + end if + end repeat + + if tHandlerName is empty then return true + + repeat + put lineOffset(tHandlerName, pScript, tOffsetStartSkip) into tOffsetStartNameLine + if tOffsetStartNameLine = 0 then exit repeat + add tOffsetStartNameLine to tOffsetStartSkip + + put line tOffsetStartSkip of pScript into tLine + if tHandlerStartsA[token 1 of tLine] then + if token 1 of tLine is "private" then + if token 3 of tLine is tHandlerName then + exit repeat + else + next repeat + end if + else + if token 2 of tLine is tHandlerName then + exit repeat + else + next repeat + end if + end if + end if + end repeat + + if tOffsetStartSkip < pLineNumber then return false + + return true +end autoCompleteInSlashCommentOrOutOfHandler + +function autoCompleteIFsAreBalanced pLineNumber, pScript + local tHandlerStarts, tHandlerName + + put "on,function,command,setProp,getProp,after,before,private" into tHandlerStarts + + --put textGetScript() into tScript + + repeat with i = pLineNumber down to 1 + if token 1 of line i of pScript is among the items of tHandlerStarts then + exit repeat + end if + end repeat + + delete line 1 to i - 1 of pScript + + if token 1 of line 1 of pScript is "private" then + put token 3 of line 1 of pScript into tHandlerName + else + put token 2 of line 1 of pScript into tHandlerName + end if + + local tCounter + repeat for each line aLine in pScript + add 1 to tCounter + if token 1 of aLine is "end" and token 2 of aLine is tHandlerName then + exit repeat + end if + end repeat + + put line 1 to tCounter of pScript into pScript + + -- remove slash asterisk comments + local tBeginAsterix, tEndAsterix, tCharBegin, tCharEnd + put slash & "*" into tBeginAsterix + put "*" & slash into tEndAsterix + + repeat + put offset(tBeginAsterix, pScript) into tCharBegin + if tCharBegin is 0 then exit repeat + put offset(tEndAsterix, pScript) into tCharEnd + delete char tCharBegin to tCharEnd of pScript + end repeat + + -- remove comments after backslash + -- and remove line-continuation + local tBackSlashStart, tReturnStart + put 0 into tBackSlashStart + repeat + put offset(backslash, pScript, tBackSlashStart) into tBackSlashStart + if tBackSlashStart is 0 then exit repeat + put offset(return, pScript, tBackSlashStart) into tReturnStart + delete char tBackSlashStart to tBackSlashStart + tReturnStart of pScript + put 0 into tBackSlashStart + end repeat + + replace ";" with return in pScript -- remove ";" + + local tDepth, tToken1, tElse, tIf_Then_CodeFlag, tElse_IFFlag + put "e" & "lse" into tElse -- avoid "tokenization" + put false into tIf_Then_CodeFlag + put false into tElse_IFFlag + put 0 into tDepth + + repeat for each line aLine in pScript + put token 1 of aLine into tToken1 + if tToken1 is empty then next repeat + + ######### get rid of one-liners + -- if foo() then code else code + if tToken1 is "if" and token -1 of aLine is not "then" and tElse is among the tokens of aLine then + next repeat + end if + + -- if foo() + -- then code else code + if tToken1 is "then" and token -1 of aLine is not "then" and tElse is among the tokens of aLine then + next repeat + end if + ######### end get rid of one-liners + + ######### special case of if-then-code + -- if bar() then code <-- can go on with else or end here + -- else + -- code + -- end if + -- or + -- if bar() then code <-- can end with else_code + -- -- optionally some lines else-if-then + -- else code + + if tIf_Then_CodeFlag then + if tToken1 is tElse then + + if the number of tokens of aLine = 1 then + put false into tIf_Then_CodeFlag + add 1 to tDepth + next repeat + end if + + if token 2 of aLine is "if" and token -1 of aLine is "then" then + put false into tIf_Then_CodeFlag + add 1 to tDepth + next repeat + end if + + if token 2 of aLine is "if" and token -1 of aLine is not "then" then + next repeat + end if + + if token 2 of aLine is not "if" and the number of tokens of aLine > 1 then + put false into tIf_Then_CodeFlag + next repeat + end if + + else + put false into tIf_Then_CodeFlag + end if + end if + + -- condition of entering special case if-then-code + if tToken1 is "if" and "then" is among the tokens of aLine and \ + token -1 of aLine is not "then" and tElse is not among the tokens of aLine then + put true into tIf_Then_CodeFlag + next repeat + end if + + if tToken1 is "then" and \ + token -1 of aLine is not "then" and tElse is not among the tokens of aLine then + put true into tIf_Then_CodeFlag + next repeat + end if + ######### end special case: if-then-code + + if tToken1 is "if" and token -1 of aLine is "then" then + add 1 to tDepth + end if + + if tToken1 is "then" and token -1 of aLine is "then" then + add 1 to tDepth + end if + + #################### + -- if foo() then + -- code else code <-- + if tElse is among the tokens of aLine and \ + (tToken1 is not tElse) and \ + (token -1 of aLine is not tElse) and \ + (tToken1 is not "then" and tToken1 is not "if") then + subtract 1 from tDepth + end if + #################### + + #################### + -- if foo() then + -- code + -- else code <-- + if tToken1 is tElse and token -1 of aLine is not tElse and "if" is not among the tokens of aLine then + subtract 1 from tDepth + end if + #################### + + #################### + -- special case else-if-code + -- if foo() then + -- code + -- else if bar() then code <-- can end here + -- or + -- if foo() then + -- code + -- else if bar() then code + -- else <-- or go on with else + -- code + + if tElse_IFFlag then + if tToken1 is tElse then + + if token 2 of aLine is "if" and token -1 of aLine is not "then" then + next repeat + end if + + put false into tElse_IFFlag + next repeat + + else + put false into tElse_IFFlag + subtract 1 from tDepth + end if + end if + + -- special case else-if-code + -- also tests else-if without "then", "then" is in this case on following line + if tToken1 is tElse and token 2 of aLine is "if" and token -1 of aLine is not "then" then + put true into tElse_IFFlag + next repeat + end if + -- end special case else-if-code + #################### + + if tToken1 is "end" and token 2 of aLine is "if" then + subtract 1 from tDepth + end if + + end repeat + + if tDepth is 0 then + return false + else + return true + end if + +end autoCompleteIFsAreBalanced + +# Returns +# A comma separated list of the autocompleteable structures that have names. This is currently just handlers. +private function autoCompleteNamedStructures + return handlerTypes() +end autoCompleteNamedStructures + +# Returns +# A comma separated list of the autocompleteable structures without names. Note that we only complete IF statements when the last token is then +# because there are too many possibilities, (else, else if, end if) and its better to not complete than risk forcing the user to delete stuff. +private function autoCompleteUnnamedStructures + return "repeat,try,switch,case" +end autoCompleteUnnamedStructures + +# Parameters +# pLine : a line number in the current script +# Returns +# A string describing the structure whose beginning is found on pLine. This is in the following format: +# Line 1 : The structure's type, e.g. command, repeat, try +# Line 2 : The structure's name if it has one, e.g. mouseUp +# If pLine does not represent the beginning of a completable structure then the structure type will be empty. +private function autoCompleteGetStructure pLine + local tLine + put pLine into tLine + + # Disregard "private" if first token + if token 1 of tLine is "private" then + put token 2 to -1 of tLine into tLine + end if + + local tStructureType, tStructureName + + # Establish what the structure type and name (if appropriate) are. We autocomplete handler declarations, + # repeats, trys and switches, but not ifs (because they have too many different forms, might annoy the user). + if token 1 of tLine is among the items of autoCompleteNamedStructures() then + put token 1 of tLine into tStructureType + put token 2 of tLine into tStructureName + else if token 1 of tLine is among the items of autoCompleteUnnamedStructures() then + put token 1 of tLine into tStructureType + put empty into tStructureName + else if token 1 of tLine is "if" and the last token of tLine is "then" then + put "if" into tStructureType + put empty into tStructureName + end if + + return tStructuretype & return & tStructureName +end autoCompleteGetStructure + +# Parameters +# pStructureType : the type of a completeable structure +# pStructureName : the name of a compleatable structure (may be empty) +# Returns +# The completion of the stucture if one is known. E.g if pStructureType is "on" and pStuctureName is "mouseUp", +# will return "end mouseUp" +private function autoCompleteGetCompletion pStructureType, pStructureName + # Make sure we have something valid that can be completed + if pStructureType is empty then + return empty + end if + + # Work out the completion + local tCompletion + if pStructureType is among the items of handlerTypes() then + if pStructureName is not empty then + put "end " & pStructureName into tCompletion + end if + else if pStructureType is "case" then + local tTabDepth + put __GetPreference("editor,tabdepth", 3) into tTabDepth + + repeat for tTabDepth + put space after tCompletion + end repeat + put "break" after tCompletion + else + put "end " & pStructureType into tCompletion + end if + + return tCompletion +end autoCompleteGetCompletion + +private function getSelectedText + local tFrom, tTo + get the selectedChunk + put word 2 of it into tFrom + put word 4 of it into tTo + + local tText + if tTo < tFrom then + getCaretToken + put the result into tText + else + put char tFrom to tTo of textGetScript() into tText + end if + + return tText +end getSelectedText + +# OK-2009-01-22 : Bug 7278 - Use the clickText instead of the selectedText for the context menu +# Also modified getCaretToken by adding optional pUseClick parameter. +function getClickText + -- local tFrom, tTo + -- get the clickChunk + -- put word 2 of it into tFrom + -- put word 4 of it into tTo + + local tText + -- if tTo < tFrom then + getCaretToken true + put the result into tText + --else + -- put char tFrom to tTo of textGetScript() into tText + --end if + + return tText +end getClickText + +private function handleEvent pEvent, pTarget + if the long id of pTarget is the long id of field "Script" of me then + return true + else + return false + end if +end handleEvent + +# OK-2009-03-02 : Bug 7773 +on optionKeyDown pKey + if not handleEvent("optionKey", the long id of the target) then + pass optionKeyDown + end if + + if pKey is not an integer or pKey <= 9 then + __DoKeyDown pKey + end if +end optionKeyDown + + +on scrollBarDrag + if the short name of the target is "Gutter" or the short name of the owner of the target is "Gutter" then + exit scrollBarDrag + end if + + local tVScroll + + # 2017-JUL-28 bhall2001 + # update only when vScroll changes. Mouse wheel scrolling sends + # vScrolls that don't change. Up arrow causes 2 scrollBarDrag message + # so we skip the message when up arrow flag is set. + put the vScroll of the target into tVScroll + if (tVScroll = sVScroll) or sSkipUpArrow then exit scrollBarDrag + + lock screen + put tVScroll into sVScroll + + updateGutterRequest empty, empty, empty, empty, false, true, false, true + unlock screen +end scrollBarDrag + +on keyDown pChar + if not handleEvent("keydown", the long id of the target) then + pass keyDown + end if + + if scriptLocked() then + exit keyDown + end if + + __DoKeyDown pChar +end keyDown + +private command __DoKeyDown pChar + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + local tAt, tLength + if tFrom > tTo then -- the caret is at the end + put 0 into tLength + put tFrom into tAt + else + put tFrom into tAt + put tTo - tFrom + 1 into tLength + end if + textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, pChar +end __DoKeyDown + +on backspaceKey + if not handleEvent("backspaceKey", the long id of the target) then + pass backspaceKey + end if + + if scriptLocked() then + exit backspaceKey + end if + + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + local tAt, tLength + if tFrom > tTo then + -- Caret handling, for now, is only done for an "empty" selection. + local tLine + put word 2 of the selectedLine into tLine + + local tScript + put the text of the selectedField into tScript + + local tLineStart + put the number of chars of line 1 to (tLine - 1) of tScript + 1 into tLineStart + -- Only add offset of return if we are not on the first line of the script + if tLine is not 1 then + add 1 to tLineStart + end if + + # OK-2008-08-28 : Bug 6515 - Delete whole word with commandKey + if the commandKey is "down" then + local tWordFound + put false into tWordFound + repeat with x = tTo down to 1 + if not matchText(char x of tScript, "\s") then + put true into tWordFound + else + if tWordFound then + exit repeat + end if + end if + end repeat + + if x <> 1 then + put x + 1 into tAt + else + put x into tAt + end if + + put tTo - tAt + 1 into tLength + else + # OK-2008-08-05 : Bug 6867 - If autoformatting is turned off, simply delete the last selected character + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + if tAutoFormat then + put caretPositionLeft(tLineStart, tTo, tScript) + 1 into tAt + else + put tTo into tAt + end if + put tTo - tAt + 1 into tLength + end if + else + put tTo - tFrom + 1 into tLength + put tFrom into tAt + end if + + textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, empty + + # If the user has deleted a selection of text rather than a single character, they will + # expect this to be a single undoable operation. So we close the current group straight + # after the deletion. in this case. + if tTo > tFrom then + textEndGroup + end if +end backspaceKey + +on deleteKey + if not handleEvent("deleteKey", the long id of the target) then + pass deleteKey + end if + + if scriptLocked() then + exit deleteKey + end if + + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + local tAt, tLength + if tFrom > tTo then + put tFrom into tAt + put 1 into tLength + else + put tFrom into tAt + put tTo - tFrom + 1 into tLength + end if + + textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, empty + + # If the user has deleted a selection of text rather than a single character, they will + # expect this to be a single undoable operation. So we close the current group straight + # after the deletion. in this case. + if tTo > tFrom then + textEndGroup + end if +end deleteKey + +on tabKey + if not handleEvent("tabKey", the long id of the target) then + pass tabKey + end if + + # To prevent interference with the command+tab shortcut to cycle between tabs + if the commandKey is "down" then + pass tabKey + end if + + # bhall2001-2017-07-18: Bug 18366 On MacOS, to prevent interference + # with the use of control+tab to cycle between tabs + if (the platform is "MacOS") and (the controlKey is "down") then + pass tabKey + end if + + if scriptLocked() then + exit tabKey + end if + + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + local tProviderCompletion + put __GetPreference("editor,providercompletion", true) into tProviderCompletion + + local tDoTab = true + + if tProviderCompletion and \ + revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteHandleTab the long id of me, sObjectId, sPlaceholders, sEditPlaceholder, sEditChunks + put the result into tDoTab + end if + + if tDoTab then + if tAutoFormat then + if the shiftKey is "down" then + scriptFormat "script" + else + scriptFormat "handler" + end if + else + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + local tAt, tLength + if tFrom > tTo then + put tFrom into tAt + put 0 into tLength + else + put tFrom into tAt + put tTo - tFrom into tLength + end if + + textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, tab + end if + end if +end tabKey + +# Key identifiers for a few important keys... +constant kKeyHome = "65360" +constant kKeyEnd = "65367" +constant kKeyLeftArrow = "65361" +constant kKeyRightArrow = "65363" +constant kKeyUpArrow = "65362" +constant kKeyDownArrow = "65364" +constant kKeyF1 = "65470" +constant kKeyF2 = "65471" +constant kKeyF3 = "65472" +constant kKeyF4 = "65473" +constant kKeyF5 = "65474" +constant kKeyF6 = "65475" +constant kKeyF7 = "65476" +constant kKeyF8 = "65477" +constant kKeyF9 = "65478" +constant kKeyF10 = "65479" +constant kKeyF11 = "65480" +constant kKeyF12 = "65481" +constant kKeyF13 = "65482" +constant kKeyNumLock = "65407" +constant kKeyPageUp = "65365" +constant kKeyPageDown = "65366" +# constant kKeyMenu = "80" + +private command selectFromCurrentToLineStart + local tAt + put word 4 of the selectedChunk into tAt + + local tLineNumber + put word 2 of the selectedLine into tLineNumber + + local tLineStart + put the number of chars of line 1 to (tLineNumber - 1) of the text of getScriptField() + 1 into tLineStart + # Only add offset of return if we are not on the first line of the script + if tLineNumber is not 1 then + add 1 to tLineStart + end if + + select char tLineStart to tAt of field (the short name of getScriptField()) of me +end selectFromCurrentToLineStart + +private command selectFromCurrentToLineEnd + local tAt + put word 4 of the selectedChunk into tAt + + local tLineNumber + put word 2 of the selectedLine into tLineNumber + + local tLineEnd + put the number of chars of line 1 to tLineNumber of the text of getScriptField() into tLineEnd + + select char (tAt + 1) to tLineEnd of field (the short name of getScriptField()) of me +end selectFromCurrentToLineEnd + +-- Description +-- Implements a basic page up functionality for OS X, as this is not default field behavior. +private command pageUp + local tLineNumber + put word 2 of the selectedLine into tLineNumber + + -- Work out the number of lines in one "page" of the script editor field. + local tLineCount + put the height of getScriptField() div the textHeight of getScriptField() into tLineCount + + -- Work out which line number we need to scroll up to + local tNewLineNumber + put max(tLineNumber - tLineCount, 1) into tNewLineNumber + + -- Calculate the char that we need to reach to do the page up + local tStartChar + put the number of chars of line 1 to tNewLineNumber of the text of getScriptField() into tStartChar + + local tAt + put word 4 of the selectedChunk into tAt + + if shiftKey() is "down" then + select char tStartChar to tAt of field (the short name of getScriptField()) of me + else + select after char tStartChar of field (the short name of getScriptField()) of me + end if +end pageUp + +-- Description +-- Implements a basic page down functionality for OS X, as this is not default field behavior. +private command pageDown + local tMultiSelection, tAt + get the selectedChunk + if word 4 of it > word 2 of it then + put true into tMultiSelection + put word 4 of it into tAt + else + put false into tMultiSelection + put word 2 of it into tAt + end if + + local tLineNumber + if tMultiSelection then + put word 4 of the selectedLine into tLineNumber + else + put word 2 of the selectedLine into tLineNumber + end if + + -- Work out the number of lines in one "page" of the script editor field. + local tLineCount + put the height of getScriptField() div the textHeight of getScriptField() into tLineCount + + -- Work out which line number we need to scroll down to + local tNewLineNumber + put min(tLineNumber + tLineCount, the number of lines of the text of getScriptField()) into tNewLineNumber + + -- Calculate the char that we need to reach to do the page down + local tEndChar + put the number of chars of line 1 to tNewLineNumber of the text of getScriptField() into tEndChar + + if shiftKey() is "down" then + select char tAt to tEndChar of field (the short name of getScriptField()) of me + else + select after char tEndChar of field (the short name of getScriptField()) of me + end if +end pageDown + +# Description +# RawKeyDown is handled mainly because of the home and end keys. These need to be manually implemented on OS X +# and both platforms after pressing the home key we have to ensure the caret ends up in the right place. +# Other keys may be blocked here to prevent weird chars getting inserted into the script. +on rawKeyDown pKey + if not handleEvent("rawKeyDown", the long id of the target) then + pass rawKeyDown + end if + + # For the beginning of line/paragraph action (there is no distinction in the S/E) + # make sure we update the caret position after the field has had its go. + + if the platform is not "macos" then + # For Windows: Home (Windows / Linux) + if pKey is kKeyHome then + put true into sArrowKeyPressed + send "selectionChangedByArrowKey" to me in 0 milliseconds + pass rawKeyDown + end if + else + # For Mac: Ctrl-Left / Cmd-Left / Ctrl-A (Mac) + if (pKey is kKeyLeftArrow and \ + (the eventCommandKey is down or \ + the eventControlKey is down) and \ + the eventShiftKey is up and \ + the eventOptionkey is up) or \ + (pKey is 65 and \ + the eventCommandKey is up and \ + the eventControlKey is down and \ + the eventShiftKey is up and \ + the eventOptionkey is up) then + put true into sArrowKeyPressed + send "selectionChangedByArrowKey" to me in 0 milliseconds + pass rawKeyDown + end if + + # For actions where we need to skip back, we need to ensure the caret is at the + # start of the line if it is in the white-space prefix. + + # For Mac: Alt-Down + if (pKey is kKeyUpArrow) and \ + the eventCommandKey is up and \ + the eventControlKey is up and \ + the eventShiftKey is up and \ + the eventOptionkey is down then + local tScript + put the text of the selectedField into tScript + + local tCaretChar + get the selectedChunk + put word 2 of it into tCaretChar + try + repeat while tCaretChar > 1 and (char (tCaretChar - 1) of tScript is space) + subtract 1 from tCaretChar + end repeat + catch tError + put tError + end try + if tCaretChar is not 1 and char tCaretChar - 1 of tScript is return then + lock messages + select before char tCaretChar of the selectedField + unlock messages + end if + end if + + end if + + # optionKey is down + local tKeyName + if (pKey is kKeyLeftArrow or pKey is kKeyRightArrow) and \ + the eventCommandKey is up and \ + the eventShiftKey is up and \ + the eventOptionkey is down and \ + the eventControlKey is up then + put true into sArrowKeyPressed + if pKey is kkeyRightArrow then + send "selectionChangedByArrowKey" to me in 0 milliseconds + else + put "left" into tKeyName + send "selectionChangedByArrowKey tKeyName" to me in 0 milliseconds + end if + pass rawKeyDown + end if + + if pKey is not among the items of kKeyLeftArrow,kKeyRightArrow,kKeyUpArrow,kKeyDownArrow then + pass rawKeyDown + end if + + # for simple arrowKeys + + # [[ Bug 18595 ]] "cursor should move to begin of text if click is left of text" + # moved handling of arrowKey from rawKeyUp here to flag arrowKey in sArrowKeyPressed + # before "selectionChanged" message is fired + + switch pKey + case kKeyLeftArrow + put "left" into tKeyName + break + case kKeyRightArrow + put "right" into tKeyName + break + case kKeyUpArrow + # 2017-JUL-28 bhall2001 + # when scrolling on up arrow, scrollBarDrag is sent twice. Set + # flag to update on every other up arrow message + put not sSkipUpArrow into sSkipUpArrow + put "up" into tKeyName + break + case kKeyDownArrow + put "down" into tKeyName + break + end switch + + local tPass = true + if revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteHandleArrow the long id of me, tKeyName, sObjectId, sPlaceholders, sEditPlaceholder, sEditChunks + put the result into tPass + end if + + if not scriptLocked() and tPass then + textMark "Insert" + put true into sArrowKeyPressed + send "selectionChangedByArrowKey tKeyName" to me in 0 milliseconds + end if + + if tPass then + pass rawKeyDown + end if +end rawKeyDown + +-- Drag Drop Management +local sDragMode + +on dragDrop + if not handleEvent("dragDrop", the long id of the target) then + pass dragDrop + end if + + if scriptLocked() then + exit dragDrop + end if + + lock screen + textBeginGroup "Drag" + + local tDropAt + get the dropChunk + put word 2 of it into tDropAt + + local tSelectFrom, tSelectTo + get the selectedChunk + put word 2 of it into tSelectFrom + put word 4 of it into tSelectTo + + if tDropAt >= tSelectFrom and tDropAt <= tSelectTo then + exit dragDrop + end if + + if sDragMode is "cut" then + -- Remove the selection. This will never happen on a drag that started outside the ScriptEditorPane. + + -- in this case, we cannot have tFrom > tTo + textReplace tSelectFrom, char tSelectFrom to tSelectTo of control "Script" of me, empty + + if tDropAt > tSelectTo then + subtract tSelectTo - tSelectFrom + 1 from tDropAt + end if + end if + + + local tDroppedText + put dragData["text"] into tDroppedText + -- There is an issue with the very last return character, for now it seams sufficient to remove this. + # if char -1 of tDroppedText is return then + # delete char -1 of tDroppedText + # end if + + textReplace tDropAt, empty, tDroppedText + + textEndGroup + unlock screen +end dragDrop + +on dragStart + if not handleEvent("dragStart", the long id of the target) then + pass dragStart + end if + + # OK-2008-08-01 : Bug 6709 - On Macs, the option key should result in a copying drag. + if the platform is not "MacOS" then + if the controlKey is "down" then + put "copy" into sDragMode + else + put "cut" into sDragMode + end if + else + if the optionKey is "down" then + put "copy" into sDragMode + else + put "cut" into sDragMode + end if + end if + + pass dragStart +end dragStart + +on dragEnd +end dragEnd + +# Description +## Returns a line stripped of comments at the end of the line +## and inline comments ( /* ... */ ) +private function lineStripComments pLine + local tLine, tInComment + split pLine by quote + + put false into tInComment + repeat with tIndex = 1 to the number of elements of pLine step 2 + put __StripComment(pLine[tIndex], tInComment) after tLine + if tInComment then exit repeat + if tIndex is not the number of elements of pLine then + put quote & pLine[tIndex+1] & quote after tLine + end if + end repeat + + return tLine +end lineStripComments + +private function __StripComment pLine, @xInComment + local tOffset + repeat for each word tComment in "# -- //" + put offset(tComment, pLine) into tOffset + if tOffset is not 0 then + delete char tOffset to -1 of pLine + put true into xInComment + end if + end repeat + + put __StripBlockComment(pLine, xInComment) into pLine + + return pLine +end __StripComment + +private function __StripBlockComment pline, @xInComment + local tOffset, tOffsetEnd + put offset("/*", pLine) into tOffset + if tOffset is not 0 then + put offset("*/", pLine, tOffset) into tOffsetEnd + if tOffsetEnd is not 0 then + delete char tOffset to tOffset + tOffsetEnd of pLine + put __StripBlockComment(pLine, xInComment) into pLine + else + delete char tOffset to -1 of pLine + put true into xInComment + end if + end if + + return pLine +end __StripBlockComment + +################################################################################ + +command actionCopy + copy +end actionCopy + +command actionCut + if scriptLocked() then + exit actionCut + end if + + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + if tFrom <= tTo then -- something is selected + textBeginGroup "Cut" + copy -- set the clipboard (dont cut as we do not allow field modification here) + textReplace tFrom, char tFrom to tTo of field "Script" of me, empty + textEndGroup + end if +end actionCut + +command actionPaste + if scriptLocked() then + exit actionPaste + end if + + get the selectedChunk + + local tFrom, tTo + put word 2 of it into tFrom + put word 4 of it into tTo + + lock screen + textBeginGroup "Paste" + textReplace tFrom, char tFrom to tTo of field "Script" of me, the clipboardData["text"] + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + if tAutoFormat then + scriptFormat "handler", true + end if + textEndGroup + unlock screen +end actionPaste + +command actionUndo + if scriptLocked() then + exit actionUndo + end if + textUndo +end actionUndo + +command actionRedo + if scriptLocked() then + exit actionRedo + end if + textRedo +end actionRedo + +command actionDeselectAll + lock messages + select empty + unlock messages +end actionDeselectAll + +command actionSelectAll + lock messages + + if word 1 of the name of the focusedObject is "field" then + select char 1 to -1 of the focusedObject + end if + unlock messages +end actionSelectAll + +# Parameters +# rStartLine : receives the line number that the current selection begins on +# rEndLine : receices the line number that the current selection ends on +# rStartChar : receives the char that the curent selection starts on +# rText : receives the block of text that will be commented or uncommented. +# Description +# This command obtains the details required to comment / uncomment a block of code +# it is used by the scriptComment and scriptUncomment commands. +private command commentGetDetails @rStartLine, @rEndLine, @rStartChar, @rText + # Calculate the chunk of text that the commenting will be applied to + local tStartLine, tEndLine + get the selectedLine + put word 2 of it into tStartLine + if word 3 of it is "to" then + put word 4 of it into tEndLine + end if + + # Adjust the chunk so that we have only complete lines by searching from the beginning + # backwards to the next return char. Don't bother doing this for the end as this doesn't matter. + get the selectedChunk + local tCurrentStart + put word 2 of it into tCurrentStart + + local tStartChar + + if tStartLine = 1 then + put 1 into tStartChar + else + local tPreviousChars + put char 1 to (tCurrentStart - 1) of field "Script" of me into tPreviousChars + + local tOffset + put 0 into tOffset + repeat with x = the number of chars of tPreviousChars down to 1 + if char x of tPreviousChars is return then + exit repeat + end if + add 1 to tOffset + end repeat + #subtract 1 from tOffset + + put tCurrentStart - tOffset into tStartChar + end if + + # Get the text and add in the comments + local tText + if tEndLine is empty then + put line tStartLine of field "Script" of me into tText + else + put line tStartLine to tEndLine of field "Script" of me into tText + end if + + put tStartChar into rStartChar + put tStartLine into rStartLine + put tEndLine into rEndLine + put tText into rText +end commentGetDetails + +# Description +# Returns the last known token that the caret was placed into. This is not done properly +# at the moment as it depends on the syntax, for now we just return something sensible. +command getCaretToken pUseClick + local tScript + put the text of getScriptField() into tScript + + # Don't return tokens in comments. For now we determine if the user is typing + # in a comment by simple means, using proper tokenization is not yet possible. + # This means that multi-line comments will break this. + local tLine + if pUseClick then + put word 2 of the clickLine into tLine + else + put word 2 of the selectedLine of getScriptField() into tLine + end if + if token 1 of line tLine of tScript is empty then + return empty + end if + + local tSelectedText + if pUseClick then + put the clickText into tSelectedText + else + put the selectedText of getScriptField() into tSelectedText + # OK-2008-06-22 : Bug 8054 - pUseClick is only set if we are building a context menu, so in this case + # do the expansion anyway to try and get a whole token. + if tSelectedText is not empty then + return tSelectedText + end if + end if + + # This is expanded to include tokens that the caret was placed immediately before or after, + # the reason for this is that it allows us to begin searching for tokens while the user is typing. + local tFrom, tTo + if pUseClick then + get the clickChunk + else + get the selectedChunk + end if + put word 2 of it into tFrom + put word 4 of it into tTo + + # We can't perfectly match tokens at the moment, so we just make a reasonable guess with a regular expression + # to match any char that delimits a token. + ## AL-2014-01-15: [[ Bug 11094 ]] Added # to the list of script editor token delimiters + local tExpression + put "\s|[\%\^\&\*\(\)\-\+\=\]\]\;\,\\@\\\/\<\>\#]" into tExpression + + # Try looking backwards first + local tText, tChar + repeat with x = (tFrom - 1) down to 1 + put char x of tScript into tChar + if matchText(tChar, tExpression) then + exit repeat + end if + put tChar before tText + end repeat + + # Try looking forwards + repeat with x = tFrom to the number of chars of tScript + put char x of tScript into tChar + if matchText(tChar, tExpression) then + exit repeat + end if + put tChar after tText + end repeat + + return tText +end getCaretToken + +# Description +# Comments out the selected text +command scriptComment + local tStartLine, tEndLine, tStartChar, tText + commentGetDetails tStartLine, tEndLine, tStartChar, tText + if tStartLine is empty then + exit scriptComment + end if + + lock screen + + -- allow environment with no dependencies + local tCommentChar + put __GetPreference("editor,commentchar", "--") into tCommentChar + + local tCommentedText + repeat for each line tLine in tText + # Don't comment out empty lines as it looks messy + if not matchText(tLine, "^\s*$") then + put tCommentChar before tLine + end if + put tLine & return after tCommentedText + end repeat + delete the last char of tCommentedText + + # Apply the mutation to the field + textBeginGroup "Comment" + textReplace tStartChar, tText, tCommentedText + + # Restore the selection + select char tStartChar to tStartChar + length(tCommentedText) of field "Script" + + # OK-2009-03-03 : Bug 7537 - Reformat the handler after commenting, this may be flawed, + # but the proper solution is rather time-consuming. + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + if tAutoFormat then + scriptFormat "handler", true + end if + textEndGroup + + unlock screen +end scriptComment + +# Desription +# Uncomments the selected text +command scriptUncomment + local tStartLine, tEndLine, tStartChar, tText + commentGetDetails tStartLine, tEndLine, tStartChar, tText + if tStartLine is empty then + exit scriptUncomment + end if + + lock screen + -- allow environment with no dependencies + local tCommentChar + put __GetPreference("editor,commentchar", "--") into tCommentChar + + local tUncommentedText + + local tCommentCharLength + put the length of tCommentChar into tCommentCharLength + + repeat for each line tLine in tText + # Remove the first comment char that appears on the line + local tOffset + put offset(tCommentChar, tLine) into tOffset + if tOffset is 0 then + put tLine & return after tUncommentedText + next repeat + end if + + # Only remove the comment char if there is nothing significant before it + # MM-2012-09-28: [[ Bug 10162 ]] Make sure we include lines with chars before the comment in the uncommented text. + local tPreviousChars + put char 1 to (tOffset - 1) of tLine into tPreviousChars + if matchText(tPreviousChars, "^\s*$") then + if char tOffset + tCommentCharLength of tLine is space then + delete char tOffset + tCommentCharLength of tLine + end if + put char 1 to (tOffset - 1) of tLine & char (tOffset + tCommentCharLength) to -1 of tLine & return after tUncommentedText + else + put tLine & return after tUncommentedText + end if + end repeat + delete the last char of tUncommentedText + + # Apply the mutation to the field + textBeginGroup "Uncomment" + textReplace tStartChar, tText, tUncommentedText + + # Restore the selection + select char tStartChar to tStartChar + length(tUncommentedText) of field "Script" + + # OK-2009-03-03 : Bug 7537 - Reformat the handler after commenting, this may be flawed, + # but the proper solution is rather time-consuming. + -- allow environment with no dependencies + local tAutoFormat + put __GetPreference("editor,autoformat", true) into tAutoFormat + + if tAutoFormat then + scriptFormat "handler", true + end if + textEndGroup + + unlock screen +end scriptUncomment + +# Parameters +# pOption : one of three possible strings, see below for details. +# pValue : depends on pOption, details below. +# Description +# Colorizes the current script. pOption is one of the following options. +# "script" - colorize the whole script (default). pValue is ignored. +# "line" - colorize a particular line, pValue is the line number +# "handler" - colorize a particular handler, pValue is the handler name. Currently not implemented. +command scriptColorize pOption, pValue + if pOption is "script" then + _internal script colorize char 1 to (the number of chars of field "Script" of me) of field "Script" of me + else if pOption is "line" then + _internal script colorize line pValue to pValue of field "Script" of me + end if +end scriptColorize + +# Parameters +# pScope : either "script" or "handler" +# Description +# Formats the current script according to the pScope parameter. If pScope is "script", then +# entire script is formatted. If pScope is handler, then the current handler is formatted. +# Note, formatting the whole script could be quite slow. +command scriptFormat pScope, pDontGroup + lock screen + local tScroll + put the vScroll of field "Script" of me into tScroll + + local tStart, tEnd + get the selectedChunk + put word 2 of it into tStart + put word 4 of it into tEnd + + if pScope is "script" then + local tStartChar + put 1 into tStartChar + + local tOldText + put the text of field "Script" of me into tOldText + + local tFirstLine, tLastLine, tCharsAboveFirstLineOld, tCharsAboveLastLineOld + get the selectedLine + put word 2 of it into tFirstLine + if word 4 of it is a number then put word 4 of it into tLastLine else put tFirstLine into tLastLine + + put the number of chars of line 1 to tFirstLine of tOldText into tCharsAboveFirstLineOld + if tFirstLine is tLastLine then + put tCharsAboveFirstLineOld into tCharsAboveLastLineOld + else + put the number of chars of line 1 to tLastLine of tOldText into tCharsAboveLastLineOld + end if + + local tNewText + put textFormatSelection(tOldText) into tNewText + + local tCharsAboveFirstLineNew, tCharsAboveLastLineNew, tDiffFirstLine, tDiffLastLine + put the number of chars of line 1 to tFirstLine of tNewText into tCharsAboveFirstLineNew + if tFirstLine is tLastLine then + put tCharsAboveFirstLineNew into tCharsAboveLastLineNew + else + put the number of chars of line 1 to tLastLine of tNewText into tCharsAboveLastLineNew + end if + + put tCharsAboveFirstLineOld - tCharsAboveFirstLineNew into tDiffFirstLine + put tCharsAboveLastLineOld - tCharsAboveLastLineNew into tDiffLastLine + + local tFirstLineChar + put (the number of chars of line 1 to tFirstLine - 1 of tNewText) + 1 into tFirstLineChar + + textReplace tStartChar, tOldText, tNewText, empty, pDontGroup + + if tStart is not empty then + subtract tDiffFirstLine from tStart + put max(tStart, tFirstLineChar) into tStart # dont let selection go into previous line + subtract tDiffLastLine from tEnd + select char tStart to tEnd of field "Script" of me + end if + + else # handler only + local tLine + put word 2 of the selectedLine into tLine + + local tScript + put the text of the selectedField into tScript + + local tSelectionLineCount + put the number of lines of char tStart to tEnd of tScript into tSelectionLineCount + + # Before doing the formatting, save the indent of the first and last line of the selection. + # Once the formatting is done, we can compare this with the new indents in order to adjust the selection. + local tOldFirstIndent + put textFormatGetLineIndent(line tLine of tScript) into tOldFirstIndent + + local tOldLastIndent + if tStart > tEnd then + put tOldFirstIndent into tOldLastIndent + else + put textFormatGetLineIndent(line (tLine + tSelectionLineCount - 1) of tScript) into tOldLastIndent + end if + + local tCode + put textFormat(tLine, tSelectionLineCount, tScript) into tCode + textReplace tCode["startchar"], tCode["oldtext"], tCode["newtext"], empty, pDontGroup + + local tNewScript + put the text of field "Script" of me into tNewScript + + # We know that formatting cannot change the number of lines of the field, so we can assume that + # tLine will still be corrrect. (tStart and tEnd now no longer point to meaningful chars in the new script.) + local tNewFirstIndent + put textFormatGetLineIndent(line tLine of tNewScript) into tNewFirstIndent + + local tNewLastIndent + if tStart > tEnd then + put tNewFirstIndent into tNewLastIndent + else + # Note that we use the line count from the original selection, as we know this is correct, rather than calculating + # it again for the new selection. + put textFormatGetLineIndent(line (tLine + tSelectionLineCount) of tNewScript) into tNewLastIndent + end if + + # The selection offsets are composed of two parts, the difference in the indent of the line that the selection started / ended on + # and the difference in the number of chars before that line. + local tFirstSelectionOffset + put (the number of chars of line 1 to tLine of tNewScript - the number of chars of line 1 to tLine of tScript) into tFirstSelectionOffset + + put (the number of chars of line 1 to tLine - 1 of tNewScript) + 2 into tFirstLineChar + if tLine is 1 then subtract 1 from tFirstLineChar + + local tLastSelectionOffset + if tStart > tEnd then + put tFirstSelectionOffset into tLastSelectionOffset + else + put(the number of chars of line 1 to (tLine + (tSelectionLineCount - 1)) of tNewScript \ + - the number of chars of line 1 to (tLine + (tSelectionLineCount - 1)) of tScript) into tLastSelectionOffset + end if + + if tStart is not empty then + if tStart > tEnd then + select char (tStart + tFirstSelectionOffset ) to (tEnd + tFirstSelectionOffset ) of field "Script" of me + else + put tStart + tFirstSelectionOffset into tStart + if tStart < tFirstLineChar + (the number of chars of tNewFirstIndent) then + put tFirstLineChar + (the number of chars of tNewFirstIndent) into tStart + end if + select char (tStart) to (tEnd + tLastSelectionOffset) of field "Script" of me + end if + end if + end if + + set the vScroll of field "Script" of me to tScroll + unlock screen +end scriptFormat + +# Description +# Returns the number of the selected line in the current script +command getSelectedLine + return word 2 of the selectedLine +end getSelectedLine + + +# Parameters +# pObject : the object to get the script of. Must be one of the current target objects +# Description +# If pObject is not specified then returns the current script in the editor group, +# otherwise returns the script of the specified object in the state it was last left in +# by the user. I.e. if the script is not applied, the edited one is returned. +command scriptGet pObject + if pObject is empty or revRuggedId(pObject) is revRuggedId(sObjectID) then + return textGetScript() + end if + + # If not the current script, we need to retrieve the script from a cache, as it + # is no longer in the field. + local tCachedScript + put sScriptCache[revRuggedId(pObject)] into tCachedScript + if tCachedScript is empty and exists(pObject) then + return the script of pObject + else + return tCachedScript + end if +end scriptGet + +command scriptGetCache pObject + return sScriptCache[revRuggedId(pObject)] +end scriptGetCache + +command cacheScript pObject, pScript + if exists(pObject) then + put pScript into sScriptCache[revRuggedId(pObject)] + end if +end cacheScript + +# Description +# Returns the number of lines of the current script +command scriptGetLineCount + return the number of lines of field "Script" of me +end scriptGetLineCount + +# Description +# This command returns the current script as *real* html. The result of this command +# is suitable for displaying in a browser, not in Revolution fields as htmlText. This command +# requires the colorization scheme "Revolution Classic" to be used as it contains hard-coded +# replacements. For html suitable for printing or displaying in a Revolution field see scriptGetHtmlText. +command scriptGetAsHtml + local tOldScript + put the text of field "Script" of me into tOldScript + + # First wrap the script to the required width, this is a total hack as doing it properly would take quite a while. + local tScript + put tOldScript into tScript + + local tMaxCharCount + put "65" into tMaxCharCount + + local tWrappedScript + repeat for each line tLine in tScript + # Ignore lines that don't need to be wrapped + if the number of chars of tLine <= tMaxCharCount then + put tLine & return after tWrappedScript + next repeat + end if + + # Find the word offset to wrap from. Only whole words can be wrapped + local tWordOffset + put (the number of words of char 1 to tMaxCharCount of tLine) -1 into tWordOffset + + # The line could be a comment, in which case we need to find which comment char its using + # wrap the line, and put the comment char in front of the wrapped part. This won't work with + # multi-line comments etc. + local tCommentChar + if token 1 of tLine is empty then + local tOffset + put offset("#", tLine) into tOffset + if tOffset = 0 then + put offset("--", tLine) into tOffset + put "--" into tCommentChar + else + put "#" into tCommentChar + end if + + if tCommentChar is empty then + put word 1 to tWordOffset of tLine & return & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript + else + put word 1 to tWordOffset of tLine & return & tCommentChar & space & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript + end if + next repeat + end if + + # The line was not a comment. In this case we just wrap it with a continuation char + # This of course may have issues if the line already has a continuation char, is inside a nested comment etc. + if token 1 of tLine is not empty then + put word 1 to tWordOffset of tLine & " \" & return & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript + next repeat + end if + end repeat + delete the last char of tWrappedScript + + textReplace 1, tOldScript, tWrappedScript + scriptFormat "script" + + local tHtml + put the htmlText of field "Script" of me into tHtml + + local tNewHtml + put "<div class=" & quote & "code" & quote & ">" & return into tNewHtml + put "<pre>" & return after tNewHtml + + local tBody + put tHtml into tBody + replace "<p>" with empty in tBody + replace "</p>" with empty in tBody + + replace "<font color=" & quote & "#000000" & quote & ">" with "<span class=" & quote & "normal" & quote & ">" in tBody + replace "<font color=" & quote & "#0000FF" & quote & ">" with "<span class=" & quote & "command" & quote & ">" in tBody + replace "<font color=" & quote & "#FF0000" & quote & ">" with "<span class=" & quote & "property" & quote & ">" in tBody + replace "<font color=" & quote & "#68228B" & quote & ">" with "<span class=" & quote & "comment" & quote & ">" in tBody + replace "<font color=" & quote & "#F88017" & quote & ">" with "<span class=" & quote & "function" & quote & ">" in tBody + replace "<font color=" & quote & "#980517" & quote & ">" with "<span class=" & quote & "keyword" & quote & ">" in tBody + replace "</font>" with "</span>" in tBody + put tBody & return after tNewHtml + + put "</pre>" & return after tNewHtml + put "</div>" after tNewHtml + + + # Restore the original script + textReplace 1, the text of field "Script" of me, tOldScript + + return tNewHtml +end scriptGetAsHtml + +# Description +# Returns the htmlText of the script field. This is suitable for printing, or displaying +# in another Revolution field, not for putting on the net. For real html, see scriptGetAsHtml. +command scriptGetHtmlText + return the htmlText of field "Script" of me +end scriptGetHtmlText + +# Description +# Returns the long id of the script field. This is required by the Revolution printing library, +# the field ID is used to determine the properties require to make the printout look correct. +# Please *do not* use this command to directly access the script field, doing so will break the +# script editor completely. +command scriptGetField + return the long id of field "Script" of me +end scriptGetField + +# Description +# Returns the name of the current handler. This is the handler that the caret +# is inside in edit mode, or that the current statement to execute is in in +# debug mode. +command scriptGetCurrentHandler + # Waiting for engine support for this function... +end scriptGetCurrentHandler + + +private command __BracketCompletion pOffset, @xOldText, @xNewText + local tBracketCompletion + put __GetPreference("editor,bracketcompletion", true) into tBracketCompletion + if tBracketCompletion is not true then + return empty for value + end if + + if the length of xNewText is not 1 then + return empty for value + end if + + local tNextChar + put char pOffset of field "script" of me into tNextChar + + local tCompletionChar + switch xNewText + case quote + if tNextChar is not quote then + put quote into tCompletionChar + end if + break + case "[" + put "]" into tCompletionChar + break + case "(" + put ")" into tCompletionChar + break + end switch + + if tCompletionChar is not empty then + if xOldText is empty then + put tCompletionChar after xNewText + return "pair" for value + else + put xOldText & tCompletionChar after xNewText + return "wrap" for value + end if + else if xOldText is empty then + if xNewText is in quote & "])" and \ + xNewText is tNextChar then + put xNewText into xOldText + end if + end if + return empty for value +end __BracketCompletion + +local sHighlightedBrackets + +private command __ClearHighlights + if sHighlightedBrackets["open"] is not empty then + set the backgroundColor of char sHighlightedBrackets["open"] of field "script" of me to empty + set the backgroundColor of char sHighlightedBrackets["close"] of field "script" of me to empty + delete variable sHighlightedBrackets + end if +end __ClearHighlights + +private command __CheckHighlights + lock screen + __ClearHighlights + + local tBracketHighlighting + put __GetPreference("editor,brackethighlighting", true) into tBracketHighlighting + + if not tBracketHighlighting then + exit __CheckHighlights + end if + + local tChunk + put the selectedChunk into tChunk + if word 4 of tChunk < word 2 of tChunk then + local tChar, tCharNum + put word 2 of tChunk into tCharNum + put char tCharNum of field "script" of me into tChar + if tChar is in "([])" then + __HighlightBrackets tCharNum, tChar + else + put word 4 of tChunk into tCharNum + put char tCharNum of field "script" of me into tChar + if tChar is in "([])" then + __HighlightBrackets tCharNum, tChar + end if + end if + end if + + unlock screen +end __CheckHighlights + +private command __HighlightBrackets pCharNum, pChar + local tMatchedCharNum + put pCharNum into tMatchedCharNum + switch pChar + case "[" + __LookForPair "]", "[", 1, tMatchedCharNum + break + case "(" + __LookForPair ")", "(", 1, tMatchedCharNum + break + case "]" + __LookForPair "[", "]", -1, tMatchedCharNum + break + case ")" + __LookForPair "(",")", -1, tMatchedCharNum + break + end switch + + if it and pCharNum is not tMatchedCharNum then + local tColor + put __GetPreference("editor,brackethighlightcolor", "255,200,200") into tColor + + put pCharNum into sHighlightedBrackets["open"] + set the backgroundColor of char pCharNum of field "script" of me to tColor + put tMatchedCharNum into sHighlightedBrackets["close"] + set the backgroundColor of char tMatchedCharNum of field "script" of me to tColor + end if +end __HighlightBrackets + +private command __LookForPair pChar, pPairChar, pStep, @xCharNum + local tBracketCount = 0 + local tEndCondition + + local tScript + local tScriptLine + local tCharNum + local tIndex + if pStep < 0 then + put 1 into tEndCondition + put char 1 to xCharNum of field "script" of me into tScript + split tScript by return + put tScript[the number of elements of tScript] into tScriptLine + + repeat with tIndex = the number of elements in tScript-1 down to 1 + if lineIsContinued(tScript[tIndex]) then + put tScript[tIndex] & return before tScriptLine + else + exit repeat + end if + end repeat + + put the length of tScriptLine into tCharNum + else + put char xCharNum+1 to -1 of field "script" of me into tScript + split tScript by return + put tScript[1] into tScriptLine + + repeat with tIndex = 1 to the number of elements in tScript + if lineIsContinued(tScript[tIndex]) then + put return & tScript[tIndex+1] after tScriptLine + else + exit repeat + end if + end repeat + + put the length of tScriptLine into tEndCondition + put 0 into tCharNum + end if + + if tScriptLine is empty or tCharNum is tEndCondition then + return false for value + end if + + repeat + add pStep to tCharNum + add pStep to xCharNum + local tChar + put codepoint tCharNum of tScriptLine into tChar + switch + case tChar is pChar and tBracketCount is 0 + return true for value + break + case tChar is pPairChar + add 1 to tBracketCount + break + case tChar is pChar + subtract 1 from tBracketCount + break + end switch + + if tCharNum is tEndCondition then + return false for value + end if + end repeat +end __LookForPair + + +-- autocompletion + +private command __UpdateAutoCompleteList pUUID + local tProviderCompletion + put __GetPreference("editor,providercompletion", true) into tProviderCompletion + if tProviderCompletion and revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteUpdate the long id of me, sObjectID, sPlaceholders[pUUID]["classes"] + end if +end __UpdateAutoCompleteList + +-- placeholders + +private command __ClearCurrentPlaceholder pForce + if not pForce then + if the selectedField is empty or \ + the long id of the selectedField is not the long id of field "script" of me then + exit __ClearCurrentPlaceholder + end if + local tChunk + put the selectedChunk into tChunk + if exists(tChunk) then + local tUUID + put the metadata of tChunk into tUUID + if tUUID is sEditPlaceholder then + exit __ClearCurrentPlaceholder + end if + end if + end if + + delete variable sPlaceholders[sEditPlaceholder] + + if the number of elements of sEditChunks > 0 then + repeat for each element tChunk in sEditChunks + set the metadata of char tChunk["start"] to tChunk["end"] of field "script" of me to empty + set the backgroundColor of char tChunk["start"] to tChunk["end"] of field "script" of me to empty + end repeat + delete variable sEditChunks + end if + delete variable sEditPlaceholder +end __ClearCurrentPlaceholder + +private command __SelectPlaceholder pUUID, pFromParagraph, pToParagraph, pStyledText + if pFromParagraph is empty then + put 1 into pFromParagraph + end if + + if pToParagraph is empty then + put -1 into pToParagraph + end if + + local tUUID, tChunk + put the selectedChunk into tChunk + if exists(tChunk) then + put the metadata of tChunk into tUUID + end if + + local tOffset + put the number of chars of line 1 to pFromParagraph-1 of field "script" of me into tOffset + if pFromParagraph is not 1 then + add 1 to tOffset + end if + + if pStyledText is empty then + put the styledText of line pFromParagraph to pToParagraph of field "script" of me into pStyledText + end if + + local tScroll + put the vScroll of field "script" of me into tScroll["v"] + put the hScroll of field "script" of me into tScroll["h"] + lock screen + + delete variable sEditChunks + put pUUID into sEditPlaceholder + + local tColor + put __GetPreference("editor,placeholdercolor", kPlaceholderDefaultBackgroundColor) into tColor + + local tParagraphIndex + repeat with tParagraphIndex = 1 to the number of elements of pStyledText + local tRunIndex + repeat with tRunIndex = 1 to the number of elements of pStyledText[tParagraphIndex]["runs"] + if pUUID is pStyledText[tParagraphIndex]["runs"][tRunIndex]["metadata"] then + put the effective hiliteColor of field "Script" of me \ + into pStyledText[tParagraphIndex]["runs"][tRunIndex]["style"]["backgroundColor"] + local tPlaceholderNum + put the number of elements of sEditChunks + 1 into tPlaceholderNum + put tOffset+1 into sEditChunks[tPlaceholderNum]["start"] + put tOffset+the length of pStyledText[tParagraphIndex]["runs"][tRunIndex]["text"] into sEditChunks[tPlaceholderNum]["end"] + else if pStyledText[tParagraphIndex]["runs"][tRunIndex]["metadata"] is not empty then + if pStyledText[tParagraphIndex]["runs"][tRunIndex]["text"] is space or \ + pStyledText[tParagraphIndex]["runs"][tRunIndex]["metadata"] is tUUID then + delete variable sPlaceholders[pStyledText[tParagraphIndex]["runs"][tRunIndex]["metadata"]] + delete variable pStyledText[tParagraphIndex]["runs"][tRunIndex]["metadata"] + delete variable pStyledText[tParagraphIndex]["runs"][tRunIndex]["style"]["backgroundColor"] + else + put tColor into pStyledText[tParagraphIndex]["runs"][tRunIndex]["style"]["backgroundColor"] + end if + end if + add the length of pStyledText[tParagraphIndex]["runs"][tRunIndex]["text"] to tOffset + end repeat + add 1 to tOffset + end repeat + + set the styledText of line pFromParagraph to pToParagraph of field "script" of me to pStyledText + set the vScroll of field "script" of me to tScroll["v"] + set the hScroll of field "script" of me to tScroll["h"] + + if the number of elements of sEditChunks > 0 then + -- select the first chunk + select char sEditChunks[1]["start"] to sEditChunks[1]["end"] of field "script" of me + else if exists(tChunk) then + select tChunk + end if +end __SelectPlaceholder + +command SelectNextPlaceholder pChar, pFromParagraph, pToParagraph + local tStyle + + local tPlaceholdersToDelete + + put the styledText of line pFromParagraph to pToParagraph of field "script" of me into tStyle + local tParagraphIndex + repeat with tParagraphIndex = 1 to the number of elements of tStyle + local tRunOffset + put 0 into tRunOffset + local tRunIndex + repeat with tRunIndex = 1 to the number of elements of tStyle[tParagraphIndex]["runs"] + if tParagraphIndex > 1 or (tParagraphIndex is 1 and (tRunOffset + 1) >= pChar) then + if tStyle[tParagraphIndex]["runs"][tRunIndex]["metadata"] is not empty and \ + tStyle[tParagraphIndex]["runs"][tRunIndex]["metadata"] is not sEditPlaceholder then + if tStyle[tParagraphIndex]["runs"][tRunIndex]["text"] is not space then + __SelectPlaceholder \ + tStyle[tParagraphIndex]["runs"][tRunIndex]["metadata"], \ + pFromParagraph, \ + pToParagraph, \ + tStyle + selectionUpdate + return true + else + get the number of elements of tPlaceholdersToDelete + put tRunOffset + 1,pFromParagraph + tParagraphIndex - 1 into \ + tPlaceholdersToDelete[it + 1] + end if + end if + end if + add the length of tStyle[tParagraphIndex]["runs"][tRunIndex]["text"] to tRunOffset + end repeat + end repeat + + repeat for each key tUUID in tPlaceholdersToDelete + repeat for each element tRange in tPlaceholdersToDelete[tUUID] + set the metadata of char (item 1 of tRange) of line (item 2 of tRange) of field "script" of me to empty + set the backgroundColor of char (item 1 of tRange) of line (item 2 of tRange) of field "script" of me to empty + end repeat + delete variable sPlaceholders[tUUID] + end repeat + + -- if we get here we thought there were placeholders and there weren't + -- so select after the line and clear the placeholder variable + select after line pFromParagraph of field "script" of me + selectionUpdate + + return false +end SelectNextPlaceholder diff --git a/Toolset/palettes/script editor/behaviors/revsedocumentationpanebehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsedocumentationpanebehavior.livecodescript index ddeb670f81..e5755d4c8b 100644 --- a/Toolset/palettes/script editor/behaviors/revsedocumentationpanebehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsedocumentationpanebehavior.livecodescript @@ -1,7 +1,7 @@ script "revSEDocumentationPaneBehavior" # String representing the last searched for doc, this is what the cDoc was last set to local sDoc = "" -local sTypesA +local sTypesA, sLibsA # String returned by the last Documentation search, this can be used to reload the last doc. local sLastFoundDoc = "" @@ -135,6 +135,9 @@ private function renderDocDataShort pData, pIndex put tData["display name"] into tName put tData["syntax"] into tSyntax put tData["summary"] into tSummary + if tSummary is empty then + put tData["description"] into tSummary + end if put tData["type"] into tType local tResult @@ -273,7 +276,7 @@ private function renderDocData pData, pIndex, pFull return tHtml end renderDocData -private command renderDoc pType +private command renderDoc pType, pLib if sLastFoundDoc is empty or sDoc is empty then renderEmpty exit renderDoc @@ -281,7 +284,7 @@ private command renderDoc pType # Documentation library: Retrieve the summary from the docs database local tHTML - put renderDocDictionary(sDoc, pType) into tHTML + put renderDocDictionary(sDoc, pType, pLib) into tHTML set the htmlText of field "View" of me to tHTML scrollbarCheck @@ -312,27 +315,33 @@ private function removeAngleBrackets pText, pIsSyntax end removeAngleBrackets # Returns HTML of that doc in the form required for this component -private function renderDocDictionary pTag, pType +private function renderDocDictionary pTag, pType, pLib local tResult, tData # Get the required info from the doc - put ideDocsFetchLCSData(pTag) into tData - + put ideDocsFetchScriptData(pTag) into tData + if pType is empty then put sTypesA[pTag] into pType end if + if pLib is empty then + put sLibsA[pTag] into pLib + end if put pType into sTypesA[pTag] + put pLib into sLibsA[pTag] - if pType is not empty then - repeat for each key tIndex in tData - if tData[tIndex]["type"] is pType then - return renderDocEntry(tData, tIndex) - end if - end repeat - end if + repeat for each key tIndex in tData + if pType is not empty and \ + tData[tIndex]["type"] is pType and \ + pLib is not empty and \ + tData[tIndex]["library"] is pLib then + return renderDocEntry(tData, tIndex) + end if + end repeat put tData[1]["type"] into sTypesA[pTag] + put tData[1]["library"] into sLibsA[pTag] return renderDocEntry(tData, 1) end renderDocDictionary @@ -345,13 +354,18 @@ private function renderDocEntry pData, pIndex end renderDocEntry function renderDocAlternatives pAlternatives, pCurIndex - local tFormattedAlternatives, tAlternative - repeat for each key tAlternativeIndex in pAlternatives + local tFormattedAlternatives, tAlternative, tAlternativeIndices + put the keys of pAlternatives into tAlternativeIndices + sort tAlternativeIndices by pAlternatives[each]["type"] + sort tAlternativeIndices by pAlternatives[each]["library"] + repeat for each line tAlternativeIndex in tAlternativeIndices if tAlternativeIndex is pCurIndex then next repeat end if - put "<a>" & pAlternatives[tAlternativeIndex]["type"] & "</a>" into tAlternative + put "<a>" & pAlternatives[tAlternativeIndex]["library"] && \ + "-" && pAlternatives[tAlternativeIndex]["type"] & "</a>" \ + into tAlternative if tFormattedAlternatives is empty then put tAlternative into tFormattedAlternatives @@ -372,7 +386,8 @@ private command scrollbarCheck end scrollbarCheck on linkClicked pLink - renderDoc pLink + set the itemdelimiter to "-" + renderDoc word 1 to -1 of item 2 of pLink, word 1 to -1 of item 1 of pLink end linkClicked function prefGet pTag @@ -390,7 +405,7 @@ on mouseUp break case "LaunchDocs" - revIDEGoToLCSDictionaryEntry sDoc, sTypesA[sDoc] + revIDEGoToLCSDictionaryEntry sDoc, sTypesA[sDoc], sLibsA[sDoc] break end switch end mouseUp diff --git a/Toolset/palettes/script editor/behaviors/revseeditorbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revseeditorbehavior.livecodescript index ec830c0218..137604e788 100644 --- a/Toolset/palettes/script editor/behaviors/revseeditorbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revseeditorbehavior.livecodescript @@ -6,52 +6,11 @@ # The map is updated whenever scriptCompile is called. local sHandlerMap -# The following variables store information used for the undo / redo system. -local sTextOperationOffsets -local sTextOperationNewTexts -local sTextOperationOldTexts -local sTextOperationIndex - -local sTextOperationTop - -local sTextGroupLabels -local sTextGroupLengths -local sTextGroupIndex -local sTextGroupTop - -local sTextGutterNumbers -local sTextGutterOverlay -local sTextGutterLastNumber - -local sTextFormatKeywordMap - -local sTextMark - # These two variables store which object the current search was started on, and which# # object the most recent result was found in respectively. local sFirstFindObject local sLastFindObject -# OK-2009-01-17 : Bug 7169 - Store whether scripts are "dirty" or not, i.e whether the user has actually -# modified them, as opposed to they were modified by the script editor. (This can happen in the case of template scripts) -local sDirty - -################################################################################ -# -# Editor object interface, please do not call any commands / functions outside the -# following section. -# -################################################################################ - -# OK-2009-01-17 : Bug 7169 -command setDirty pObject, pValue - put pValue into sDirty[pObject] -end setDirty - -command getDirty pObject - return sDirty[pObject] -end getDirty - constant kMinGutterWidth = 16 # Description @@ -137,7 +96,6 @@ command resize end resize -local sObjectId local sUniqueId # Description @@ -145,9 +103,9 @@ local sUniqueId # Initializes the group. Note that this is also called when there are no more # objects to edit, this may happen when the user has removed the last object # from the script editor. This is the reason why this command saves the previous -# context before putting empty into sObjectId. +# context before putting empty into getObjectID(). command initialize - if sObjectId is not empty then + if getObjectID() is not empty then contextSave end if @@ -156,6 +114,7 @@ command initialize call "initialize" to group "Gutter" of me set the backgroundColor of field "Script" of me to sePrefGet("editor,backgroundcolor") + setHandlersFieldBackColor set the hScrollbar of field "Script" of me to (sePrefGet("editor,hscrollbar") is "true") -- See bug 16773. Mac likes an odd scrollbarwidth, @@ -172,12 +131,20 @@ command initialize call "openControl" to group "Interactive Find" of me end if - put empty into sObjectId + setObjectID empty put 0 into sUniqueId unlock screen end initialize +private command setHandlersFieldBackColor + if there is a field "Handlers" of group "Left Handler List" of group "Left Bar" \ + of card "Main" of this stack then + set the backgroundColor of field "Handlers" of group "Left Handler List" of group "Left Bar" \ + of card "Main" of this stack to sePrefGet("editor,backgroundcolor") + end if +end setHandlersFieldBackColor + private command initializeFonts local tFont, tFontSize put sePrefGet("editor,font") into tFont @@ -219,6 +186,7 @@ command reapplyPreferences scriptColorize "script" set the backgroundColor of field "Script" of me to sePrefGet("editor,backgroundcolor") + setHandlersFieldBackColor set the hScrollbar of field "Script" of me to (sePrefGet("editor,hscrollbar") is "true") updateGutterRequest empty, empty, empty, empty, false, false, true @@ -226,9 +194,6 @@ command reapplyPreferences unlock screen end reapplyPreferences -# Stores an array of cached object scripts for switching back to objects with unsaved changes -local sScriptCache - local sLastSelections # Description @@ -238,32 +203,30 @@ local sLastSelections # in memory as a script local. Thus full selections are remembered when switching tabs, but only # the location of the selection is remembered when opening a new tab or after restarting rev. private command contextSave - revMetadataSet sObjectId, "general", "scripteditorvscroll", the vScroll of field "Script" of me + revMetadataSet getObjectID(), "general", "scripteditorvscroll", the vScroll of field "Script" of me if the long id of the focusedObject is the long id of field "Script" of me then get the selectedChunk - put word 2 of it & comma & word 4 of it into sLastSelections[sObjectId] - revMetadataSet sObjectId, "general", "scripteditorselection", word 4 of it + put word 2 of it & comma & word 4 of it into sLastSelections[getObjectID()] + revMetadataSet getObjectID(), "general", "scripteditorselection", word 4 of it end if end contextSave -local sLastSelectedChunk - # Description # Loads the previously saved context for for current object if one was saved. private command contextLoad local tSelection - if sLastSelections[sObjectId] is not empty then + if sLastSelections[getObjectID()] is not empty then # If there is a last selection stored in memory, this means the user has previously opened this object # and is just changing tabs. In this case we remember the entire selection. - put sLastSelections[sObjectId] into tSelection + put sLastSelections[getObjectID()] into tSelection else # If there is no last selection in memory, this means either the user didnt select anything, or they # have not opened the object yet. In this case we only remember the location of the selection, not what was selected. # This information is stored as object metadata. In previous versions of the script editor, both the selection start and end # were stored, but this was changed to store only the selection end. This change is what warrants the extra check. - put revMetadataGet(sObjectId, "general", "scripteditorselection") into tSelection + put revMetadataGet(getObjectID(), "general", "scripteditorselection") into tSelection # In case the object was last edited with an older version, get rid of any excess selection info. if the number of items of tSelection > 1 then @@ -280,12 +243,12 @@ private command contextLoad select char (item 1 of tSelection) to (item 2 of tSelection) of field "Script" of me # OK-2009-01-17 : Bug 7601 - Update sLastSelectedChunk here as it will be incorrect until the first selectionChanged message is triggered - put tSelection into sLastSelectedChunk + setLastSelectedChunk tSelection end try end if local tScroll - put revMetadataGet(sObjectId, "general", "scripteditorvscroll") into tScroll + put revMetadataGet(getObjectID(), "general", "scripteditorvscroll") into tScroll if tScroll is not empty then set the vScroll of field "Script" of me to tScroll @@ -324,77 +287,32 @@ command loadScript end if local tCachedScript - put sScriptCache[sObjectId] into tCachedScript + scriptGetCache getObjectID() + put the result into tCachedScript + lock screen if tCachedScript is not empty then # If there is a cached script, this means that the user is coming back to this object from another tab. textSetScriptRaw tCachedScript else - # If the object has no script, get the default script for it, otherwise the current script is used - if the script of sObjectId is not empty then - local tScript - put the script of sObjectId into tScript - - textSetScriptRaw tScript - - # OK-2008-07-07 : Bug 6746 - seUpdateCheckSum sObjectId, tScript - else - # AL-2015-09-21: Tweaked logic for default script - local tType, tStyle - put word 1 of the name of sObjectID into tType - if tType is among the items of "button,field,stack,graphic,scrollbar" then - put the style of sObjectId into tStyle - else if tType is "widget" then - put the kind of sObjectID into tStyle - else -- groups, cards, images and players have no style property so just pass empty - put empty into tStyle - end if - - local tDefaultScript - put seDefaultScript(tType, tStyle) into tDefaultScript - textSetScriptRaw tDefaultScript - - local tDefaultSelection - put seDefaultScriptSelection(tType, tStyle) into tDefaultSelection - - # OK-2008-08-19 : When a default script is put into an object, the object should be marked as modified - # in the script editor, as the script in the field is not the same as the object's actual script. - if tDefaultScript is not empty then - seSetObjectState sObjectId, "edited" - end if - - # OK-2008-07-07 : Bug 6746 - When a default script was loaded, it means the object's actual script was empty, - # therefore the checksum should represent this. - local tEmpty - put empty into tEmpty - seUpdateChecksum sObjectId, tEmpty - - if tDefaultSelection is not empty then - # Try is needed here to allow the IDE to add objects to a script editor before opening it - try - select char (item 1 of tDefaultSelection) to (item 2 of tDefaultSelection) of field "Script" of me - - # OK-2009-01-17 : Bug 7601 - When a script is first loaded, slastSelectedChunk may be empty - # or incorrect as the user has not yet done a selection to trigger selectedChanged and update it. - put tDefaultSelection into sLastSelectedChunk - end try - else - select before field "Script" of me - end if + local tScript + put the script of getObjectID() into tScript + + textSetScriptRaw tScript + + # OK-2008-07-07 : Bug 6746 + seUpdateCheckSum getObjectID(), tScript + if tScript is empty then + select before field "Script" of me end if end if - # Only load the previous context if we didn't use the default script and default selection, - # otherwise these will get overriden and the selection will be wrong. - if tDefaultSelection is empty then - # The lock messages is required, because otherwise an exitField is received before the contextLoad - # can execute, causing the context to be overwritten just before we load it. Not currently sure why - # this happens... - lock messages - contextLoad - unlock messages - end if + # The lock messages is required, because otherwise an exitField is received before the contextLoad + # can execute, causing the context to be overwritten just before we load it. Not currently sure why + # this happens... + lock messages + contextLoad + unlock messages # As we have changed the selection, update the rest of the script editor to reflect this --selectionUpdateRequest @@ -403,6 +321,43 @@ command loadScript selectionUpdate end loadScript +command selectionUpdate + lock screen + findClearResults + if the lockText of field "Script" of me is false then + deSelectLastGoneToLine + end if + + # Tell the script editor to update its panes. This is called here in particular + # for the documentation pane to update itself when the user selects a new term. + paneUpdateRequest + + # Update the variables that store the last selected line and handler list + updateHandlerList + + updateSelectedHandler + + contextSave + + # Update the toolbar so that the handlers list can reflect the new selection. For efficiency we pass + # a parameter to the update command which tells it that the selected handler can be assumed to be + # up to date, so it doesn't need to evaluate it again (as we just updated it). + local tTrueString + put "true" into tTrueString + + # OK-2009-10-05: Optimized this a little. The previous call to update was doing quite a bit of stuff + # that is not required here. I factored out the stuff that we actually need into a new method, which + # is now called instead. + -- send "update tTrueString" to group "Toolbar" of stack (revTargetStack(the long id of me)) + send "updateSelectedHandler tTrueString" to group "Toolbar" of stack (revTargetStack(the long id of me)) + # Update the left bar in the same way as the toolbar is updated + # OK-2009-10-05: Some more optimization here, the update method was doing a lot of stuff that is not + # needed, so I added a more specific method to handle this situation. + send "updateSelectedHandler" to group "Left Bar" of stack (revTargetStack(the long id of me)) + unlock screen + pass selectionUpdate +end selectionUpdate + # Parameters # pObjectId : reference to the object to set the script to. Must be one of the target objects of the script editor. # Description @@ -411,18 +366,18 @@ command setObject pObjectId, pDontSendCallbacks local tRuggedObjectId put seGetRuggedId(pObjectId) into tRuggedObjectId - if sObjectId is not empty and tRuggedObjectId is sObjectId then + if getObjectID() is not empty and tRuggedObjectId is getObjectID() then if not pDontSendCallbacks then - seSendCallbacks sObjectId, the name of stack (revTargetStack(the long id of me)) + seSendCallbacks getObjectID(), the name of stack (revTargetStack(the long id of me)) end if exit setObject end if # If we are closing a previous object and the script has not been applied, # cache the script of the previous object internally, and save the context - if sObjectId is not empty then - put textGetScript() into sScriptCache[sObjectId] - if there is a sObjectId then + if getObjectID() is not empty then + cacheScript getObjectID(), textGetScript() + if there is a getObjectID() then contextSave end if end if @@ -436,14 +391,14 @@ command setObject pObjectId, pDontSendCallbacks findClearResults - EditorFieldCacheSwap sObjectId, tRuggedObjectId - put tRuggedObjectId into sObjectId + EditorFieldCacheSwap getObjectID(), tRuggedObjectId + setObjectID tRuggedObjectId loadScript resize unlock screen if not pDontSendCallbacks then - seSendCallbacks sObjectId, the name of stack (revTargetStack(the long id of me)) + seSendCallbacks getObjectID(), the name of stack (revTargetStack(the long id of me)) end if end setObject @@ -451,7 +406,7 @@ end setObject # Reverts the script of the current object to the last applied version command revertObject loadScript - seSetObjectState sObjectId, "applied" + seSetObjectState getObjectID(), "applied" end revertObject # Parameters @@ -462,114 +417,32 @@ end revertObject # its rugged id. It should not be called outside this situation as stuff will break. command setObjectRaw pObjectId local tOldObjectId - put sObjectId into tOldObjectId + put getObjectID() into tOldObjectId - put seGetRuggedId(pObjectId) into sObjectId + setObjectID pObjectId if tOldObjectId is empty then exit setObjectRaw end if - # If there was a previous object and we are changing its id, then we have to update all the script locals - # that may contain references to the old object. This is rather ugly, but it allows things like undo to work - # even when objects are moved. - local tStateData - - # Script cache, stores unapplied scripts when tabs are changed - updateArrayKey sScriptCache, tOldObjectId, sObjectId - - # Undo stuff - updateMultiItemArrayKey sTextOperationOffsets, tOldObjectId, sObjectId, 44, 1 - updateMultiItemArrayKey sTextOperationOldTexts, tOldObjectId, sObjectId, 44, 1 - updateMultiItemArrayKey sTextOperationNewTexts, tOldObjectId, sObjectId, 44, 1 - updateArrayKey sTextOperationTop, tOldObjectId, sObjectId - updateArrayKey sTextOperationIndex, tOldObjectId, sObjectId - - updateMultiItemArrayKey sTextGroupLabels, tOldObjectId, sObjectId, 44, 1 - updateMultiItemArrayKey sTextGroupLengths, tOldObjectId, sObjectId, 44, 1 - updateArrayKey sTextGroupIndex, tOldObjectId, sObjectId - updateArrayKey sTextGroupTop, tOldObjectId, sObjectId - updateArrayKey sTextMark, tOldObjectId, sObjectId + updateObjectID tOldObjectID, getObjectID() # Find results if sLastFindObject is tOldObjectId then - put sObjectId into sLastFindObject + put getObjectID() into sLastFindObject end if if sFirstFindObject is tOldObjectId then - put sObjectId into sFirstFindObject + put getObjectID() into sFirstFindObject end if end setObjectRaw - -# Parameters -# pArray : reference to an array. This gets modified -# pOldKey : one of the array keys -# pNewKey : the new key to replace pOldKey with -# Description -# Removes the element pOldKey from the array, and creates -# a new element pNewKey with the same data. Essentially renaming the key. -# If the element is empty, does nothing. -private command updateArrayKey @pArray, pOldKey, pNewKey - local tData - if pArray[pOldKey] is not empty then - put pArray[pOldKey] into tData - delete variable pArray[pOldKey] - put tData into pArray[pNewKey] - end if -end updateArrayKey - -# Parameters -# pArray : reference to an array. This gets modified -# pOldKey : one of the array keys -# pNewKey : the new key to replace pOldKey with -# pDelimiter : an ascii char code that delimits dimensions in the array's key. If empty, comma is assumed. -# pItemNumer : which item number of the key needs to match pOldKey -# Description -# Removes all keys with the specified dimension matching pOldKey from the array -# and replaces them with equivalent keys matching pNewKey. -private command updateMultiItemArrayKey @pArray, pOldKey, pNewKey, pDelimiter, pItemNumber - local tData - - if pDelimiter is not empty then - set the itemDelimiter to numToChar(pDelimiter) - end if - - # Create a list of keys that need to be modified - local tKeys - repeat for each line tKey in the keys of pArray - if item pItemNumber of tKey is pOldKey then - put tKey & return after tKeys - end if - end repeat - delete the last char of tKeys - - if tKeys is empty then - exit updateMultiItemArrayKey - end if - - # Apply the modification to the keys - repeat for each line tKey in tKeys - local tNewKey - put tKey into tNewKey - put pNewKey into item pItemNumber of tNewKey - put pArray[tKey] into pArray[tNewKey] - delete variable pArray[tKey] - end repeat -end updateMultiItemArrayKey - # Description # Returns a reference to the current object being edited. command getObject - return sObjectId + return getObjectID() end getObject -# Description -# Returns the number of the selected line in the current script -command getSelectedLine - return word 2 of the selectedLine -end getSelectedLine - # Parameters # pDontUpdate : if true, the selected handler is assumed to be up to date and the stored one is just returned. # Description @@ -654,13 +527,7 @@ command getHandlerList end getHandlerList private command updateHandlerList - # The script is compiled before updating the handler list. We temporarily turn off - # variable checking before this. - local tOldVarChecking - put sePrefGet("explicitVariables") into tOldVarChecking - sePrefSet "explicitVariables", "false" - scriptCompile sObjectId - sePrefSet "explicitVariables", tOldVarChecking + scriptCompile getObjectID() end updateHandlerList # Parameters @@ -675,163 +542,38 @@ command clearCache pObject, pDontCheckId else put seGetRuggedId(pObject) into tObject end if - delete variable sScriptCache[tObject] delete variable sLastSelections[tObject] -end clearCache - ---command revertCache pObject --- local tObject --- put seGetRuggedId(pObject) into tObject --- delete variable sLastSelections[tObject] --- put the script of tObject into sScriptCache[tObject] ---end revertCache - -# Description -# Returns the last known token that the caret was placed into. This is not done properly -# at the moment as it depends on the syntax, for now we just return something sensible. -command getCaretToken pUseClick - local tScript - put the text of getScriptField() into tScript - - # Don't return tokens in comments. For now we determine if the user is typing - # in a comment by simple means, using proper tokenization is not yet possible. - # This means that multi-line comments will break this. - local tLine - if pUseClick then - put word 2 of the clickLine into tLine - else - put word 2 of the selectedLine of getScriptField() into tLine - end if - if token 1 of line tLine of tScript is empty then - return empty - end if - - local tSelectedText - if pUseClick then - put the clickText into tSelectedText - else - put the selectedText of getScriptField() into tSelectedText - # OK-2008-06-22 : Bug 8054 - pUseClick is only set if we are building a context menu, so in this case - # do the expansion anyway to try and get a whole token. - if tSelectedText is not empty then - return tSelectedText - end if - end if - - # This is expanded to include tokens that the caret was placed immediately before or after, - # the reason for this is that it allows us to begin searching for tokens while the user is typing. - local tFrom, tTo - if pUseClick then - get the clickChunk - else - get the selectedChunk - end if - put word 2 of it into tFrom - put word 4 of it into tTo - - # We can't perfectly match tokens at the moment, so we just make a reasonable guess with a regular expression - # to match any char that delimits a token. - ## AL-2014-01-15: [[ Bug 11094 ]] Added # to the list of script editor token delimiters - local tExpression - put "\s|[\%\^\&\*\(\)\-\+\=\]\]\;\,\\@\\\/\<\>\#]" into tExpression - - # Try looking backwards first - local tText, tChar - repeat with x = (tFrom - 1) down to 1 - put char x of tScript into tChar - if matchText(tChar, tExpression) then - exit repeat - end if - put tChar before tText - end repeat - - # Try looking forwards - repeat with x = tFrom to the number of chars of tScript - put char x of tScript into tChar - if matchText(tChar, tExpression) then - exit repeat - end if - put tChar after tText - end repeat - - return tText -end getCaretToken - -local slastNonEmptySelection - -command getLastSelection - return slastNonEmptySelection -end getLastSelection - -command getLastSelectedWord - local tFrom, tTo - put item 1 of sLastSelectedChunk into tFrom - put item 2 of sLastSelectedChunk into tTo - # If there is a non empty selection, just return that. - if tTo > tFrom then - return char tFrom to tTo of the text of getScriptField() - end if - - # If the selection is in the middle of a word, then return that. - # First loop back from the selected character to find the first part of the word. Keep going until we find a character - # that is either whitespace, or a bracket. - local tWordDivider - put merge("^[\[[quote]]|\[|\]\(|\)|\s]$") into tWordDivider - - local tBefore - repeat with x = tTo down to 1 - get char x of the text of getScriptField() - if matchText(it, tWordDivider) then - exit repeat - end if - put it before tBefore - end repeat - - local tAfter - repeat with x = tTo + 1 to the number of chars of the text of getScriptField() - get char x of the text of getScriptField() - if matchText(it, tWordDivider) then - exit repeat - end if - put it after tAfter - end repeat - - local tWord - put tBefore & tAfter into tWord - return tWord -end getLastSelectedWord + pass clearCache +end clearCache # Description # Locks the script to prevent the uesr from editing it. Used by the debugger. command scriptLock set the lockText of field "Script" of me to true set the backgroundColor of field "Script" of me to sePrefGet("editor,debugBackgroundcolor") + set the backgroundColor of field "Handlers" of group "Left Handler List" of group "Left Bar" \ + of card "Main" of this stack to sePrefGet("editor,debugBackgroundcolor") end scriptLock -# Returns -# Whether or not the script is locked -private function scriptLocked - return the lockText of field "Script" of me -end scriptLocked - # Description # Unlocks the script, allowing the user to edit it. command scriptUnlock set the lockText of field "Script" of me to false set the backgroundColor of field "Script" of me to sePrefGet("editor,backgroundColor") + setHandlersFieldBackColor end scriptUnlock # Returns # Whether or not the current object script is password protected. private function scriptProtected # Prevent errors when editing the script editor. - if sObjectId is empty then + if getObjectID() is empty then return false end if local tStack - put revTargetStack(sObjectId) into tStack + put revTargetStack(getObjectID()) into tStack # think this may be wrong... -- if the passKey of stack tStack is not the password of stack tStack then @@ -852,166 +594,11 @@ end scriptProtected # Shows error indicators for the specified compilation errors command setCompilationErrors pErrors, pObject send "setCompilationErrors pErrors, pObject" to group "Gutter" of me - if seGetRuggedId(pObject) is sObjectId then + if seGetRuggedId(pObject) is getObjectID() then updateGutterRequest empty, empty, empty, empty, false, true end if end setCompilationErrors -# Parameters -# rStartLine : receives the line number that the current selection begins on -# rEndLine : receices the line number that the current selection ends on -# rStartChar : receives the char that the curent selection starts on -# rText : receives the block of text that will be commented or uncommented. -# Description -# This command obtains the details required to comment / uncomment a block of code -# it is used by the scriptComment and scriptUncomment commands. -private command commentGetDetails @rStartLine, @rEndLine, @rStartChar, @rText - # Calculate the chunk of text that the commenting will be applied to - local tStartLine, tEndLine - get the selectedLine - put word 2 of it into tStartLine - if word 3 of it is "to" then - put word 4 of it into tEndLine - end if - - # Adjust the chunk so that we have only complete lines by searching from the beginning - # backwards to the next return char. Don't bother doing this for the end as this doesn't matter. - get the selectedChunk - local tCurrentStart - put word 2 of it into tCurrentStart - - local tStartChar - - if tStartLine = 1 then - put 1 into tStartChar - else - local tPreviousChars - put char 1 to (tCurrentStart - 1) of field "Script" of me into tPreviousChars - - local tOffset - put 0 into tOffset - repeat with x = the number of chars of tPreviousChars down to 1 - if char x of tPreviousChars is return then - exit repeat - end if - add 1 to tOffset - end repeat - #subtract 1 from tOffset - - put tCurrentStart - tOffset into tStartChar - end if - - # Get the text and add in the comments - local tText - if tEndLine is empty then - put line tStartLine of field "Script" of me into tText - else - put line tStartLine to tEndLine of field "Script" of me into tText - end if - - put tStartChar into rStartChar - put tStartLine into rStartLine - put tEndLine into rEndLine - put tText into rText -end commentGetDetails - -# Description -# Comments out the selected text -command scriptComment - local tStartLine, tEndLine, tStartChar, tText - commentGetDetails tStartLine, tEndLine, tStartChar, tText - if tStartLine is empty then - exit scriptComment - end if - - lock screen - - local tCommentChar - put sePrefGet("editor,commentchar") & space into tCommentChar - - local tCommentedText - repeat for each line tLine in tText - # Don't comment out empty lines as it looks messy - if not matchText(tLine, "^\s*$") then - put tCommentChar before tLine - end if - put tLine & return after tCommentedText - end repeat - delete the last char of tCommentedText - - # Apply the mutation to the field - textMark "Insert" - textReplace tStartChar, tText, tCommentedText - - # Restore the selection - select char tStartChar to tStartChar + length(tCommentedText) of field "Script" - - # OK-2009-03-03 : Bug 7537 - Reformat the handler after commenting, this may be flawed, - # but the proper solution is rather time-consuming. - if sePrefGet("editor,autoformat") then - scriptFormat "handler" - end if - - unlock screen -end scriptComment - -# Desription -# Uncomments the selected text -command scriptUncomment - local tStartLine, tEndLine, tStartChar, tText - commentGetDetails tStartLine, tEndLine, tStartChar, tText - if tStartLine is empty then - exit scriptUncomment - end if - - lock screen - local tCommentChar - put sePrefGet("editor,commentchar") into tCommentChar - local tUncommentedText - - local tCommentCharLength - put the length of tCommentChar into tCommentCharLength - - repeat for each line tLine in tText - # Remove the first comment char that appears on the line - local tOffset - put offset(tCommentChar, tLine) into tOffset - if tOffset is 0 then - put tLine & return after tUncommentedText - next repeat - end if - - # Only remove the comment char if there is nothing significant before it - # MM-2012-09-28: [[ Bug 10162 ]] Make sure we include lines with chars before the comment in the uncommented text. - local tPreviousChars - put char 1 to (tOffset - 1) of tLine into tPreviousChars - if matchText(tPreviousChars, "^\s*$") then - if char tOffset + tCommentCharLength of tLine is space then - delete char tOffset + tCommentCharLength of tLine - end if - put char 1 to (tOffset - 1) of tLine & char (tOffset + tCommentCharLength) to -1 of tLine & return after tUncommentedText - else - put tLine & return after tUncommentedText - end if - end repeat - delete the last char of tUncommentedText - - # Apply the mutation to the field - textMark "Insert" - textReplace tStartChar, tText, tUncommentedText - - # Restore the selection - select char tStartChar to tStartChar + length(tUncommentedText) of field "Script" - - # OK-2009-03-03 : Bug 7537 - Reformat the handler after commenting, this may be flawed, - # but the proper solution is rather time-consuming. - if sePrefGet("editor,autoformat") then - scriptFormat "handler" - end if - - unlock screen -end scriptUncomment - # OK-2009-03-03 : Bug 7450 # Parameters # pName : the name of a handler @@ -1090,126 +677,6 @@ private function convertTypeCodeToSyntax pTypeCode end switch end convertTypeCodeToSyntax -# Parameters -# pOption : one of three possible strings, see below for details. -# pValue : depends on pOption, details below. -# Description -# Colorizes the current script. pOption is one of the following options. -# "script" - colorize the whole script (default). pValue is ignored. -# "line" - colorize a particular line, pValue is the line number -# "handler" - colorize a particular handler, pValue is the handler name. Currently not implemented. -command scriptColorize pOption, pValue - if pOption is "script" then - _internal script colorize char 1 to (the number of chars of field "Script" of me) of field "Script" of me - else if pOption is "line" then - _internal script colorize line pValue to pValue of field "Script" of me - end if -end scriptColorize - -# Formats the specified script snippet. -command scriptFormatSnippet pScript - textFormatInitialize - local tNewScript - put textFormatSelection(pScript) into tNewScript - return tNewScript -end scriptFormatSnippet - - -# Parameters -# pScope : either "script" or "handler" -# Description -# Formats the current script according to the pScope parameter. If pScope is "script", then -# entire script is formatted. If pScope is handler, then the current handler is formatted. -# Note, formatting the whole script could be quite slow. -command scriptFormat pScope, pDontGroup - lock screen - local tScroll - put the vScroll of field "Script" of me into tScroll - - local tStart, tEnd - get the selectedChunk - put word 2 of it into tStart - put word 4 of it into tEnd - - if pScope is "script" then - local tStartChar - put 1 into tStartChar - - local tOldText - put the text of field "Script" of me into tOldText - - local tNewText - put textFormatSelection(tOldText) into tNewText - textReplace tStartChar, tOldText, tNewText, empty, pDontGroup - - if tStart is not empty then - select char tStart to tEnd of field "Script" of me - end if - - else # handler only - local tLine - put word 2 of the selectedLine into tLine - - local tScript - put the text of the selectedField into tScript - - local tSelectionLineCount - put the number of lines of char tStart to tEnd of tScript into tSelectionLineCount - - # Before doing the formatting, save the indent of the first and last line of the selection. - # Once the formatting is done, we can compare this with the new indents in order to adjust the selection. - local tOldFirstIndent - put textFormatGetLineIndent(line tLine of tScript) into tOldFirstIndent - - local tOldLastIndent - if tStart > tEnd then - put tOldFirstIndent into tOldLastIndent - else - put textFormatGetLineIndent(line (tLine + tSelectionLineCount) of tScript) into tOldLastIndent - end if - - local tCode - put textFormat(tLine, tSelectionLineCount, tScript) into tCode - textReplace tCode["startchar"], tCode["oldtext"], tCode["newtext"], empty, pDontGroup - - local tNewScript - put the text of field "Script" of me into tNewScript - - # We know that formatting cannot change the number of lines of the field, so we can assume that - # tLine will still be corrrect. (tStart and tEnd now no longer point to meaningful chars in the new script.) - local tNewFirstIndent - put textFormatGetLineIndent(line tLine of tNewScript) into tNewFirstIndent - - local tNewLastIndent - if tStart > tEnd then - put tNewFirstIndent into tNewLastIndent - else - # Note that we use the line count from the original selection, as we know this is correct, rather than calculating - # it again for the new selection. - put textFormatGetLineIndent(line (tLine + tSelectionLineCount) of tNewScript) into tNewLastIndent - end if - - # The selection offsets are composed of two parts, the difference in the indent of the line that the selection started / ended on - # and the difference in the number of chars before that line. - local tFirstSelectionOffset - put (the number of chars of tNewFirstIndent - the number of chars of tOldFirstIndent) + (the number of chars of line 1 to (tLine - 1) of tNewScript - the number of chars of line 1 to (tLine - 1) of tScript) into tFirstSelectionOffset - - local tLastSelectionOffset - if tStart > tEnd then - put tFirstSelectionOffset into tLastSelectionOffset - else - put (the number of chars of tNewLastIndent - the number of chars of tOldLastIndent) + (the number of chars of line 1 to (tLine + tSelectionLineCount) of tNewScript - the number of chars of line 1 to (tLine + tSelectionLineCount) of tScript) into tLastSelectionOffset - end if - - if tStart is not empty then - select char (tStart + tFirstSelectionOffset) to (tEnd + tLastSelectionOffset) of field "Script" of me - end if - end if - - set the vScroll of field "Script" of me to tScroll - unlock screen -end scriptFormat - # Parameters # pObject : reference to the object to compile the script of. Must be one of the target objects. # Description @@ -1233,13 +700,52 @@ command scriptCompile pObject put the result into tScript local tResult + local tDoUpdateDescription set the script of button "revCompileObject" of me to tScript put the result into tResult + -- if setting the script failed with explicit vars try without + if tResult is not empty and the explicitVariables then + set the explicitVariables to false + set the script of button "revCompileObject" of me to tScript + put the result is empty into tDoUpdateDescription + else + put tResult is empty into tDoUpdateDescription + end if - if tResult is empty then + if tDoUpdateDescription then + --! TODO remove use of revAvailableHandlers here (quite invasive) put the revAvailableHandlers of button "revCompileObject" of me into sHandlerList + get getObjectID() + if exists(it) and revEnvironmentEditionProperty("autocomplete") then + ideAutocompleteUpdateScriptDescription it, the revScriptDescription of button "revCompileObject" of me + end if end if + local tLiveErrors + put sePrefGet("editor,liveerrors") into tLiveErrors + put tLiveErrors and not the lockText of field "script" of me into tLiveErrors + + local tState + getDirty pObject + if the result then + put "edited" into tState + else + put "applied" into tState + end if + + if tLiveErrors then + send "clearErrors" to group "Errors" of the owner of me + if tResult is empty then + setCompilationErrors empty, pObject + else + send "addError compilation, line 1 of tResult, pObject" to group "Errors" of the owner of me + setCompilationErrors line 1 of tResult, pObject + put "error" into tState + end if + end if + + seSetObjectState pObject, tState + set the preserveVariables to tOldPreserveVariables set the explicitVariables to tOldExplicitVariables @@ -1252,150 +758,6 @@ command scriptCompile pObject return tResult end scriptCompile -# Parameters -# pObject : the object to get the script of. Must be one of the current target objects -# Description -# If pObject is not specified then returns the current script in the editor group, -# otherwise returns the script of the specified object in the state it was last left in -# by the user. I.e. if the script is not applied, the edited one is returned. -command scriptGet pObject - if pObject is empty or seGetRuggedId(pObject) is seGetRuggedId(sObjectId) then - return textGetScript() - end if - - # If not the current script, we need to retrieve the script from a cache, as it - # is no longer in the field. - local tCachedScript - put sScriptCache[seGetRuggedId(pObject)] into tCachedScript - if tCachedScript is empty then - return the script of pObject - else - return tCachedScript - end if -end scriptGet - -# Description -# Returns the number of lines of the current script -command scriptGetLineCount - return the number of lines of field "Script" of me -end scriptGetLineCount - -# Description -# This command returns the current script as *real* html. The result of this command -# is suitable for displaying in a browser, not in Revolution fields as htmlText. This command -# requires the colorization scheme "Revolution Classic" to be used as it contains hard-coded -# replacements. For html suitable for printing or displaying in a Revolution field see scriptGetHtmlText. -command scriptGetAsHtml - local tOldScript - put the text of field "Script" of me into tOldScript - - # First wrap the script to the required width, this is a total hack as doing it properly would take quite a while. - local tScript - put tOldScript into tScript - - local tMaxCharCount - put "65" into tMaxCharCount - - local tWrappedScript - repeat for each line tLine in tScript - # Ignore lines that don't need to be wrapped - if the number of chars of tLine <= tMaxCharCount then - put tLine & return after tWrappedScript - next repeat - end if - - # Find the word offset to wrap from. Only whole words can be wrapped - local tWordOffset - put (the number of words of char 1 to tMaxCharCount of tLine) -1 into tWordOffset - - # The line could be a comment, in which case we need to find which comment char its using - # wrap the line, and put the comment char in front of the wrapped part. This won't work with - # multi-line comments etc. - local tCommentChar - if token 1 of tLine is empty then - local tOffset - put offset("#", tLine) into tOffset - if tOffset = 0 then - put offset("--", tLine) into tOffset - put "--" into tCommentChar - else - put "#" into tCommentChar - end if - - if tCommentChar is empty then - put word 1 to tWordOffset of tLine & return & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript - else - put word 1 to tWordOffset of tLine & return & tCommentChar & space & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript - end if - next repeat - end if - - # The line was not a comment. In this case we just wrap it with a continuation char - # This of course may have issues if the line already has a continuation char, is inside a nested comment etc. - if token 1 of tLine is not empty then - put word 1 to tWordOffset of tLine & " \" & return & word tWordOffset + 1 to -1 of tLine & return after tWrappedScript - next repeat - end if - end repeat - delete the last char of tWrappedScript - - textReplace 1, tOldScript, tWrappedScript - scriptFormat "script" - - local tHtml - put the htmlText of field "Script" of me into tHtml - - local tNewHtml - put "<div class=" & quote & "code" & quote & ">" & return into tNewHtml - put "<pre>" & return after tNewHtml - - local tBody - put tHtml into tBody - replace "<p>" with empty in tBody - replace "</p>" with empty in tBody - - replace "<font color=" & quote & "#000000" & quote & ">" with "<span class=" & quote & "normal" & quote & ">" in tBody - replace "<font color=" & quote & "#0000FF" & quote & ">" with "<span class=" & quote & "command" & quote & ">" in tBody - replace "<font color=" & quote & "#FF0000" & quote & ">" with "<span class=" & quote & "property" & quote & ">" in tBody - replace "<font color=" & quote & "#68228B" & quote & ">" with "<span class=" & quote & "comment" & quote & ">" in tBody - replace "<font color=" & quote & "#F88017" & quote & ">" with "<span class=" & quote & "function" & quote & ">" in tBody - replace "<font color=" & quote & "#980517" & quote & ">" with "<span class=" & quote & "keyword" & quote & ">" in tBody - replace "</font>" with "</span>" in tBody - put tBody & return after tNewHtml - - put "</pre>" & return after tNewHtml - put "</div>" after tNewHtml - - - # Restore the original script - textReplace 1, the text of field "Script" of me, tOldScript - - return tNewHtml -end scriptGetAsHtml - -# Description -# Returns the htmlText of the script field. This is suitable for printing, or displaying -# in another Revolution field, not for putting on the net. For real html, see scriptGetAsHtml. -command scriptGetHtmlText - return the htmlText of field "Script" of me -end scriptGetHtmlText - -# Description -# Returns the long id of the script field. This is required by the Revolution printing library, -# the field ID is used to determine the properties require to make the printout look correct. -# Please *do not* use this command to directly access the script field, doing so will break the -# script editor completely. -command scriptGetField - return the long id of field "Script" of me -end scriptGetField - -# Description -# Returns the name of the current handler. This is the handler that the caret -# is inside in edit mode, or that the current statement to execute is in in -# debug mode. -command scriptGetCurrentHandler - # Waiting for engine support for this function... -end scriptGetCurrentHandler # Description # Shows the interactive find dialog and focuses the appropriate control for the user to enter text. @@ -1412,28 +774,6 @@ command hideInteractiveFind send "closeControl" to group "Interactive Find" of me end hideInteractiveFind -# Description -# Returns whether or not undo is available in the current object. I.e. the script has been edited since it was opened in this -# instance of the script editor. -command undoAvailable - if sTextGroupIndex[sObjectId] is 0 then - return false - else - return true - end if -end undoAvailable - -# Description -# Returns whether or not redo is available in the current object. I.e. something has been undone since it was opened in -# this instance of the script editor. -command redoAvailable - if sTextGroupIndex[sObjectId] is sTextGroupTop[sObjectId] then - return false - else - return true - end if -end redoAvailable - ################################################################################ # # End of editor object interface. Code below here is part of the object's internal @@ -1519,2436 +859,392 @@ private function arrayShow pArray end arrayShow command textInitialize - put empty into field "Script" of me - put empty into sTextOperationOffsets - put empty into sTextOperationNewTexts - put empty into sTextOperationOldTexts - put 0 into sTextOperationIndex - put 0 into sTextOperationTop - - put empty into sTextGroupLabels - put empty into sTextGroupLengths - put 0 into sTextGroupIndex - put 0 into sTextGroupTop - - put empty into sTextMark - put empty into sScriptCache - initializeFonts - textFormatInitialize seColorizationInit colorizationUpdate - textMark "Insert" - EditorFieldCacheFlushAll + + pass textInitialize end textInitialize -on textMark pLabel - put pLabel into sTextMark[sObjectId] -end textMark - -on textBeginGroup pLabel, pObject - local tObject - if pObject is empty then - put sObjectId into tObject - else - put pObject into tObject - end if - - add 1 to sTextGroupIndex[tObject] +# Description +# Updates the gutter according to the specified parameters. +command updateGutterDo + local tOffset, tSelectedLine, tOldLines, tNewLines, tTextChanged - put pLabel into sTextGroupLabels[tObject,sTextGroupIndex[tObject]] - put 0 into sTextGroupLengths[tObject,sTextGroupIndex[tObject]] + local tDetails + put getUpdateGutterRequestDetails() into tDetails + put tDetails["offset"] into tOffset + put tDetails["selectedLine"] into tSelectedLine + put tDetails["oldLines"] into tOldLines + put tDetails["newLines"] into tNewLines + put tDetails["textChanged"] into tTextChanged - repeat with tIndex = sTextGroupIndex[tObject] + 1 to sTextGroupTop[tObject] - delete variable sTextGroupLabels[tObject,tIndex] - delete variable sTextGroupLengths[tObject,tIndex] - end repeat + local tUpdateCompilationErrors + put tDetails["updateCompilationErrors"] into tUpdateCompilationErrors - repeat with tIndex = sTextOperationIndex[tObject] + 1 to sTextOperationTop[tObject] - delete variable sTextOperationOffsets[tObject,tIndex] - delete variable sTextOperationNewTexts[tObject,tIndex] - delete variable sTextOperationOldTexts[tObject,tIndex] - end repeat + local tForceBreakpointRedraw + put tDetails["forceBreakpointRedraw"] into tForceBreakpointRedraw - put sTextOperationIndex[sObjectId] into sTextOperationTop[tObject] - put sTextGroupIndex[sObjectId] into sTextGroupTop[tObject] + send "update tOffset, tSelectedLine, tOldLines, tNewLines, tTextChanged, tUpdateCompilationErrors, tForceBreakpointRedraw" to group "Gutter" of me - put empty into sTextMark[tObject] -end textBeginGroup - -on textEndGroup - if sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] = 0 then - throw "empty_text_group_inserted" - end if - textMark "Insert" -end textEndGroup - --- Text Formatting Code -private command textFormatInitialize - local tTabDepth - put sePrefGet("editor,tabdepth") into tTabDepth - - put "0," & tTabDepth into sTextFormatKeywordMap["try"] - put "0," & tTabDepth into sTextFormatKeywordMap["switch"] - put "0," & tTabDepth into sTextFormatKeywordMap["if"] - put -tTabDepth & ",0" into sTextFormatKeywordMap["endif"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["elseif"] - put "0," & tTabDepth into sTextFormatKeywordMap["repeat"] - - put "0," & tTabDepth into sTextFormatKeywordMap["on"] - put "0," & tTabDepth into sTextFormatKeywordMap["function"] - put "0," & tTabDepth into sTextFormatKeywordMap["setprop"] - put "0," & tTabDepth into sTextFormatKeywordMap["getprop"] - put "0," & tTabDepth into sTextFormatKeywordMap["command"] - put "0," & tTabDepth into sTextFormatKeywordMap["private"] - put "0," & tTabDepth into sTextFormatKeywordMap["before"] - put "0," & tTabDepth into sTextFormatKeywordMap["after"] - - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["else"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["case"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["default"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["catch"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["finally"] - put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["catch"] - --put -tTabDepth & comma & tTabDepth into sTextFormatKeywordMap["break"] - put 0 & comma & 0 into sTextFormatKeywordMap["break"] - - put -tTabDepth & ",0" into sTextFormatKeywordMap["end"] -end textFormatInitialize - -private function textFormatIndentLineAdds pLine - local tToken - put token 1 of pLine into tToken - if tToken is "if" then - if "else" is among the words of pLine then - return 0 - else if token -1 of pLine is not "then" then - return 0 - else - return item 2 of sTextFormatKeywordMap["if"] - end if - - else if tToken is "else" then - if token 2 of pLine is "if" then - if "else" is among the words of word 3 to -1 of pLine then - return 0 - else if token -1 of pLine is not "then" then - return 0 - else - return item 2 of sTextFormatKeywordMap["elseif"] - end if - else if token 2 of pLine is not empty then - return 0 - else - return item 2 of sTextFormatKeywordMap["else"] - end if - - else if token 1 of pLine is empty then - return 0 - ## Bug 10467 - else in a comment was causing incorrect indentation - ## Check for "else" in line without comments - --else if token 1 of pLine is not "else" and "else" is among the words of pLine then - else if token 1 of pLine is not "else" and "else" is among the words of lineStripComments(pLine) then - return -sePrefGet("editor,tabdepth") - else if token -1 of pLine is "then" then - # Either a weirdly formatted if structure, or the condition of the if contained a line continuation character. - # In this case, behave as though pLine is a normal if. - return item 2 of sTextFormatKeywordMap["if"] - else - return item 2 of sTextFormatKeywordMap[tToken] - end if - return 0 -end textFormatIndentLineAdds - - -private function textFormatIndentLineRemoves pPreviousLine, pLine - local tToken - put token 1 of pLine into tToken - if tToken is "else" then - if token 2 of pLine is "if" then - if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" then - return 0 - else - return item 1 of sTextFormatKeywordMap["elseif"] - end if - - else - if "then" is among the words of pPreviousLine and token -1 of pPreviousLine is not "then" then - return 0 - else - return item 1 of sTextFormatKeywordMap["else"] - end if - end if - else if tToken is empty then - # Comments and empty lines do not remove any formatting - return 0 - else if tToken is "end" and token 2 of pLine is "switch" and token 1 of pPreviousLine is not "switch" then - # Special case for end switch if there is a preceeding "break", "default" or other statement, we need to remove - # double the normal indent. - return (2 * item 1 of sTextFormatKeywordMap["end"]) - else if tToken is "case" then - # A case statement removes indent from the previous line in all cases except if the - # previous line was the beginning of the parent switch structure. - if token 1 of pPreviousLine is "switch" then - return 0 - else - return item 1 of sTextFormatKeywordMap["case"] - end if - # OK-2009-04-28 : Bug 8016 - Special case required for "default" to make switches format correctly. - else if tToken is "default" then - if token 1 of pPreviousLine is "switch" then - return 0 - else - return item 1 of sTextFormatKeywordMap["default"] - end if - else if tToken is "end" and token 2 of pLine is not among the words of "if switch repeat try" and not lineIsContinued(pLine) then - # Handler ends always remove all indentation as they can't be nested - # OK-2009-02-16 : Bug 7707 - We can't assume the previous line was correctly formatted or script may be deleted. - # Instead we simplify this by simply chopping off whatever indentation it did have. - --return min(-(the number of chars of textFormatGetLineIndent(pPreviousLine)), item 1 of sTextFormatKeywordMap[tToken]) - return item 1 of sTextFormatKeywordMap["end"] - else - # We can't assume that the previous line was correctly indented - # because the script might have been edited from outside this script editor. Therefore - # we have to ensure that a line doesnt try to remove more formating than the previous - # line actually had. Otherwise non-whitespace chars may be deleted. - if the number of chars of textFormatGetLineIndent(pPreviousLine) + the number of chars of textFormatGetLineIndent(pLine) + textFormatIndentLineAdds(pPreviousLine) < abs(item 1 of sTextFormatKeywordMap[tToken]) then - return -(the number of chars of textFormatGetLineIndent(pPreviousLine)) - else - return item 1 of sTextFormatKeywordMap[tToken] - end if - end if -end textFormatIndentLineRemoves + # Once an update has been carried out, we reset the sGutterUpdateRequestDetails array + deleteUpdateGutterRequestDetails +end updateGutterDo -private function textFormatGetLineIndent pLine - local tResult - repeat for each char tChar in pLine - if tChar is space then - put space after tResult - else - return tResult - end if - end repeat - return tResult -end textFormatGetLineIndent +################################################################################ -private function lineIsContinued pLine - if word -1 of pLine is "\" then - return true - else - return false +# Description +# Called when the script editor is about to be closed. +command finalize + cancelPendingMessages + + if there is a getObjectID() then + contextSave end if -end lineIsContinued - -private function textFormatGetContinuationIndent pLastLineNumber - # In order to calculate the indentation we need to loop back until we find the start of the continuation, - # constructing a string which is the equivalent of the continued line in a single line. We then use this to calculate - # the indent of the last line -end textFormatGetContinuationIndent + _internal script flush field "Script" of me +end finalize -private function combineContinuedLine pLastLineNumber, @pTextLines - local tContinuation - put pTextLines[pLastLineNumber] into tContinuation - - local tIndex - repeat with tIndex = (pLastLineNumber - 1) down to 1 - if not lineIsContinued( pTextLines[tIndex]) then - exit repeat - end if - - put pTextLines[tIndex] before tContinuation - end repeat - replace "\" with empty in tContinuation - return tContinuation -end combineContinuedLine +# Description +# Sets some state variables that may be needed to update the script editor panes +# and calls the sePanesUpdate command to do the update. +command paneUpdate + sePanesUpdate +end paneUpdate -constant kContinuationIndent = 6 +local sLastSelectedGoneToChunk +local sLastGoneToLine -private function textFormatLine pLine, pTextLines, @xPreviousLine - local tResult +# Parameters +# pLine : a line number to go to, from 1 up to the number of lines in the current script. +# pHighlightMode : How to highlight the specified line. If this is false or not specified, the line is not highlighted. +# Description +# Goes to the specified line and highlights if required. The highlight mode is either false / empty for no highlight +# or "select" to select the line or "color" to set the line's background color. A value of "true" is treated the same +# as "select". +command goLine pLine, pHighlightMode, pPosition + local tScroll + put the vScroll of field "Script" of me into tScroll - # OK-2009-01-30 : Bug 7051 - Deal better with continuation characters. - local tCurrentLineIsContinued - local tPreviousLineWasContinued - local tPreviousPreviousLineWasContinued - - # Continuations can only happen with consecutive lines, there can't be comments or empty lines in between, - # so we simply use the two previous lines to work out if they are continued or not. If these lines are empty - # or are comments, then the result will be that they are not continuations anyway which is correct. - put lineIsContinued(pTextLines[pLine - 1]) into tPreviousLineWasContinued - put lineIsContinued(pTextLines[pLine - 2]) into tPreviousPreviousLineWasContinued - - put lineIsContinued(pTextLines[pLine]) into tCurrentLineIsContinued - - # Get the previous non-empty line - if xPreviousLine is 0 and pLine > 1 then - put pLine into xPreviousLine - repeat while xPreviousLine > 1 - subtract 1 from xPreviousLine - if token 1 of pTextLines[xPreviousLine] is not empty then - exit repeat - end if - end repeat - end if + # OK-2008-08-25 : Bug 7013 - Preserve horizontal scroll + local tHScroll + put the hScroll of field "Script" of me into tHScroll - local tPreviousLine - if xPreviousLine > 0 then - # This is the case where we have reached the end of a continued line. Here, we treat the continued line - # as a single entity in order to calculate its indentation properties correctly for the line after it. - if lineIsContinued(pTextLines[xPreviousLine - 1]) then - put combineContinuedLine(xPreviousLine, pTextLines) into tPreviousLine - else - put pTextLines[xPreviousLine] into tPreviousLine + # Select the line according to the value of pHighlight + lock messages + if pHighlightMode is "true" or pHighlightMode is "select" then + select line pLine of field "Script" of me + get the selectedChunk + put word 2 of it & comma & word 4 of it into sLastSelectedGoneToChunk + else if pHighlightMode is "color" then + set the backgroundColor of line pLine of field "Script" of me to sePrefGet("editor,selectbackgroundcolor") + local tStart + put the number of chars of line 1 to (pLine - 1) of field "Script" of me + 1 into tStart + put tStart & comma & tStart + the number of chars of line pLine of field "Script" of me into sLastSelectedGoneToChunk + else if pHighlightMode is "position" then + # OK-2009-03-03 : Bug 7550 - Allow for particular chars to be highlighted for better error display + local tEnd + put item 1 of pPosition into tStart + put item 2 of pPosition into tEnd + + # As typically Revolution errors only have a start char, and every after that gets ignored, + # if no end is specified, we highlight from the start char to the end of the line. + if tEnd is empty then + put the number of chars of line pLine of field "Script" of me into tEnd end if - # Get the current indent of the previous line - local tPreviousLineIndent - put textFormatGetLineIndent(tPreviousLine) into tPreviousLineIndent - end if - - # Get the current indent of the line - local tCurrentLineIndent - put textFormatGetLineIndent(pTextLines[pLine]) into tCurrentLineIndent - - # Work out how much indentation the current line should remove from the previous line - local tIndentCurrentLineRemoves - if tPreviousLineWasContinued then - put 0 into tIndentCurrentLineRemoves - else - put textFormatIndentLineRemoves(tPreviousLine, pTextLines[pLine]) into tIndentCurrentLineRemoves - end if - - # Work out how much indentation the previous line should add to the current line. - local tIndentPreviousLineAdds - if xPreviousLine is 0 then - put 0 into tIndentPreviousLineAdds - else if tPreviousLineWasContinued then - # we always add the continuation indent because we combined the continued lines - put kContinuationIndent into tIndentPreviousLineAdds + select char tStart to tEnd of line pLine of field "Script" of me + get the selectedChunk + put word 2 of it & comma & word 4 of it into sLastSelectedGoneToChunk + else if pHighlightMode is "after" then + put empty into sLastSelectedGoneToChunk + select after line pLine of field "Script" of me else - put textFormatIndentLineAdds(pTextLines[xPreviousLine]) into tIndentPreviousLineAdds + put empty into sLastSelectedGoneToChunk + select before line pLine of field "Script" of me end if + unlock messages - local tCurrentIndent - repeat (the number of chars of tPreviousLineIndent + tIndentCurrentLineRemoves + tIndentPreviousLineAdds) - put space after tCurrentIndent - end repeat - - put ((the number of chars of tPreviousLineIndent + tIndentCurrentLineRemoves + tIndentPreviousLineAdds) - the number of chars of tCurrentLineIndent) & comma into tResult - - -- Finally, calculate the expected next indent. - local tNewIndent - put tCurrentIndent into tNewIndent - - local tIndentCurrentLineAdds - if tCurrentLineIsContinued and tPreviousLineWasContinued then - put 0 into tIndentCurrentLineAdds - else if tCurrentLineIsContinued and (not tPreviousLineWasContinued) then - put kContinuationIndent into tIndentCurrentLineAdds - else if (not tCurrentLineIsContinued) and tPreviousLineWasContinued then - put -kContinuationIndent into tIndentCurrentLineAdds - else - put textFormatIndentLineAdds(pTextLines[pLine]) into tIndentCurrentLineAdds + # Scroll until the line is centred (assumes fixed line height) + if the vScroll of field "Script" of me > tScroll then + # The field has scrolled down in order to show the selection, therefore + # we need to make it scroll down again to centre it. + set the vScroll of field "Script" of me to the vScroll of field "Script" of me + round(the height of field "Script" of me / 2) + else if the vScroll of field "Script" of me < tScroll then + # The field has scrolled up in order to show the selection, therefore + # we need to make it scroll up again to centre it. + set the vScroll of field "Script" of me to the vScroll of field "Script" of me - round(the height of field "Script" of me / 2) end if - if tIndentCurrentLineAdds < 0 then - repeat -tIndentCurrentLineAdds times - delete char 1 of tNewIndent - end repeat - else - repeat tIndentCurrentLineAdds times - put space after tNewIndent - end repeat - end if + set the hScroll of field "Script" of me to tHScroll - put tNewIndent after tResult + put pLine into sLastGoneToLine - if token 1 of pTextLines[pLine] is not empty then - put pLine into xPreviousLine - end if - return tResult -end textFormatLine + updateGutterRequest empty, empty, empty, empty, false, false +end goLine -# Returns -# The chunk of pLine from the beginning of the first word to the end. -private function firstWordToEnd pLine - local tOffset - put offset(word 1 of pLine, pLine) into tOffset - return char tOffset to -1 of pLine -end firstWordToEnd +function getLastGoneToLine + return sLastGoneToLine +end getLastGoneToLine -# Parameters -# pText : the text to format -private function textFormatSelection pText - local tResult - local tPreviousLine = 0 - local tTextLines - put pText into tTextLines - split tTextLines by return - - get textFormatLine(1, tTextLines, tPreviousLine) - put firstWordToEnd(tTextLines[1]) into tTextLines[1] - put tTextLines[1] into tResult - local tIndex - repeat with tIndex = 2 to the number of elements of tTextLines - put item 2 of it & firstWordToEnd(tTextLines[tIndex]) into tTextLines[tIndex] - get textFormatLine(tIndex, tTextLines, tPreviousLine) +# Description +# Deselects the last line that was selected by the goLine command if there was one +# and it is still selected. +command deselectLastGoneToLine + lock screen + get the selectedChunk + -- MM-2012-06-20: [[ Bug 10027 ]] Make sure there was a last line selected - causes bugs deselects elsewhere within the IDE. + if sLastSelectedGoneToChunk is not empty and word 2 of it is item 1 of sLastSelectedGoneToChunk and word 4 of it is item 2 of sLastSelectedGoneToChunk then - if item 1 of it < 0 then - repeat -(item 1 of it) times - if char 1 of line -1 of tTextLines[tIndex] is space then - delete char 1 of tTextLines[tIndex] - end if - end repeat - else if item 1 of it > 0 then - repeat item 1 of it times - put space before tTextLines[tIndex] - end repeat + lock messages + local tSelobj + put revIDESelectedObjects() into tSelobj + select empty + if tSelobj is not the long id of field "Script" of me then + revIDESelectObjects tSelobj end if + set the backgroundColor of char (item 1 of sLastSelectedGoneToChunk) to (item 2 of sLastSelectedGoneToChunk) of field "Script" of me to empty + unlock messages - put return & tTextLines[tIndex] after tResult - end repeat + end if + put empty into sLastSelectedGoneToChunk - return tResult -end textFormatSelection + # We update the gutter here to remove the current line indicator + updateGutterRequest empty, empty, empty, empty, false, false + unlock screen +end deselectLastGoneToLine -private function handlerTypes - return "command,on,function,setprop,getprop,before,after" -end handlerTypes - -private function textFormat pLineNumber, pLineCount, pText - -- Find the range to format. - -- 1. Search down until we find a handler (a) or the end of one (b). - -- 2. Based on 1, in case a, search up until we find the end of any other handler, or the beginning of the script. - -- In case b we need to search for the start of that handler. - local tEnd - - local tText - put pText into tText - split tText by return - put pLineNumber into tEnd - - # Search down to find what the handler name is and whether pLineNumber is the first line of the handler. - local tHandler - local tFirstLine - put true into tFirstLine - - local tContinuation, tCurrentLineContinues - put lineIsContinued(tText[pLineNumber-1]) into tContinuation - - local tLineIndex - repeat with tLineIndex = pLineNumber to the number of elements of tText - put lineIsContinued(tText[tLineIndex]) into tCurrentLineContinues - if token 1 of tText[tLineIndex] is "end" and token 2 of tText[tLineIndex] is not among the items of "if,repeat,switch,try" and not tContinuation and not tCurrentLineContinues then - put true into tHandler[token 2 of tText[tLineIndex]] - if pLineCount < 0 then - exit repeat - end if - else if token 1 of tText[tLineIndex] is among the items of handlerTypes() and not tFirstLine then - if pLineCount < 0 then - exit repeat - end if - exit repeat - else if token 1 of tText[tLineIndex] is "private" and token 2 of tText[tLineIndex] is among the items of handlerTypes() and not tFirstLine then - if pLineCount < 0 then - exit repeat - end if - exit repeat - else - put tCurrentLineContinues into tContinuation - end if - if tFirstLine then put false into tFirstLine - subtract 1 from pLineCount - add 1 to tEnd - end repeat - - # Search up to find the beginning of the handler, or the beginning of the script if not found. - local tStart - repeat with tLineIndex = pLineNumber down to 1 - put tLineIndex into tStart - if tHandler is an array then - if token 1 of tText[tLineIndex] is among the items of handlerTypes() and tHandler[token 2 of tText[tLineIndex]] then - exit repeat - else if token 1 of tText[tLineIndex] is "private" and token 2 of tText[tLineIndex] is among the items of handlerTypes() and tHandler[token 3 of tText[tLineIndex]] then - exit repeat - end if - else if token 1 of tText[tLineIndex] is "end" and token 2 of tText[tLineIndex] is not among the items of "if,repeat,switch,catch" then - exit repeat - end if - end repeat - - if tHandler is not an array and tStart is not 1 then - add 1 to tStart - end if - if tEnd > the number of elements of tText then - put the number of elements of tText into tEnd - end if - - -- Now format lines tStart to tEnd of pText, and return the result. - local tStartChar - if tStart is 1 then - put 1 into tStartChar - else - put the number of chars of line 1 to (tStart - 1) of pText into tStartChar - add 2 to tStartChar - end if - - local tOldText - put line tStart to tEnd of pText into tOldText - - local tResult - put tStartChar into tResult["startchar"] - put tOldText into tResult["oldtext"] - put textFormatSelection(tOldText) into tResult["newtext"] - - return tResult -end textFormat - -function textGetScript - return the text of field "Script" of me -end textGetScript - -function getScriptField - return the long id of field "Script" of me -end getScriptField - -on textSetSelection pAfterChar - select after char pAfterChar of field "Script" of me -end textSetSelection - -# Parameters -# pOldText : the text replaced in an operation -# pNewText : the replacing text in an operation -# Returns -# Whether or not a new undo group is needed for the specified -# operation. -private function textReplaceNewGroupNeeded pOldText, pNewText - # If the invoker of the replacement operation has specified that an undo group - # is needed, always create one - if sTextMark[sObjectId] is not empty then - return true - end if - - # If the number of chars of either the string replaced or replacing string is above one - # this means it must be a deletion of a selection or a cut or paste. This should always - # require a new group - if the number of chars of pOldText > 1 or the number of chars of pNewText > 1 then - return true - end if - - # If either the text being replaced or the replacing text contain return chars, new group - if pOldText contains return or pNewText contains return then - return true - end if - - return false -end textReplaceNewGroupNeeded - -# Parameters -# pOffset : the char number of where the replacement should start -# pOldText : the text that is being replaced -# pNewText : the text that is being inserted -# pObject : the long id of the object to replace in. If not given, the current object is assumed. -# Description -# This is the point through which all standard editing operations on scripts are sent through. -# Any change made via this function will be added to the undo system. This is called when the -# user types keys, formats text, cuts, pastes etc. -private command textReplace pOffset, pOldText, pNewText, pObject, pDontGroup - local tObject - if pObject is empty then - put sObjectId into tObject - else - put pObject into tObject - end if - - if pDontGroup is not true and textReplaceNewGroupNeeded(pOldText, pNewText) then - textBeginGroup sTextMark[tObject], tObject - end if - - add 1 to sTextOperationIndex[tObject] - add 1 to sTextGroupLengths[tObject,sTextGroupIndex[tObject]] - - put pOffset into sTextOperationOffsets[tObject,sTextOperationIndex[tObject]] - put pOldText into sTextOperationOldTexts[tObject,sTextOperationIndex[tObject]] - put pNewText into sTextOperationNewTexts[tObject,sTextOperationIndex[tObject]] - - # When the script has been edited, the breakpoints should be suspended until it is applied again. - # Because this command is called as the user types, we could a send in time for this, as its not that urgent. - revDebuggerSuspendBreakpoints tObject - - # If the specified object to replace in is the current object being edited, we perform the replace - # directly on the script editing field using textReplaceRaw. Otherwise we perform it on the - # script cache stored for the object. - if tObject is empty or seGetRuggedId(tObject) is sObjectId then - textReplaceRaw pOffset, pOldText, pNewText - else - local tCache - put sScriptCache[seGetRuggedId(tObject)] into tCache - if tCache is empty then - put the script of tObject into tCache - end if - textReplaceRawInVariable tCache, pOffset, pOldText, pNewText - put tCache into sScriptCache[seGetRuggedId(tObject)] - end if - - set the caseSensitive to true - if pOldText is not pNewText then - seSetObjectState tObject, "edited" - - # OK-2009-01-17 : Bug 7169 - Flag the object as dirty when it is modifed by this method only. - # The textReplaceRaw etc functions should not do this as they do not represent a user modifying - # the script. - setDirty tObject, true - end if -end textReplace - -# Parameters -# pOffset : the char number to begin the replacement at -# @rScript : the text to perform the replacement in, gets mutated -# @pOldText : the text that is to be replaced. This is not mutated, its a reference for efficiency reasons -# @pNewText : the text to be inserted. This is not mutated, its a reference for efficiency reasons -# Description -# Performs a raw replace exactly as textReplaceRaw, except in a variable instead of directly in the editing field. -# This is used by replace-all, because it may need to replace text in the script of objects which are not open. -private command textReplaceRawInVariable @rScript, pOffset, @pOldText, @pNewText - local tOldLength - put the length of pOldText into tOldLength - put pNewText into char pOffset to pOffset + tOldLength - 1 of rScript -end textReplaceRawInVariable - -# Parameters -# pOffset : the char number to begin the replacement at -# @pOldText : the text that is to be replaced. This is not mutated, its a reference for efficiency reasons -# @pNewText : the text to be inserted. This is not mutated, its a reference for efficiency reasons -# pDontUpdateBreakpoints : optional, defaults to false. If this is true, breakpoints in the gutter are not moved. -# Description -# This is the raw replacement operation that performs a mutation on the script field without -# saving any undo information. This should be called only from inside textReplace, when doing an undo or a redo -# and when setting the script when a new object is loaded. -private command textReplaceRaw pOffset, @pOldText, @pNewText, pDontUpdateBreakpoints - lock screen - lock messages - - local tSelectedLine - put word 2 of the selectedLine into tSelectedLine - - local tOldLength - put the length of pOldText into tOldLength - - _internal script replace char pOffset to pOffset + tOldLength - 1 of field "Script" of me with pNewText - - --Do some work to update the gutter. - local tOldLines, tNewLines - put the number of lines of pOldText into tOldLines - if pOldText is not return and (char -1 of pOldText is return or pOldText is empty) then - add 1 to tOldLines - end if - if pNewText is empty and pOldText is return then - put 0 into tNewLines - else - put the number of lines of pNewText into tNewLines - if char -1 of pNewText is return or pNewText is return or pNewText is empty then - add 1 to tNewLines - end if - end if - - if pDontUpdateBreakpoints then - updateGutterRequest empty, empty, tOldLines, tNewLines, false, false - else - updateGutterRequest pOffset, tSelectedLine, tOldLines, tNewLines, true, false - end if - - unlock messages - - # OK-2008-09-10 : Bug 7132 - Update the panes and handler list everytime the text of the field is changed. - # OK-2009-01-19 : Don't do this here as it slows down the script editor on OS X. Instead do it in the individual - # cases where it may be needed, cut, paste, return, delete, backspace, undo and redo - --selectionUpdateRequest - - unlock screen -end textReplaceRaw - --- Sets the contents of the fields to pScript WITHOUT touching the undo queue. This should be done before any editing. -on textSetScriptRaw pScript - --put empty into field "Script" of me - local tOldText - put the text of field "Script" of me into tOldText - if tOldText is not pScript then - textReplaceRaw 1, tOldText, pScript, true - end if -end textSetScriptRaw - --- Sets the script within the undo queue. -on textSetScript pScript - textReplace 1, the text of field "Script" of me, pScript -end textSetScript - -# Description -# Performs an undo operation on the current script -on textUndo - undoAvailable - if not the result then - exit textUndo - end if - - local tOperations - put sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] into tOperations - lock screen - repeat with tIndex = sTextOperationIndex[sObjectId] down to sTextOperationIndex[sObjectId] - tOperations + 1 - local tNewText, tOldText - put sTextOperationNewTexts[sObjectId,tIndex] into tNewText - put sTextOperationOldTexts[sObjectId,tIndex] into tOldText - textReplaceRaw sTextOperationOffsets[sObjectId,tIndex], tNewText, tOldText - end repeat - unlock screen - - subtract tOperations from sTextOperationIndex[sObjectId] - subtract 1 from sTextGroupIndex[sObjectId] - - revDebuggerSuspendBreakpoints sObjectId - seSetObjectState sObjectId, "edited" - textMark "Insert" -end textUndo - -# Description -# Performs a redo operation on the current script -on textRedo - redoAvailable - if not the result then - exit textRedo - end if - - add 1 to sTextGroupIndex[sObjectId] - - local tOperations - put sTextGroupLengths[sObjectId,sTextGroupIndex[sObjectId]] into tOperations - lock screen - repeat with tIndex = sTextOperationIndex[sObjectId] + 1 to sTextOperationIndex[sObjectId] + tOperations - local tNewText, tOldText - put sTextOperationOldTexts[sObjectId,tIndex] into tOldText - put sTextOperationNewTexts[sObjectId,tIndex] into tNewText - textReplaceRaw sTextOperationOffsets[sObjectId,tIndex], tOldText, tNewText - end repeat - unlock screen - - add tOperations to sTextOperationIndex[sObjectId] - revDebuggerSuspendBreakpoints sObjectId - seSetObjectState sObjectId, "edited" - textMark "Insert" -end textRedo - -# Description -# This is a debugging command used to print the status of the undo queue when investigating -# problems. It should not be called anywhere in the code. -on textPrint - lock screen - - local tOperation - put 1 into tOperation - repeat with x = 1 to sTextGroupTop[sObjectId] - - put "Group(" & x & "):" && sTextGroupLabels[sObjectId,x] & return after message - repeat sTextGroupLengths[sObjectId,x] times - - local tOldText, tNewText - put sTextOperationOldTexts[sObjectId,tOperation] into tOldText - put sTextOperationNewTexts[sObjectId,tOperation] into tNewText - replace return with "\n" in tOldText - replace return with "\n" in tNewText - - put tab & "[" & tOperation & "]:" && sTextOperationOffsets[tOperation], tOldText, tNewText & return after message - - if tOperation is sTextOperationIndex[sObjectId] then - put tab & "--------" & return after message - end if - - add 1 to tOperation - end repeat - - if x is sTextGroupIndex[sObjectId] then - put "--------" & return after message - end if - end repeat - - unlock screen -end textPrint - -# Stores the id of the last request to update the gutter, if there is one pending. -local sGutterUpdateRequest - -# We also need to store whether the last update request involved text changing and -# whether it required the compilation errors to be updated. This is because it may be -# cancelled by a subsequent request that didn't require these things, resulting in the update -# being lost. -local sGutterUpdateRequestDetails - -private command updateGutterMergeRequestDetails pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw - # The offset and selected line are just overwritten providing they are not empty - if pOffset is not empty then - put pOffset into sGutterUpdateRequestDetails["offset"] - end if - - if pSelectedLine is not empty then - put pSelectedLine into sGutterUpdateRequestDetails["selectedLine"] - end if - - # The old number of lines is not changed, however if its empty, we put the new value in - if sGutterUpdateRequestDetails["oldLines"] is empty then - put pOldLines into sGutterUpdateRequestDetails["oldLines"] - end if - - # The new number of lines overwrites the previous setting, again providing that its not empty - if pNewLines is not empty then - put pNewLines into sGutterUpdateRequestDetails["newLines"] - end if - - # The new text changed value is the logical OR of the new and old values - # The same is done for the update compilation errors and the force breakpoint redraw - put (pTextChanged or sGutterUpdateRequestDetails["textChanged"]) into sGutterUpdateRequestDetails["textChanged"] - put (pUpdateCompilationErrors or sGutterUpdateRequestDetails["updateCompilationErrors"]) into sGutterUpdateRequestDetails["updateCompilationErrors"] - put (pForceBreakpointRedraw or sGutterUpdateRequestDetails["forceBreakpointRedraw"]) into sGutterUpdateRequestDetails["forceBreakpointRedraw"] -end updateGutterMergeRequestDetails - -# Parameters -# pOffset : the offset of the last text change -# pSelectedLine : the selected line at the point of the last text change -# pOldLines : the old number of lines in the script field at the point of the last text change -# pNewLines : the new number of liens in the script field after the last text change -# pTextChanged : whether text was changed or not since the last gutter update. If this is false, all the previous parameters are ignored. -# pUpdateCompilationErrors : whether to update the gutter's compilation errors -# Description -# Sends a request to update the gutter. This is called whenever the current script is edited, or the field -# is scrolled etc. A request is sent using a short delay and any previous requests are cancelled. -# The gutter's scroll is updated immediately however. Also a message is sent to the gutter to hide its -# mutable objects (the breakpoint / compilation error images). These are show again when the update is -# actually carried out. -command updateGutterRequest pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw - updateGutterMergeRequestDetails pOffset, pSelectedLine, pOldLines, pNewLines, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw - if sGutterUpdateRequest is not empty then - cancel sGutterUpdateRequest - end if - - # We always update the gutter's scroll immediately, as otherwise it looks bad. Other stuff is delayed though. - send "updateScroll" to group "Gutter" of me - send "updateGutterDo" to me in 5 milliseconds - put the result into sGutterUpdateRequest -end updateGutterRequest - - -# Description -# Updates the gutter according to the specified parameters. -command updateGutterDo - local tOffset, tSelectedLine, tOldLines, tNewLines, tTextChanged - put sGutterUpdateRequestDetails["offset"] into tOffset - put sGutterUpdateRequestDetails["selectedLine"] into tSelectedLine - put sGutterUpdateRequestDetails["oldLines"] into tOldLines - put sGutterUpdateRequestDetails["newLines"] into tNewLines - put sGutterUpdateRequestDetails["textChanged"] into tTextChanged - - local tUpdateCompilationErrors - put sGutterUpdateRequestDetails["updateCompilationErrors"] into tUpdateCompilationErrors - - local tForceBreakpointRedraw - put sGutterUpdateRequestDetails["forceBreakpointRedraw"] into tForceBreakpointRedraw - - send "update tOffset, tSelectedLine, tOldLines, tNewLines, tTextChanged, tUpdateCompilationErrors, tForceBreakpointRedraw" to group "Gutter" of me - - # Once an update has been carried out, we reset the sGutterUpdateRequestDetails array - delete variable sGutterUpdateRequestDetails -end updateGutterDo ################################################################################ -command actionCopy - copy -end actionCopy - -command actionCut - if scriptLocked() then - exit actionCut - end if - - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - if tFrom <= tTo then -- something is selected - textBeginGroup "Cut" - copy -- set the clipboard (dont cut as we do not allow field modification here) - textReplace tFrom, char tFrom to tTo of field "Script" of me, empty - textEndGroup - - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest - end if -end actionCut - -command actionPaste - if scriptLocked() then - exit actionPaste - end if - - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - lock screen - textBeginGroup "Paste" - textReplace tFrom, char tFrom to tTo of field "Script" of me, the clipboardData["text"] - if sePrefGet("editor,autoformat") then - scriptFormat "handler", true - end if - textEndGroup - unlock screen - - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end actionPaste - -command actionUndo - if scriptLocked() then - exit actionUndo - end if - textUndo - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end actionUndo - -command actionRedo - if scriptLocked() then - exit actionRedo - end if - textRedo - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end actionRedo - -command actionDeselectAll - lock messages - select empty - unlock messages -end actionDeselectAll - -command actionSelectAll - lock messages - - if word 1 of the name of the focusedObject is "field" then - select char 1 to -1 of the focusedObject - end if - unlock messages -end actionSelectAll - -# Description -# Called when the script editor is about to be closed. -command finalize - cancelPendingMessages - - if there is a sObjectId then - contextSave - end if - _internal script flush field "Script" of me -end finalize - -# Stores requests to update the script editor in reponse to a selection changed -local sSelectionUpdateRequest - -# Stores requests to update the script editor panes -local sPaneUpdateRequest - -command cancelPendingMessages - if sGutterUpdateRequest is not empty then - cancel sGutterUpdateRequest - end if - - if sSelectionUpdateRequest is not empty then - cancel sSelectionUpdateRequest - end if - - if sPaneUpdateRequest is not empty then - cancel sPaneUpdateRequest - end if -end cancelPendingMessages - --- This is sent by the engine -on selectionChanged - handleSelectionChanged -end selectionChanged - --- PM-2016-09-22: [[ Bug 15887 ]] Distinguish between "selectionChanged" sent by the engine and \ --- "selectionChangedByArrowKey pArrowKey" -on handleSelectionChanged - if the selectedText of field "Script" of me is not empty then - put the selectedText of field "Script" of me into sLastNonEmptySelection - end if - - # OK-2008-10-22 : Bug 7343 - Must save the last selection point as its lost - # when the user begins typing into the search field. - if the long id of the focusedObject is the long id of field "Script" of me then - put word 2 of it & comma & word 4 of it into sLastSelectedChunk - end if -end handleSelectionChanged - -on selectionChangedByArrowKey pArrowKey - handleSelectionChanged - get the selectedChunk - - local tAt - if word 2 of it > word 4 of it then - put word 4 of it into tAt - else - -- It is a multiple selection, so we need to exit this. - exit selectionChangedByArrowKey - end if - - -- Single selection in the process of making a larger selection, so exit if shift is down. - if the shiftKey is "down" then - exit selectionChangedByArrowKey - end if - - local tLine - put word 2 of the selectedLine into tLine - - local tField - put the long id of the selectedField into tField - - local tScript - put the text of tField into tScript - - local tLineStart - switch pArrowKey - case "left" - put the number of chars of line 1 to (tLine - 1) of tScript + 1 into tLineStart - # OK-2008-03-03 : Only add offset of return if we are not on the first line of the script - if tLine is not 1 then - add 1 to tLineStart - end if - put caretPositionLeft(tLineStart, tAt + 1, tScript) into tAt - - lock messages - select after char tAt of tField - unlock messages - break - case "right" - caretUpdate tField, tScript - break - if char (tAt + 1) of tScript is return then - add 1 to tLine - end if - put the number of chars of line 1 to (tLine - 1) of tScript + 2 into tLineStart - get line tLine of tScript - put caretPositionRight(tLineStart, tAt + 1, it) into tAt - break - case "up" - case "down" - caretUpdate tField, tScript - break - case "empty" - default - caretUpdate tField, tScript - break - end switch - - textMark "Insert" - - selectionUpdateRequest -end selectionChangedByArrowKey - - -private command selectionUpdateRequest - if sSelectionUpdateRequest is not empty then - cancel sSelectionUpdateRequest - end if - - send "selectionUpdate" to me in 10 milliseconds - put the result into sSelectionUpdateRequest -end selectionUpdateRequest - -command selectionUpdate - lock screen - findClearResults - if the lockText of field "Script" of me is false then - deSelectLastGoneToLine - end if - - # Tell the script editor to update its panes. This is called here in particular - # for the documentation pane to update itself when the user selects a new term. - paneUpdateRequest - - # Update the variables that store the last selected line and handler list - updateHandlerList - - updateSelectedHandler - - # Update the toolbar so that the handlers list can reflect the new selection. For efficiency we pass - # a parameter to the update command which tells it that the selected handler can be assumed to be - # up to date, so it doesn't need to evaluate it again (as we just updated it). - local tTrueString - put "true" into tTrueString - - # OK-2009-10-05: Optimized this a little. The previous call to update was doing quite a bit of stuff - # that is not required here. I factored out the stuff that we actually need into a new method, which - # is now called instead. - -- send "update tTrueString" to group "Toolbar" of stack (revTargetStack(the long id of me)) - send "updateSelectedHandler tTrueString" to group "Toolbar" of stack (revTargetStack(the long id of me)) - - # Update the left bar in the same way as the toolbar is updated - # OK-2009-10-05: Some more optimization here, the update method was doing a lot of stuff that is not - # needed, so I added a more specific method to handle this situation. - send "updateSelectedHandler" to group "Left Bar" of stack (revTargetStack(the long id of me)) - unlock screen -end selectionUpdate - - -# Description -# Sends a request to the script editor to update the panes. Requests are sent -# only after a period of inactivity to prevent bombardment. -command paneUpdateRequest - if sPaneUpdateRequest is not empty then - cancel sPaneUpdateRequest - end if - - send "paneUpdate" to me in sePrefGet("editor,paneupdatedelay") milliseconds - put the result into sPaneUpdateRequest -end paneUpdateRequest - -# Description -# Sets some state variables that may be needed to update the script editor panes -# and calls the sePanesUpdate command to do the update. -command paneUpdate - put empty into sPaneUpdateRequest - sePanesUpdate -end paneUpdate - -local sLastSelectedGoneToChunk -local sLastGoneToLine - -# Parameters -# pLine : a line number to go to, from 1 up to the number of lines in the current script. -# pHighlightMode : How to highlight the specified line. If this is false or not specified, the line is not highlighted. -# Description -# Goes to the specified line and highlights if required. The highlight mode is either false / empty for no highlight -# or "select" to select the line or "color" to set the line's background color. A value of "true" is treated the same -# as "select". -command goLine pLine, pHighlightMode, pPosition - local tScroll - put the vScroll of field "Script" of me into tScroll - - # OK-2008-08-25 : Bug 7013 - Preserve horizontal scroll - local tHScroll - put the hScroll of field "Script" of me into tHScroll - - # Select the line according to the value of pHighlight - lock messages - if pHighlightMode is "true" or pHighlightMode is "select" then - select line pLine of field "Script" of me - get the selectedChunk - put word 2 of it & comma & word 4 of it into sLastSelectedGoneToChunk - else if pHighlightMode is "color" then - set the backgroundColor of line pLine of field "Script" of me to sePrefGet("editor,selectbackgroundcolor") - local tStart - put the number of chars of line 1 to (pLine - 1) of field "Script" of me + 1 into tStart - put tStart & comma & tStart + the number of chars of line pLine of field "Script" of me into sLastSelectedGoneToChunk - else if pHighlightMode is "position" then - # OK-2009-03-03 : Bug 7550 - Allow for particular chars to be highlighted for better error display - local tEnd - put item 1 of pPosition into tStart - put item 2 of pPosition into tEnd - - # As typically Revolution errors only have a start char, and every after that gets ignored, - # if no end is specified, we highlight from the start char to the end of the line. - if tEnd is empty then - put the number of chars of line pLine of field "Script" of me into tEnd - end if - - select char tStart to tEnd of line pLine of field "Script" of me - get the selectedChunk - put word 2 of it & comma & word 4 of it into sLastSelectedGoneToChunk - else - put empty into sLastSelectedGoneToChunk - select before line pLine of field "Script" of me - end if - unlock messages - - # Scroll until the line is centred (assumes fixed line height) - if the vScroll of field "Script" of me > tScroll then - # The field has scrolled down in order to show the selection, therefore - # we need to make it scroll down again to centre it. - set the vScroll of field "Script" of me to the vScroll of field "Script" of me + round(the height of field "Script" of me / 2) - else if the vScroll of field "Script" of me < tScroll then - # The field has scrolled up in order to show the selection, therefore - # we need to make it scroll up again to centre it. - set the vScroll of field "Script" of me to the vScroll of field "Script" of me - round(the height of field "Script" of me / 2) - end if - - set the hScroll of field "Script" of me to tHScroll - - put pLine into sLastGoneToLine - - updateGutterRequest empty, empty, empty, empty, false, false -end goLine - -function getLastGoneToLine - return sLastGoneToLine -end getLastGoneToLine - -# Description -# Deselects the last line that was selected by the goLine command if there was one -# and it is still selected. -command deselectLastGoneToLine - get the selectedChunk - -- MM-2012-06-20: [[ Bug 10027 ]] Make sure there was a last line selected - causes bugs deselects elsewhere within the IDE. - if sLastSelectedGoneToChunk is not empty and word 2 of it is item 1 of sLastSelectedGoneToChunk and word 4 of it is item 2 of sLastSelectedGoneToChunk then - lock screen - lock messages - local tSelobj - put revIDESelectedObjects() into tSelobj - select empty - if tSelobj is not the long id of field "Script" of me then - revIDESelectObjects tSelobj - end if - set the backgroundColor of char (item 1 of sLastSelectedGoneToChunk) to (item 2 of sLastSelectedGoneToChunk) of field "Script" of me to empty - unlock messages - unlock screen - end if - put empty into sLastSelectedGoneToChunk - - # We update the gutter here to remove the current line indicator - updateGutterRequest empty, empty, empty, empty, false, false -end deselectLastGoneToLine - - -################################################################################ - --- This calculates the position of the caret based on pPosition where the caret is (hypothetically). -function caretPositionRight pLineStartChar, pProposedPosition, pLine - local tFirstPosition - put pLineStartChar - 1 into tFirstPosition - repeat for each char tChar in pLine - if tChar is space then - add 1 to tFirstPosition - else - exit repeat - end if - end repeat - - return max(tFirstPosition, pProposedPosition) -end caretPositionRight - --- On moving the caret/backspace left, this returns the correct char position. -function caretPositionLeft pLineStartChar, pCurrentPosition, pScript - repeat with x = pCurrentPosition down to pLineStartChar - if char x of pScript is not space then - return (pCurrentPosition-1) - break - end if - end repeat - return pLineStartChar - 2 -end caretPositionLeft - -on caretUpdate pField, pScript - local tLine - put word 2 of the selectedLine into tLine - - local tField - if pField is empty then - put the long id of the selectedField into tField - else - put pField into tField - end if - - local tScript - if pScript is empty then - put the text of the selectedField into tScript - else - put pScript into tScript - end if - - # The current line is the first then its first char is char 1, otherwise it is the number of - # chars of all previous lines + 1 char for the return char and 1 for the first char of the line. - local tLineStart - if tLine is 1 then - put 1 into tLineStart - else - put the number of chars of line 1 to (tLine - 1) of tScript + 2 into tLineStart - end if - - lock messages -- dont cause selectionChanged loop - - select after char caretPositionRight(tLineStart, word 4 of the selectedChunk, line tLine of tScript) of tField - - unlock messages -end caretUpdate - - -# Offset between a field's top margin and the start of the text -constant kFudge = "-4" - -# Parameters -# pLineNumber : a line number in the script of the current object -# Returns -# The vertical location of that line in the gutter or 0 if the line is not visible -function lineNumberToVerticalLoc pLineNumber - local tField - put getScriptField() into tField - - local tHeight - put (pLineNumber - 1) * the effective textHeight of getScriptField() into tHeight - - # If the breakpoint is on a line earlier than the first one in the visible area then don't render it - if tHeight < the vScroll of getScriptField() then - return 0 - end if - - # If the breakpoint is on a line after the last one in the visible area the don't render it - if tHeight > (the vScroll of getScriptField() + the height of getScriptField()) then - return 0 - end if - - # Adjust the height to take the vScroll into account - local tLoc - put tHeight - the vScroll of getScriptField() into tLoc - - # Adjust the height so its relative to the start of the gutter - add the top of me to tLoc - - # Adjust the the height to take the field's margins into account. This requires a little fudge... - if the number of items of the margins of getScriptField() = 4 then - add item 2 of the margins of getScriptField() + kFudge to tLoc - else - add the margins of getScriptField() + kFudge to tLoc - end if - - # Adjust to the middle of the line - add round(0.5 * the effective textHeight of getScriptField()) to tLoc - - return tLoc -end lineNumberToVerticalLoc - -# Parameters -# pVerticalLoc : a vertical location within the gutter's area -# Returns -# The line number in the current script that is associated with the specified location. -# If the location is beyond any lines in the script, or the line cannot have a breakpoint -# on it, then 0 is returned. -function verticalLocToLineNumber pVerticalLoc - # Add the vScroll of the script field so that the location is relative to the start of the text - local tHeight - put the vScroll of getScriptField() + pVerticalLoc into tHeight - - # Make it relative to 0 rather than the top of the gutter - subtract the top of me from tHeight - - # Adjust the the height to take the field's margins into account. This requires a little fudge... - if the number of items of the margins of getScriptField() = 4 then - subtract item 2 of the margins of getScriptField() + kFudge from tHeight - else - subtract the margins of getScriptField() + kFudge from tHeight - end if - - # Divide to calculate which line number it falls nearest. Always round up. - local tLineNumber - put (tHeight div the effective textHeight of getScriptField()) + 1 into tLineNumber - return tLineNumber -end verticalLocToLineNumber - local sDefinitionMatches - -private command prepareContextMenu - local tSelectedText - put getClickText() into tSelectedText - - local tLine, tSelectedHandler - put word 2 of the selectedLine into tLine - if tLine is not empty then - put handlerContainingLine(tLine) into tSelectedHandler - end if - - local tObject - getObject - put the result into tObject - - local tMatches - put seMatchingDefinitions(tSelectedText, tObject, tSelectedHandler) into tMatches - - put tMatches into sDefinitionMatches - - local tGoToDefinition - put "Go to definition" into tGoToDefinition - if tMatches is empty then - put "(" before tGoToDefinition - end if - - local tText - put tGoToDefinition & return into tText - if not revIDEBrowserWidgetUnavailable() then - put "Find in Docs" & return after tText - end if - - put "-" & return after tText - - put "Set Breakpoint" & return after tText - put "-" & return after tText - - if scriptLocked() then - put "(Cut" & return & \ - "Copy" & return & \ - "(Paste" after tText - else - put"Cut" & return & \ - "Copy" & return & \ - "Paste" after tText - end if - - if the last char of tText is not return then - put return after tText - end if - - -- Dispatch a hook into the message path to customize the context menu - local tModifiedText - dispatch "revHookBuildScriptEditorContextMenu" to me with (the long id of tObject), tSelectedText, tText, tModifiedText - if it is not "handled" then - put tText into tModifiedText - end if - - set the text of button "Context Menu" of me to tModifiedText -end prepareContextMenu - -################################################################################ - -private function handleEvent pEvent, pTarget - if the long id of pTarget is the long id of field "Script" of me then - return true - else - return false - end if -end handleEvent - -# OK-2009-03-02 : Bug 7773 -on optionKeyDown pKey - if not handleEvent("optionKey", the long id of the target) then - pass optionKeyDown - end if - - # Block this message on OS X as it can cause weird characters to be entered into the field - if the platform is not "MacOS" then - pass optionKeyDown - end if - - -- OK-2009-03-09 : But simulate the message as a normal keydown - keyDown pKey -end optionKeyDown - - -on scrollBarDrag - if the short name of the target is "Gutter" or the short name of the owner of the target is "Gutter" then - exit scrollBarDrag - end if - - updateGutterRequest empty, empty, empty, empty, false, true -end scrollBarDrag - -on keyDown pChar - if not handleEvent("keydown", the long id of the target) then - pass keyDown - end if - - if scriptLocked() then - exit keyDown - end if - - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - local tAt, tLength - if tFrom > tTo then -- the caret is at the end - put 0 into tLength - put tFrom into tAt - else - put tFrom into tAt - put tTo - tFrom + 1 into tLength - end if - textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, pChar -end keyDown - -on backspaceKey - if not handleEvent("backspaceKey", the long id of the target) then - pass backspaceKey - end if - - if scriptLocked() then - exit backspaceKey - end if - - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - local tAt, tLength - if tFrom > tTo then - -- Caret handling, for now, is only done for an "empty" selection. - local tLine - put word 2 of the selectedLine into tLine - - local tScript - put the text of the selectedField into tScript - - local tLineStart - put the number of chars of line 1 to (tLine - 1) of tScript + 1 into tLineStart - -- Only add offset of return if we are not on the first line of the script - if tLine is not 1 then - add 1 to tLineStart - end if - - # OK-2008-08-28 : Bug 6515 - Delete whole word with commandKey - if the commandKey is "down" then - local tWordFound - put false into tWordFound - repeat with x = tTo down to 1 - if not matchText(char x of tScript, "\s") then - put true into tWordFound - else - if tWordFound then - exit repeat - end if - end if - end repeat - - if x <> 1 then - put x + 1 into tAt - else - put x into tAt - end if - - put tTo - tAt + 1 into tLength - else - # OK-2008-08-05 : Bug 6867 - If autoformatting is turned off, simply delete the last selected character - if sePrefGet("editor,autoformat") then - put caretPositionLeft(tLineStart, tTo, tScript) + 1 into tAt - else - put tTo into tAt - end if - put tTo - tAt + 1 into tLength - end if - else - put tTo - tFrom + 1 into tLength - put tFrom into tAt - end if - - textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, empty - - # If the user has deleted a selection of text rather than a single character, they will - # expect this to be a single undoable operation. So we close the current group straight - # after the deletion. in this case. - if tTo > tFrom then - textEndGroup - end if - - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end backspaceKey - -on deleteKey - if not handleEvent("deleteKey", the long id of the target) then - pass deleteKey - end if - - if scriptLocked() then - exit deleteKey - end if - - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - local tAt, tLength - if tFrom > tTo then - put tFrom into tAt - put 1 into tLength - else - put tFrom into tAt - put tTo - tFrom + 1 into tLength - end if - - textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, empty - - # If the user has deleted a selection of text rather than a single character, they will - # expect this to be a single undoable operation. So we close the current group straight - # after the deletion. in this case. - if tTo > tFrom then - textEndGroup - end if - - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end deleteKey - -on tabKey - if not handleEvent("tabKey", the long id of the target) then - pass tabKey - end if - - # To prevent interference with the command+tab shortcut to cycle between tabs - if the commandKey is "down" then - pass tabKey - end if - - if scriptLocked() then - exit tabKey - end if - - if sePrefGet("editor,autoformat") then - scriptFormat "handler" - else - get the selectedChunk - - local tFrom, tTo - put word 2 of it into tFrom - put word 4 of it into tTo - - local tAt, tLength - if tFrom > tTo then - put tFrom into tAt - put 0 into tLength - else - put tFrom into tAt - put tTo - tFrom into tLength - end if - - textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, tab - end if -end tabKey - -# Key identifiers for a few important keys... -constant kKeyHome = "65360" -constant kKeyEnd = "65367" -constant kKeyLeftArrow = "65361" -constant kKeyRightArrow = "65363" -constant kKeyUpArrow = "65362" -constant kKeyDownArrow = "65364" -constant kKeyF1 = "65470" -constant kKeyF2 = "65471" -constant kKeyF3 = "65472" -constant kKeyF4 = "65473" -constant kKeyF5 = "65474" -constant kKeyF6 = "65475" -constant kKeyF7 = "65476" -constant kKeyF8 = "65477" -constant kKeyF9 = "65478" -constant kKeyF10 = "65479" -constant kKeyF11 = "65480" -constant kKeyF12 = "65481" -constant kKeyF13 = "65482" -constant kKeyNumLock = "65407" -constant kKeyPageUp = "65365" -constant kKeyPageDown = "65366" -# constant kKeyMenu = "80" - -private command selectFromCurrentToLineStart - local tAt - put word 4 of the selectedChunk into tAt - - local tLineNumber - put word 2 of the selectedLine into tLineNumber - - local tLineStart - put the number of chars of line 1 to (tLineNumber - 1) of the text of getScriptField() + 1 into tLineStart - # Only add offset of return if we are not on the first line of the script - if tLineNumber is not 1 then - add 1 to tLineStart - end if - - select char tLineStart to tAt of field (the short name of getScriptField()) of me -end selectFromCurrentToLineStart - -private command selectFromCurrentToLineEnd - local tAt - put word 4 of the selectedChunk into tAt - - local tLineNumber - put word 2 of the selectedLine into tLineNumber - - local tLineEnd - put the number of chars of line 1 to tLineNumber of the text of getScriptField() into tLineEnd - - select char (tAt + 1) to tLineEnd of field (the short name of getScriptField()) of me -end selectFromCurrentToLineEnd - --- Description --- Implements a basic page up functionality for OS X, as this is not default field behavior. -private command pageUp - local tLineNumber - put word 2 of the selectedLine into tLineNumber - - -- Work out the number of lines in one "page" of the script editor field. - local tLineCount - put the height of getScriptField() div the textHeight of getScriptField() into tLineCount - - -- Work out which line number we need to scroll up to - local tNewLineNumber - put max(tLineNumber - tLineCount, 1) into tNewLineNumber - - -- Calculate the char that we need to reach to do the page up - local tStartChar - put the number of chars of line 1 to tNewLineNumber of the text of getScriptField() into tStartChar - - local tAt - put word 4 of the selectedChunk into tAt - - if shiftKey() is "down" then - select char tStartChar to tAt of field (the short name of getScriptField()) of me - else - select after char tStartChar of field (the short name of getScriptField()) of me - end if -end pageUp - --- Description --- Implements a basic page down functionality for OS X, as this is not default field behavior. -private command pageDown - local tMultiSelection, tAt - get the selectedChunk - if word 4 of it > word 2 of it then - put true into tMultiSelection - put word 4 of it into tAt - else - put false into tMultiSelection - put word 2 of it into tAt - end if - - local tLineNumber - if tMultiSelection then - put word 4 of the selectedLine into tLineNumber - else - put word 2 of the selectedLine into tLineNumber - end if - - -- Work out the number of lines in one "page" of the script editor field. - local tLineCount - put the height of getScriptField() div the textHeight of getScriptField() into tLineCount - - -- Work out which line number we need to scroll down to - local tNewLineNumber - put min(tLineNumber + tLineCount, the number of lines of the text of getScriptField()) into tNewLineNumber - - -- Calculate the char that we need to reach to do the page down - local tEndChar - put the number of chars of line 1 to tNewLineNumber of the text of getScriptField() into tEndChar - - if shiftKey() is "down" then - select char tAt to tEndChar of field (the short name of getScriptField()) of me - else - select after char tEndChar of field (the short name of getScriptField()) of me - end if -end pageDown - - -# Description -# RawKeyDown is handled mainly because of the home and end keys. These need to be manually implemented on OS X -# and both platforms after pressing the home key we have to ensure the caret ends up in the right place. -# Other keys may be blocked here to prevent weird chars getting inserted into the script. -on rawKeyDown pKey - if not handleEvent("rawKeyDown", the long id of the target) then - pass rawKeyDown - end if - - # For the beginning of line/paragraph action (there is no distinction in the S/E) - # make sure we update the caret position after the field has had its go. - - # For Windows: Home (Windows / Linux) - if pKey is kKeyHome and seGetPlatform() is not "macos" then - send "selectionChangedByArrowKey" to me in 0 milliseconds - pass rawKeyDown - end if - - # For Mac: Ctrl-Left / Cmd-Left / Ctrl-A (Mac) - if (pKey is kKeyLeftArrow and (the controlKey is "down" or the commandKey is "down") or \ - (pKey is 65 and the controlKey is "down" and the shiftKey is "up")) and seGetPlatform() is "macos" then - send "selectionChangedByArrowKey" to me in 0 milliseconds - pass rawKeyDown - end if - - # For actions where we need to skip back, we need to ensure the caret is at the - # start of the line if it is in the white-space prefix. - - # For Mac: Alt-Down - if (pKey is kKeyUpArrow) and (the optionKey is "down" and the shiftKey is "up") and seGetPlatform() is "macos" then - local tScript - put the text of the selectedField into tScript - - local tCaretChar - get the selectedChunk - put word 2 of it into tCaretChar - try - repeat while tCaretChar > 1 and (char (tCaretChar - 1) of tScript is space) - subtract 1 from tCaretChar - end repeat - catch tError - put tError - end try - if tCaretChar is not 1 and char tCaretChar - 1 of tScript is return then - lock messages - select before char tCaretChar of the selectedField - unlock messages - end if - end if - - pass rawKeyDown -end rawKeyDown - - -# Description -# RawKeyUp is handled to deal with the arrow keys. The script editor needs to update when these are pressed -# because they change the selection, however in order to do this efficiently, we have to only update when the key -# is actually released, not each repeat interval. -on rawKeyUp pKey - if not handleEvent("rawKeyUp", the long id of the target) then - pass rawKeyUp - end if - - if pKey is not among the items of kKeyLeftArrow,kKeyRightArrow,kKeyUpArrow,kKeyDownArrow then - pass rawKeyUp - end if - - # Check to see if one of the arrow keys is still being held down. If so, don't do the selectionChanged update until they - # are all released as it will still be moving - local tDownKeys - put keysDown() into tDownKeys - if (kKeyLeftArrow is among the items of tDownKeys) or (kKeyRightArrow is among the items of tDownKeys) or (kKeyUpArrow is among the items of tDownKeys) or (kKeyDownArrow is among the items of tDownKeys) then - pass rawKeyUp - end if - - local tKeyName - switch pKey - case kKeyLeftArrow - put "left" into tKeyName - break - case kKeyRightArrow - put "right" into tKeyName - break - case kKeyUpArrow - put "up" into tKeyName - break - case kKeyDownArrow - put "down" into tKeyName - break - end switch - - if not scriptLocked() then - textMark "Insert" - send "selectionChangedByArrowKey tKeyName" to me in 0 milliseconds - end if - pass rawKeyUp -end rawKeyUp - -local sLastClickLine - -on mouseDown pButtonNumber - put word 2 of the clickLine into sLastClickLine - if pButtonNumber <> 3 or the long id of the target is not the long id of field "Script" of me then - pass mouseDown - end if - - prepareContextMenu - showContextMenu - pass mouseDown -end mouseDown - -private command showContextMenu - popup button "Context Menu" of me -end showContextMenu - -on menuPick pItemName - if the long id of the target is not the long id of button "Context Menu" of me then - pass menuPick - end if - - -- Dispatch a hook into the message path to give first action to any customizations - dispatch "revHookScriptEditorContextMenuPick" to me with pItemName - if it is "handled" then - exit menuPick - end if - - switch pItemName - case "Set Breakpoint" - if sLastClickLine is not empty then - local tScript - put textGetScript() into tScript - - local tLineNumber - put revDebuggerNextAvailableBreakpoint(tScript, sLastClickLine - 1) into tLineNumber - - revDebuggerAddBreakpoint sObjectId, tLineNumber - revDebuggerActivateBreakpoint sObjectId, tLineNumber - updateGutterRequest empty, empty, empty, empty, false, false - end if - break - - case "Find in Docs" - local tText, tData - put getClickText() into tText - put ideDocsFetchLCSData(tText) into tData - if tData is not empty then - revIDEGoToLCSDictionaryEntry tText, tData[1]["type"] - end if - break - - case "Cut" - actionCut - break - - case "Copy" - actionCopy - break - - case "Paste" - actionPaste - break - - case "Go to definition" - local tMatches - put sDefinitionMatches into tMatches - if tMatches is empty then - exit menuPick - end if - - if the number of lines of tMatches > 1 then - set the cSymbols of getDisambiguatorObject() to tMatches - send "update" to getDisambiguatorObject() - modal getDisambiguatorObject() - - local tResult - put the cResult of getDisambiguatorObject() into tResult - if tResult is empty then - exit menuPick - end if - - goMatchingDefinition tResult - else - goMatchingDefinition tMatches - end if - - break - end switch -end menuPick - -private command goMatchingDefinition pMatch - local tObject, tLine - put item 5 to -1 of pMatch into tObject - - put item 4 of pMatch into tLine - - revSEGoExecutionPoint tObject, tLine, true, true -end goMatchingDefinition - - -private function getDisambiguatorObject - return the long id of stack "revSEDisambiguator" -end getDisambiguatorObject - ---private command showDisambiguator --- local tObject --- put getDisambiguatorObject() into tObject --- --set the topLeft of tObject to the selectedLoc --- set the loc of ---end showDisambiguator - ---private command hideDisambigutator --- set the right of getDisambiguatorObject() to the left of the long owner of getDisambiguatorObject() - 500 ---end hideDisambigutator - ---command disambiguatorPick pSymbol --- hideDisambigutator --- log "pSymbol: " & the cResult of getDisambiguatorObject() ---end disambiguatorPick - -private function getSelectedText - local tFrom, tTo - get the selectedChunk - put word 2 of it into tFrom - put word 4 of it into tTo - - local tText - if tTo < tFrom then - getCaretToken - put the result into tText - else - put char tFrom to tTo of textGetScript() into tText - end if - - return tText -end getSelectedText - -# OK-2009-01-22 : Bug 7278 - Use the clickText instead of the selectedText for the context menu -# Also modified getCaretToken by adding optional pUseClick parameter. -private function getClickText - -- local tFrom, tTo - -- get the clickChunk - -- put word 2 of it into tFrom - -- put word 4 of it into tTo - - local tText - -- if tTo < tFrom then - getCaretToken true - put the result into tText - --else - -- put char tFrom to tTo of textGetScript() into tText - --end if - - return tText -end getClickText - -# Parameters -# pLine : the line number we are inserting at (i.e word 2 of the selectedLine at the point which the return was pressed which triggered the autocomplete) -# xString : the string to put the completion after. This is the string that is about to be appended to the script as a result of pressing return -# Description -# Calculates the correct completion according to what is already on line pLine, including formatting, and places it after xString, -# which can then be inserted into the script field. -private command autoComplete pLine, @xString - local tScript - put textGetScript() into tScript - - local tCurrentLine - put line pLine of tScript into tCurrentLine - - # From the text in the current line, calculate what kind of structure the user is typing the start of (if any) - local tStructureType, tStructureName - get autoCompleteGetStructure(tCurrentLine) - put line 1 of it into tStructureType - put line 2 of it into tStructureName - - # Once we know what the structure is, lookup what the correct completion is for that structure. - local tCompletion - put autoCompleteGetCompletion(tStructureType, tStructureName) into tCompletion - if tCompletion is empty then - exit autoComplete - end if - - if tCompletion is empty then - exit autoComplete - end if - - # Look down the script and work out if we actually need to complete this structure, i.e. find out if its - # already been completed or not. - if not autoCompleteCompletionRequired(pLine, tStructureType, tStructureName, tCompletion) then - exit autoComplete - end if - - # Format the completion, this is easy because the indentation of the complete will always match - # that of pLine. - local tIndent - put textFormatGetLineIndent(tCurrentLine) before tCompletion - put return & tCompletion after xString -end autoComplete - -private function autoCompleteSearchContext @pScript, pLineNumber, pStructureType, pStructureName, pCompletion - if pStructureName is not empty then - return 1 - end if - - local tDepth - put 0 into tDepth - repeat with x = pLineNumber down to 1 - local tLine - put line x of pScript into tLine - - if token 1 of tLine is "private" and token 2 of tLine is among the items of autoCompleteNamedStructures() then - exit repeat - else if token 1 of tLine is among the items of autoCompleteNamedStructures() then - exit repeat - end if - - if token 1 of tLine is pStructureType then - add 1 to tDepth - else if token 1 of tLine is "end" and token 2 of tLine is pStructureType then - subtract 1 from tDepth - end if - end repeat - - return tDepth -end autoCompleteSearchContext - -# Parameters -# pLineNumber : the line that the structure to be completed starts on -# pStructureType : the type of the structure to be completed this is either one of autoCompleteNamedStructures() or autoCompleteUnnamedStructures() -# pStructureName : the name of the structure. (May be empty, not all structures have names, basically only handlers do) -# pCompletion : what the completion of the structure would be (this is needed in order to see if its already there). -# Returns -# True if a completion is required for this specification, false otherwise. -function autoCompleteCompletionRequired pLineNumber, pStructureType, pStructureName, pCompletion - local tScript - put textGetScript() into tScript - - local tInitialDepth - put autoCompleteSearchContext(tScript, pLineNumber, pStructureType, pStructureName, pCompletion) into tInitialDepth - put line pLineNumber + 1 to -1 of tScript into tScript - - # The nesting depth starts at 1 as we have just entered a structure - local tNestingDepth - put tInitialDepth into tNestingDepth - repeat for each line tLine in tScript - if token 1 of tLine is token 1 of pCompletion and token 2 of tLine is token 2 of pCompletion then - subtract 1 from tNestingDepth - if tNestingDepth = 0 then - # The structure is already completed - return false - end if - else if token 1 of tLine is "end" and token 2 of tLine is not among the items of autoCompleteUnnamedStructures() and token 2 of tLine is not "if" then - # If a named structure is ending, but it doesn't match the structure we are looking for - # then if the structure we're looking for is un-named, we return true - if pStructureName is empty then - return true - end if - - # Else if we are looking for a named structure, then don't do the completion, because - # its possible that the user is renaming a handler and we should be conservative here. - if pStructureName is not empty then - return false - end if - else - get autoCompleteGetStructure(tLine) - - # If we have a matching structure being opened, increment the nesting depth - if line 1 of it is pStructureType and line 2 of it is pStructureName then - add 1 to tNestingDepth - end if - - # If a new handler has started and we are completing an any structure then - # we should return true now. - if line 2 of it is not empty then - return true - end if - end if - end repeat - - return true -end autoCompleteCompletionRequired - -# Returns -# A comma separated list of the autocompleteable structures that have names. This is currently just handlers. -private function autoCompleteNamedStructures - return handlerTypes() -end autoCompleteNamedStructures - -# Returns -# A comma separated list of the autocompleteable structures without names. Note that we don't complete IF statements -# because there are too many possibilities, (else, else if, end if) and its better to not complete than risk forcing the user to delete stuff. -private function autoCompleteUnnamedStructures - return "repeat,try,switch" -end autoCompleteUnnamedStructures - -# Parameters -# pLine : a line number in the current script -# Returns -# A string describing the structure whose beginning is found on pLine. This is in the following format: -# Line 1 : The structure's type, e.g. command, repeat, try -# Line 2 : The structure's name if it has one, e.g. mouseUp -# If pLine does not represent the beginning of a completable structure then the structure type will be empty. -private function autoCompleteGetStructure pLine - local tLine - put pLine into tLine - - # Disregard "private" if first token - if token 1 of tLine is "private" then - put token 2 to -1 of tLine into tLine - end if - - local tStructureType, tStructureName - - # Establish what the structure type and name (if appropriate) are. We autocomplete handler declarations, - # repeats, trys and switches, but not ifs (because they have too many different forms, might annoy the user). - if token 1 of tLine is among the items of autoCompleteNamedStructures() then - put token 1 of tLine into tStructureType - put token 2 of tLine into tStructureName - else if token 1 of tLine is among the items of autoCompleteUnnamedStructures() then - put token 1 of tLine into tStructureType - put empty into tStructureName - end if - - return tStructuretype & return & tStructureName -end autoCompleteGetStructure - -# Parameters -# pStructureType : the type of a completeable structure -# pStructureName : the name of a compleatable structure (may be empty) -# Returns -# The completion of the stucture if one is known. E.g if pStructureType is "on" and pStuctureName is "mouseUp", -# will return "end mouseUp" -private function autoCompleteGetCompletion pStructureType, pStructureName - # Make sure we have something valid that can be completed - if pStructureType is empty then - return empty - end if - - # Work out the completion - local tCompletion - if pStructureType is among the items of handlerTypes() then - if pStructureName is not empty then - put "end " & pStructureName into tCompletion - end if - else - put "end " & pStructureType into tCompletion - end if - - return tCompletion -end autoCompleteGetCompletion - -# Parameters -# Description -# Returns the specification of replace operation that represents the inserting of a -# return character at the specified location in the current script. Includes formatting. -# This command will also remove indentation from the previous line. -private command calculateReturnFormatting pTo, pFrom, pLine, pContinuationRequired, @rAt, @rLength, @rString - local tReturnString - if pContinuationRequired then - put " \" & return into tReturnString - else - put return into tReturnString - end if - - # If there is a non-empty selection, the inserted return char will replace this - # and for now, no formatting is done. - if pFrom <= pTo then - put pFrom into rAt - put pTo - pFrom + (the length of tReturnString) into rLength - put tReturnString into rString - exit calculateReturnFormatting - end if - - # If the preference is not to use formatting, just return the specification of the basic - # insertion of a return character. - if not sePrefGet("editor,autoformat") then - put pFrom into rAt - put 0 into rLength - put tReturnString into rString - exit calculateReturnFormatting - end if - - local tScript - put textGetScript() into tScript - - local tPreviousChars - repeat with x = pFrom - 1 down to 1 - if char x of tScript is empty or char x of tScript is return then - exit repeat - end if - put char x of tScript after tPreviousChars - end repeat - - local tWhitespaceBefore - put matchText(tPreviousChars, "^\s*$") into tWhitespaceBefore - - if tWhitespaceBefore then - local tIndent - put textFormatGetLineIndent(line pLine of tScript) into tIndent - - # If the caret has somehow been placed in the middle of the indentation string we need to allow - # for this by subtracting from tIndent - local tCurrentChar - put pFrom into tCurrentChar - repeat until (char tCurrentChar of tScript is not space) or the number of chars of tIndent = 0 - delete char 1 of tIndent - add 1 to tCurrentChar - end repeat - - local tLength - put 0 into tLength - - local tAt - put pFrom into tAt - - local tReturn - put return & tIndent into tReturn - else - local tFormatting - local tPreviousLine = 0 - local tTextLines - put tScript into tTextLines - split tTextLines by return - - put textFormatLine(pLine, tTextLines, tPreviousLine) into tFormatting - - put (the number of chars of line 1 to (pLine - 1) of tScript) + 1 into tAt - if pLine <> 1 then - add 1 to tAt - end if - - if item 1 of tFormatting > 0 then - repeat item 1 of tFormatting times - put space after tIndent - end repeat - textReplace tAt, empty, tIndent - else if item 1 of tFormatting < 0 then - textReplace tAt, char tAt to (tAt - item 1 of tFormatting - 1) of tScript, empty - end if - - put 0 into tLength - put pFrom into tAt - add item 1 of tFormatting to tAt - put tReturnString & item 2 of tFormatting into tReturn - end if - - put tAt into rAt - put tLength into rLength - put tReturn into rString -end calculateReturnFormatting - -on returnInField - if the commandKey is "down" then - # Pass to prevent conflict with command + return keyboard shortcut - pass returnInField - end if - - if not handleEvent("returnInField", the long id of the target) then - pass returnInField - end if + +private command prepareContextMenu + local tSelectedText + put getClickText() into tSelectedText - if scriptLocked() then - exit returnInField + local tLine, tSelectedHandler + put word 2 of the selectedLine into tLine + if tLine is not empty then + put handlerContainingLine(tLine) into tSelectedHandler end if - local tFrom, tTo - get the selectedChunk - put word 2 of it into tFrom - put word 4 of it into tTo + local tObject + getObject + put the result into tObject - local tLine - put word 2 of the selectedLine into tLine + local tMatches + put seMatchingDefinitions(tSelectedText, tObject, tSelectedHandler) into tMatches - # Option+Return places a continuation char on the current line before the return. - local tContinuationRequired - put (optionKey() is "down") into tContinuationRequired + put tMatches into sDefinitionMatches - local tAt, tLength, tReturn - calculateReturnFormatting tTo, tFrom, tLine, tContinuationRequired, tAt, tLength, tReturn + local tGoToDefinition + put "Go to definition" into tGoToDefinition + if tMatches is empty then + put "(" before tGoToDefinition + end if - local tCaretOffset - put tAt + the length of tReturn - 1 into tCaretOffset + local tText + put tGoToDefinition & return into tText + put "Find in" & return after tText - local tLineEnd - put the number of chars of line 1 to tLine of textGetScript() + 1 into tLineEnd + if not revIDEBrowserWidgetUnavailable() then + put tab & "Docs" & return after tText + end if - local tFollowingChars - put char tAt to tLineEnd of textGetScript() into tFollowingChars + repeat for each item tItem in \ + "Current Tab,All Tabs,Card,Stack,Stack File,Stack File and its stackFiles,All Stack Files,All available stacks" + put tab & tItem & return after tText + end repeat + put "-" & return after tText - local tWhitespaceAfter - put matchText(tFollowingChars, "^\s*$") into tWhitespaceAfter + put "Set Breakpoint" & return after tText + put "-" & return after tText - if sePrefGet("editor,autocomplete") and tWhitespaceAfter then - autoComplete tLine, tReturn + if scriptLocked() then + put "(Cut" & return & \ + "Copy" & return & \ + "(Paste" after tText + else + put"Cut" & return & \ + "Copy" & return & \ + "Paste" after tText end if - # The return character should be grouped separately from the line that was entered before it (if there was one) - # This copies the behavior of MS Visual Studio. - if sTextGroupIndex[sObjectId] is not 0 then - # OK-2008-07-29 : Bug 6825 - --textEndGroup - textMark "Insert" + if the last char of tText is not return then + put return after tText end if - textReplace tAt, char tAt to tAt + tLength - 1 of field "Script" of me, tReturn - select after char tCaretOffset of field "Script" of me - textEndGroup + -- Dispatch a hook into the message path to customize the context menu + local tModifiedText + dispatch "revHookBuildScriptEditorContextMenu" to me with (the long id of tObject), tSelectedText, tText, tModifiedText + if it is not "handled" then + put tText into tModifiedText + end if - # OK-2009-01-19 : Update the handler list - selectionUpdateRequest -end returnInField + set the text of button "Context Menu" of me to tModifiedText +end prepareContextMenu --- Drag Drop Management -local sDragMode +################################################################################ -on dragDrop - if not handleEvent("dragDrop", the long id of the target) then - pass dragDrop - end if - - if scriptLocked() then - exit dragDrop +local sLastClickLine + +on mouseDown pButtonNumber + put word 2 of the clickLine into sLastClickLine + if pButtonNumber <> 3 or the long id of the target is not the long id of field "Script" of me then + pass mouseDown end if - lock screen - textBeginGroup "Drag" - - local tDropAt - get the dropChunk - put word 2 of it into tDropAt - - local tSelectFrom, tSelectTo - get the selectedChunk - put word 2 of it into tSelectFrom - put word 4 of it into tSelectTo - - if tDropAt >= tSelectFrom and tDropAt <= tSelectTo then - exit dragDrop + prepareContextMenu + showContextMenu + pass mouseDown +end mouseDown + +private command showContextMenu + popup button "Context Menu" of me +end showContextMenu + +on menuPick pItemName + if the long id of the target is not the long id of button "Context Menu" of me then + pass menuPick end if - if sDragMode is "cut" then - -- Remove the selection. This will never happen on a drag that started outside the ScriptEditorPane. - - -- in this case, we cannot have tFrom > tTo - textReplace tSelectFrom, char tSelectFrom to tSelectTo of control "Script" of me, empty - - if tDropAt > tSelectTo then - subtract tSelectTo - tSelectFrom + 1 from tDropAt - end if + -- Dispatch a hook into the message path to give first action to any customizations + dispatch "revHookScriptEditorContextMenuPick" to me with pItemName + if it is "handled" then + exit menuPick end if + set the itemDelimiter to "|" - local tDroppedText - put dragData["text"] into tDroppedText - -- There is an issue with the very last return character, for now it seams sufficient to remove this. - # if char -1 of tDroppedText is return then - # delete char -1 of tDroppedText - # end if - - textReplace tDropAt, empty, tDroppedText - - textEndGroup - unlock screen -end dragDrop + switch item 1 of pItemName + case "Set Breakpoint" + if sLastClickLine is not empty then + local tScript + put textGetScript() into tScript + + local tLineNumber + put revDebuggerNextAvailableBreakpoint(tScript, sLastClickLine - 1) into tLineNumber + + revDebuggerAddBreakpoint getObjectID(), tLineNumber + revDebuggerActivateBreakpoint getObjectID(), tLineNumber + updateGutterRequest empty, empty, empty, empty, false, false, true + end if + break + + case "Find in" + + local tCallback + put "__FindAllCallback" into tCallback + + local tCallbackTarget + put the long id of me into tCallbackTarget + + local tText + put getClickText() into tText + + local tTarget + switch item 2 of pItemName + case "Docs" + local tData + put ideDocsFetchLCSData(tText) into tData + if tData is not empty then + revIDEGoToLCSDictionaryEntry tText, tData[1]["type"] + end if + break + case "All tabs" + put "all" into tTarget + break + case "Current Tab" + put "current" into tTarget + break + case "Card" + put "card" into tTarget + break + case "Stack" + put "stack" into tTarget + break + case "Stack File" + put "stack file" into tTarget + break + case "All Stack Files" + put "all stacks" into tTarget + break + case "Stack File and its stackFiles" + put "stack file and stackfiles" into tTarget + break + case "All available stacks" + put "all available stacks" into tTarget + break + end switch + if item 2 of pItemName is not "Docs" then + send "revSEFindAll tText, false, false, false, true, tTarget, tCallback, tCallbackTarget" to this stack + end if + break + case "Cut" + actionCut + break + + case "Copy" + actionCopy + break + + case "Paste" + actionPaste + break + + case "Go to definition" + local tMatches + put sDefinitionMatches into tMatches + if tMatches is empty then + exit menuPick + end if + + if the number of lines of tMatches > 1 then + set the cSymbols of getDisambiguatorObject() to tMatches + send "update" to getDisambiguatorObject() + modal getDisambiguatorObject() + + local tResult + put the cResult of getDisambiguatorObject() into tResult + if tResult is empty then + exit menuPick + end if + + goMatchingDefinition tResult + else + goMatchingDefinition tMatches + end if + + break + end switch +end menuPick -on dragStart - if not handleEvent("dragStart", the long id of the target) then - pass dragStart - end if +on __FindAllCallback pMessage + wait 0 with messages + set the cursor to busy +end __FindAllCallback + +private command goMatchingDefinition pMatch + local tObject, tLine + put item 5 to -1 of pMatch into tObject - # OK-2008-08-01 : Bug 6709 - On Macs, the option key should result in a copying drag. - if seGetPlatform() is not "MacOS" then - if the controlKey is "down" then - put "copy" into sDragMode - else - put "cut" into sDragMode - end if - else - if the optionKey is "down" then - put "copy" into sDragMode - else - put "cut" into sDragMode - end if - end if + put item 4 of pMatch into tLine - pass dragStart -end dragStart + revSEGoExecutionPoint tObject, tLine, true, true +end goMatchingDefinition -on dragEnd -end dragEnd + +private function getDisambiguatorObject + return the long id of stack "revSEDisambiguator" +end getDisambiguatorObject on exitField -- OK-2008-07-10 : Check that an object is loaded before attemping to save context, -- this is prevent annoying errors from ocurring when editing the IDE. - if sObjectId is not empty then + if getObjectID() is not empty then contextSave end if pass exitField @@ -3957,7 +1253,7 @@ end exitField on closeField -- OK-2008-07-10 : Check that an object is loaded before attemping to save context, -- this is prevent annoying errors from ocurring when editing the IDE. - if sObjectId is not empty then + if getObjectID() is not empty then contextSave end if pass closeField @@ -4016,6 +1312,8 @@ private function escapeString pString, pUseWildCard replace "}" with "\}" in pString replace ")" with "\)" in pString replace "(" with "\(" in pString + replace "|" with "\|" in pString + replace "-" with "\-" in pString # OK-2009-01-17 : Bug 7611 - Periods must be replaced as they match any char otherwise replace "." with "\." in pString @@ -4160,7 +1458,7 @@ command findMarkResult pStart, pEnd, pInteractive end if if sFirstFindObject is empty then - put sObjectid into sFirstFindObject + put getObjectID() into sFirstFindObject end if if sFirstFindLocation is empty or pInteractive then @@ -4177,7 +1475,7 @@ command findMarkResult pStart, pEnd, pInteractive put false into tFalseString send "update tFalseString" to group "Left Bar" of stack (revTargetStack(the long id of me)) - put sObjectId into sLastFindObject + put getObjectID() into sLastFindObject put pStart & comma & pEnd into sLastFindLocation end findMarkResult @@ -4208,7 +1506,7 @@ private function findObjectList pTarget, pDirection, pCallback, pCallbackTarget, # Sort the object list so that tabs are cycled through in order, starting with current object local tLineNumber set the wholeMatches to true - put lineOffset(seGetRuggedId(sObjectId), tObjectList) into tLineNumber + put lineOffset(seGetRuggedId(getObjectID()), tObjectList) into tLineNumber set the wholeMatches to false local tReorderedObjectList @@ -4226,26 +1524,26 @@ private function findObjectList pTarget, pDirection, pCallback, pCallbackTarget, else if pTarget is "card" then # This will search the card of the script editor's current object. This means the card itself # and all objects on it. - put findListObjectsOnCard(sObjectId) into tObjectList + put findListObjectsOnCard(getObjectID()) into tObjectList else if pTarget is "stack" then # Searches the stack of the sript editor's current object. This means the stack script itself, # and all other objects in the stack, including all cards but not substacks. - put findListObjectsOnStack(sObjectId) into tObjectList + put findListObjectsOnStack(getObjectID()) into tObjectList else if pTarget is "stack file" then # As with "stack" except also searches all stacks in the same file. - put findListObjectsOnStackAndSubstacks(sObjectId, false, pCallback, pCallbackTarget, rCancelled) into tObjectList + put findListObjectsOnStackAndSubstacks(getObjectID(), false, pCallback, pCallbackTarget, rCancelled) into tObjectList else if pTarget is "all stacks" then # Searches all stacks and substacks in memory put findListObjectsOnAllStacksAndSubstacks(pCallback, pCallbackTarget, rCancelled) into tObjectList else if pTarget is "stack file and stackfiles" then # As for "stack file" except also searches all available stacks in the stackFiles property - put findListObjectsOnStackAndSubstacks(sObjectId, true, pCallback, pCallbackTarget, rCancelled) into tObjectList + put findListObjectsOnStackAndSubstacks(getObjectID(), true, pCallback, pCallbackTarget, rCancelled) into tObjectList else if pTarget is "all available stacks" then # Searches all stacks and substacks in memory and all stackFiles. Note this is not recursive at the moment, i.e # stackFiles of stackFiles are not searched. put findListObjectsOnAllAvailableStacks(pCallback, pCallbackTarget, rCancelled) into tObjectList else - put sObjectId into tObjectList + put getObjectID() into tObjectList end if if tObjectList is an array then @@ -4355,15 +1653,11 @@ private function findListObjectsOnStackAndSubstacks pObject, pIncludeStackfiles, return empty end if - local tStackFileList - put empty into tStackFileList - get revIDEListSearchObjectTree(the name of stack tPath, false, empty, true, true, true, tStackFileList) - put tStackFileList after tList + get revIDEListSearchObjectTree(the name of stack tPath, false, empty, true, true, true, tList) end if unlock messages end repeat - delete the last char of tList end if return tList @@ -4501,10 +1795,6 @@ private function findDefaultSearch return tSearch end findDefaultSearch -command getLastSelectedChunk - return sLastSelectedChunk -end getLastSelectedChunk - # Parameters # (same as showNextFindResult and showPreviousFindResult) +: # pDirection : forward or backward @@ -4548,7 +1838,7 @@ private function findBuildSearch pQuery, pIsRegExp, pUseWildcard, pWholeMatch, p # Calculate the initial start and end for the search. local tLastFindLocation - if sLastFindObject is not empty and seGetRuggedId(sLastFindObject) is seGetRuggedId(sObjectId) then + if sLastFindObject is not empty and seGetRuggedId(sLastFindObject) is seGetRuggedId(getObjectID()) then put sLastFindLocation into tLastFindLocation end if @@ -4657,18 +1947,18 @@ command showNextFindResult pQuery, pIsRegExp, pUseWildCards, pWholeMatch, pIgnor lock screen local tStart repeat for each line tObject in tObjectList - if seGetRuggedId(tObject) is not seGetRuggedId(sObjectId) then + if seGetRuggedId(tObject) is not seGetRuggedId(getObjectID()) then revSESetCurrentObject tObject, empty, true put 1 into tStart else - if tStart is empty then + if sLastFindLocation is empty then # Must be the first iteration put tSearch["start"] into tStart else # Calculate a new search start - if sLastFindObject is not empty and seGetRuggedId(sLastFindObject) is seGetRuggedId(sObjectId) and sLastFindLocation is not empty then + if sLastFindObject is not empty and seGetRuggedId(sLastFindObject) is seGetRuggedId(getObjectID()) and sLastFindLocation is not empty then if pInteractive then - put item 1 of sLastFindLocation into tStart + put item 2 of sLastFindLocation into tStart else put item 1 of sLastFindLocation + 1 into tStart end if @@ -4684,7 +1974,7 @@ command showNextFindResult pQuery, pIsRegExp, pUseWildCards, pWholeMatch, pIgnor put the result into tResult unlock screen - if tResult is sFirstFindLocation and sObjectId is sFirstFindObject then + if tResult is sFirstFindLocation and getObjectID() is sFirstFindObject then --beep end if @@ -4703,7 +1993,7 @@ command showNextFindResult pQuery, pIsRegExp, pUseWildCards, pWholeMatch, pIgnor findText textGetScript(), false, 1, tSearch["start"], tSearch put the result into tResult - if tResult is sFirstFindLocation and sObjectId is sFirstFindObject then + if tResult is sFirstFindLocation and getObjectID() is sFirstFindObject then --beep end if @@ -4913,7 +2203,7 @@ command replaceOnce pString put tFrom into tAt textBeginGroup "Replace" - textReplace tAt, char tFrom to tTo of textGetScript(), pString + textReplace tAt, char tFrom to tTo of textGetScript(), pString, , , true # OK-2009-02-16 : Bug 7712 - Return information about the replaced text so that in a the context of replaceOnceAndFind, we can ensure # that the replaced text does not get searched. @@ -5060,10 +2350,12 @@ on mouseMove tooltipReset send "tooltipUpdate" to me in kTooltipUpdateDelay milliseconds put the result into sTooltipUpdateRequest + pass mouseMove end mouseMove on mouseLeave tooltipUpdateCancel + pass mouseLeave end mouseLeave # Description @@ -5088,9 +2380,9 @@ command tooltipUpdate # Get the list of variables available for either the handler the mouse is in, or the script. local tVariables if tHandler is empty then - put the revAvailableVariables of sObjectId into tVariables + put the revAvailableVariables of getObjectID() into tVariables else - put the revAvailableVariables[tHandler] of sObjectId into tVariables + put the revAvailableVariables[tHandler] of getObjectID() into tVariables end if # "Flatten" the list of variables- we don't care if they are locals, parameters, globals etc. @@ -5122,22 +2414,25 @@ command tooltipUpdate end if end if + local tContext + put seGetDebugContext() into tContext + # Find out if the variable is an array local tKeys - put revDebuggerGetKeys(tMouseVariable) into tKeys + put revDebuggerGetKeys(tMouseVariable, tContext) into tKeys # Get its value in the curent debug context from the debugger. Truncate to make sure we don't try and # display very large variables and format it for the tooltip. local tValue if tKeys is empty then - put tooltipTruncateValue(revDebuggerGetValue(tMouseVariable, empty, empty, empty), empty, 500) into tValue + put tooltipTruncateValue(revDebuggerGetValue(tMouseVariable, tContext, empty, empty), empty, 500) into tValue else repeat for each line tKey in line 1 to kTooltipArrayKeyCount of tKeys --local tExpression --put tMouseVariable & "[" & quote & tKey & quote & "]" into tExpression local tElementList put tKey into tElementList[1] - put tKey & " = " & tooltipTruncateValue(revDebuggerGetValue(tMouseVariable, ,tElementList, empty), 1, 200) & return after tValue + put tKey & " = " & tooltipTruncateValue(revDebuggerGetValue(tMouseVariable, tContext, tElementList, empty), 1, 200) & return after tValue end repeat delete the last char of tValue end if @@ -5283,25 +2578,6 @@ private command tooltipUpdateCancel put empty into sTooltipUpdateRequest end tooltipUpdateCancel -# Description -## Returns a line stripped of comments at the end of the line -private function lineStripComments pLine - local tOffset,tCommentChar - put offset("#", pLine) into tOffset - if tOffset = 0 then - put offset("--", pLine) into tOffset - put "--" into tCommentChar - else - put "#" into tCommentChar - end if - - if tCommentChar is empty then - return pLine - else - return char 1 to tOffset of pLine - end if -end lineStripComments - ---------------------------------------------------------------- -- Editor field cache ---------------------------------------------------------------- @@ -5434,3 +2710,212 @@ private command EditorFieldCacheSwap pOldRuggedObjectId, pNewRuggedObjectId -- controls. __EditorFieldCacheFlushExcess end EditorFieldCacheSwap + +# Parameters +# pRootObject : the object to list the tree for, this is a reference to any LiveCode object +# pIncludeSubstacks : if pRootObject is a mainstack, this determines whether or not its substacks are searched. Otherwise its ignored. +# Returns +# Empty if all possible objects were returned, otherwise a warning string explaining why some / all were ommited. +# Description +# rList will be set to the list of objects underneath the root object. This is inclusive, i.e. it includes pRootObject. +# If pRootObject is a mainstack, the stack will be searched, followed by all mainstacks if pIncludeSubstacks is true. +# If pRootObject is a stack, the object list is the stack, all its cards, and all objects on each card +# If pRootObject is a card the list is the card and all objects on it +# If pRootObject is any other control, the list is pRootObject. +function revIDEListSearchObjectTree pRootObject, pObeyDontSearch, pMarked, pIncludeSubstacks, pIgnorePasswordProtected, pScriptsOnly, @xList + --delete variable sAddedObjects + + # Put the root object into the list first. If this is not possible because to dontSearch or card marking then + # return an error and put empty into the list. What might also happen is that one of the child objects + # as its dontSearch set to true. In this case, we'll return a partial list. + if pObeyDontSearch and word 1 of the name of pRootObject is among the words of "field group card" and the dontSearch of pRootObject then + return "dontSearch of root object set" + end if + + # Set the HCAddressing property of the owning stack of pRootObject to false, as this will mess + # up everything otherwise. + local tOldHCAddressing + put the hcAddressing of stack revTargetStack(pRootObject) into tOldHCAddressing + set the hcAddressing of stack revTargetStack(pRootObject) to false + + # If the root object is a mainstack, we add the stack itself, then all its substacks if applicable + local tResult + switch word 1 of pRootObject + case "stack" + if the mainstack of pRootObject is the short name of pRootObject and pIncludeSubstacks then + addStack pRootObject, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly + put the result into tResult + + repeat for each line tSubstack in the substacks of pRootObject + local tSubstackResult + addStack the name of stack tSubstack, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly + put the result into tSubstackResult + if tResult is empty then + put tSubstackResult into tResult + end if + end repeat + else + # If its not a mainstack, or we're not adding substacks, just add the stack + addStack pRootObject, pObeyDontSearch, pMarked, pIgnorePasswordProtected, xList, pScriptsOnly + put the result into tResult + end if + break + case "card" + # If its a card then add the card and all its controls + addCard pRootObject, pObeyDontSearch, pMarked, xList, pScriptsOnly + put the result into tResult + break + case "group" + # If its a group then add the group and all its control + addGroup pRootObject, pObeyDontSearch, xList, pScriptsOnly + put the result into tResult + break + default + # All other objects, i.e non-containers, just add the single object to the list. + addObject pRootObject, pObeyDontSearch, xList, pScriptsOnly + put the result into tResult + break + end switch + + set the hcAddressing of stack revTargetStack(pRootObject) to tOldHCAddressing + + return tResult +end revIDEListSearchObjectTree + +private command addObject pObject, pObeyDontSearch, @xList, pScriptsOnly + if pObeyDontSearch and word 1 of the name of pObject is among the words of "card group field" and the dontSearch of pObject then + return "dontSearch set on object" + end if + + if not pScriptsOnly or the script of pObject is not empty then + put true into xList[the long id of pObject] + end if + + local tBehavior + put the behavior of pObject into tBehavior + repeat while exists(tBehavior) + put true into xList[the long id of tBehavior] + put the behavior of tBehavior into tBehavior + end repeat + + return empty +end addObject + +private command addCard pCard, pObeyDontSearch, pMarked, @xList, pScriptsOnly + if pMarked is not empty and pMarked is not the mark of pCard then + return "marked mismatch" + end if + + # Add the card itself + local tResult + addObject pCard, pObeyDontSearch, xList, pScriptsOnly + put the result into tResult + + # Add the non-grouped controls + local tObjectResult + local tControlID + repeat for each line tControlID in the childControlIDs of pCard + # Don't add groups + if word 1 of the name of control id tControlID of pCard is among the words of "group bkgnd" then + next repeat + end if + + # Don't add grouped controls + if the owner of control id tControlID of pCard is not empty and word 1 of the name of the owner of control id tControlID of pCard is among the words of "group bkgnd" then + next repeat + end if + + addObject the long id of control id tControlID of pCard, pObeyDontSearch, xList, pScriptsOnly + put the result into tObjectResult + + if tResult is empty then + put tObjectResult into tResult + end if + end repeat + + # Add any groups. + local tGroup, tGroupResult + local tID + repeat for each line tId in the groupIds of pCard + put the long id of group id tId of pCard into tGroup + if the sharedBehavior of tGroup then + next repeat + end if + + # Note that if a group on the card does not have its backgroundBehavior set, but is placed on multiple cards, + # it will be duplicated in the list. I'm not sure if this is correct or not... + addGroup tGroup, pObeyDontSearch, xList, pScriptsOnly + put the result into tGroupResult + + if tResult is empty then + put tGroupResult into tResult + end if + end repeat + + return tResult +end addCard + +private command addGroup pGroup, pObeyDontSearch, @xList, pScriptsOnly + if pObeyDontSearch and the dontSearch of pGroup then + return "dontSearch set on group" + end if + + local tResult + addObject pGroup, pObeyDontSearch, xList, pScriptsOnly + put the result into tResult + + local tObjectResult + local tControlID + repeat for each line tControlID in the controlIDs of pGroup + addObject the long id of control id tControlID of pGroup, pObeyDontSearch, xList, pScriptsOnly + put the result into tObjectResult + + if tResult is empty then + put tObjectResult into tResult + end if + end repeat + + return tResult +end addGroup + +private command addStack pStack, pObeyDontSearch, pMarked, pIgnorePasswordProtected, @xList, pScriptsOnly + local tResult + + if pIgnorePasswordProtected then + try + get the script of pStack + catch tError + return "Stack password protected" + end try + end if + + # The stack itself + addObject pStack, pObeyDontSearch, xList, pScriptsOnly + put the result into tResult + + # All shared groups groups on the stack + local tSharedGroupResult + local tGroupID + repeat for each line tGroupID in the sharedGroupIDs of pStack + addGroup the long id of control id tGroupID of pStack, pObeyDontSearch, xList, pScriptsOnly + put the result into tSharedGroupResult + + if tResult is empty then + put tSharedGroupResult into tResult + end if + end repeat + + # All the cards on the stack + local tCardResult + local tCardID + repeat for each line tCardID in the cardIDs of pStack + addCard the long id of card id tCardID of pStack, pObeyDontSearch, pMarked, xList, pScriptsOnly + put the result into tCardResult + + if tResult is empty then + put tCardResult into tResult + end if + end repeat + + return tResult +end addStack diff --git a/Toolset/palettes/script editor/behaviors/revseerrorspanebehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revseerrorspanebehavior.livecodescript new file mode 100644 index 0000000000..a838f5c1f5 --- /dev/null +++ b/Toolset/palettes/script editor/behaviors/revseerrorspanebehavior.livecodescript @@ -0,0 +1,229 @@ +script "revSEErrorsPaneBehavior" +# Stores the data for the nodes, an array with numeric keys that +# determine the order nodes appear in. The value of the array items +# is a string that is passed to the each item as parameters to the itemInit +# handler to allow each item to initialize itself +local sData + +private function listObject + if there is a group "List" of me then + return the long id of group "List" of me + else + return empty + end if +end listObject + +command paneOpenControl +end paneOpenControl + +command paneCloseControl + clearErrors +end paneCloseControl + +command paneResizeControl + ensureListObject + set the height of listObject() to the height of me + set the width of listObject() to the width of me - the width of scrollbar "Scrollbar" of me + set the topLeft of listObject() to the topLeft of me + updateList +end paneResizeControl + +# Description +# Sent by the parent when something that might have affected the error pane has changed. +# Causes the error pane to update itself. +command update + updateList +end update + +private command ensureListObject + local tObject + if listObject() is empty then + lock messages + copy group "List Template" of card "Templates" of stack (revTargetStack(the long id of me)) to me + put the long id of it into tObject + unlock messages + + set the name of tObject to "List" + set the lockLocation of tObject to true + set the cantDelete of tObject to false + set the showBorder of tObject to false + set the cMutable of tObject to true + else + put listObject() into tObject + end if + + set the cItemTemplate of tObject to itemTemplate() +end ensureListObject + +# Parameters +# pType : the error type, either "compilation", "execution" or "warning" +# pError : an error in the format returned by the result when setting a script +# Description +# Adds pError to the errors list. +command addError pType, pError, pObject + local tFormattedError + put formatError(pType, pError, pObject) into tFormattedError + if the cData of me is empty then + set the cData of me to tFormattedError + else + set the cData of me to tFormattedError & return & the cData of me + end if + + updateList +end addError + +command clearErrors + delete variable sData + ensureListObject + call "itemPurgeAll" to listObject() + set the cData of me to empty + set the cData of listObject() to empty + + updateList +end clearErrors + +# Parameters +# pType : the error type. This is either "execution", "compilation" or "warning" +# pError : an error in the format returned by the result of setting the script. +# pObject : reference to the object that the error is associated with +# Returns +# A string in the following format. +# <object> tab <type> tab <line> tab <char> tab <description> tab <token> +private function formatError pType, pError, pObject + local tLine, tPosition, tDescription, tToken + if pType is "compilation" then + put seErrorDescription(pType, pError) into tDescription + put item 2 of pError into tLine + put item 3 of pError into tPosition + put item 4 to -1 of pError into tToken + else if pType is "execution" then + put seErrorDescription(pType, pError) into tDescription + put item 4 to -1 of line 1 of pError into tToken + put item 2 of line 1 of pError into tLine + if tToken is "runtime" then + put empty into tToken + else + put item 3 of line 1 of pError into tPosition + end if + end if + + local tFormattedError + put pObject & tab & pType & tab & tLine & tab & tPosition & tab & tDescription & tab & tToken into tFormattedError + return tFormattedError +end formatError + +private command updateList + ensureListObject + + local tPrefs + put "marginLeft=5" & return & \ + "marginRight=5" & return & \ + "marginTop=10" & return & \ + "spacing=5" & return & \ + "justification=left" into tPrefs + + set the cPrefs of listObject() to tPrefs + + local tData + put the cData of me into tData + + # Show a nice green tick etc if no errors occurred + if tData is empty then + local tObject + revSEGetCurrentObject + put the result into tObject + put tObject & tab & "noerror" into tData + end if + + set the cData of listObject() to tData + + # Update the group + call "update" to listObject() + + # The scrolling is done separately to get around an engine bug (bz#4210) + updateScrollbar +end updateList + +private command updateScrollbar + lock screen + set the height of scrollbar "Scrollbar" of me to the height of listObject() + set the topRight of scrollbar "Scrollbar" of me to the topRight of listObject() + set the startValue of scrollbar "Scrollbar" of me to 0 + set the endValue of scrollbar "Scrollbar" of me to the formattedHeight of listObject() + 1 + set the lineInc of scrollbar "Scrollbar" of me to round(the formattedHeight of listObject() / 200) + set the pageInc of scrollbar "Scrollbar" of me to round(the height of listObject()) + set the thumbSize of scrollbar "Scrollbar" of me to 1 + set the thumbPosition of scrollbar "Scrollbar" of me to the vScroll of listObject() + set the visible of scrollbar "Scrollbar" of me to (the formattedHeight of listObject() > the height of listObject()) + unlock screen +end updateScrollbar + +# Returns a reference to the item template to use, this can be any control, and will be copied into the list +# for each item and send an itemInit message to initilize itself. Basically you can use any control, but the script +# of the control must handle the itemInit message. +private function itemTemplate + local tStackName + put revTargetStack(the long id of me) into tStackName + return the long id of group "Error Template" of card "Templates" of stack tStackName +end itemTemplate + +# Parameters +# pObject : reference to an object inside the errors group +# Returns +# The long id of the item that contains pObject (or pObject if already an item). +private function resolveItem pObject + if the cListItem of pObject is true then + return the long id of pObject + end if + + # For now the items only have one level of nested control ownership. + if the cListItem of the owner of pObject is true then + return the long id of the owner of pObject + end if +end resolveItem + +on mouseDoubleUp + local tItem + put resolveItem(the long id of the target) into tItem + if tItem is empty then + exit mouseDoubleUp + end if + + # If the "no errors occurred" object is clicked on, don't attempt to go to the error location. + if the cType of tItem is "noerror" then + exit mouseDoubleUp + end if + + local tObject + put the cObject of tItem into tObject + + local tLine + put the cLine of tItem into tLine + + local tPosition + put the cPosition of tItem into tPosition + + local tHighlightType + put "position" into tHighlightType + + revSESetCurrentObject tObject + send "goLine tLine, tHighlightType, tPosition" to group "Editor" +end mouseDoubleUp + +on mouseUp + local tItem + put resolveItem(the long id of the target) into tItem + if tItem is empty then + exit mouseUp + end if + + lock screen + repeat with x = 1 to the number of controls of me + if the cListItem of control x of me then + send "itemUnhilite" to control x of me + end if + end repeat + + send "itemHilite" to tItem + unlock screen +end mouseUp diff --git a/Toolset/palettes/script editor/behaviors/revseerrortemplatebehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revseerrortemplatebehavior.livecodescript new file mode 100644 index 0000000000..625acc2a0d --- /dev/null +++ b/Toolset/palettes/script editor/behaviors/revseerrortemplatebehavior.livecodescript @@ -0,0 +1,138 @@ +script "revSEErrorTemplateBehavior" +# Parameters +# pInfo : error information, format described below +# Description +# Initializes this error group with the specified information. +# pInfo is in the following format. +# <object> tab <type> tab <line> tab <char> tab <description> tab <token> +on itemInit pInfo + set the itemDelimiter to tab + + local tObjectId, tObject + put item 1 of pInfo into tObjectId + + local tType + put item 2 of pInfo into tType + + # If the type is "noerror" then we don't need to display the object + # this is important because sometimes the errors pane can be refreshed before + # any objects have been added to the script editor. In this case there will be + # no errors yet, so we check for "noerror" and only attempt to access tObjectId + # if there was an error. + if tType is not "noerror" then + put revDebuggerObjectName(tObjectId) into tObject + end if + + # Standard errors and warnings + if tType is "execution" or tType is "compilation" or tType is "warning" then + + local tLine + put item 3 of pInfo into tLine + + local tDescription + put item 5 of pInfo into tDescription + + local tToken + put item 6 of pInfo into tToken + + local tPosition + put item 4 of pInfo into tPosition + + local tLabel + if tType is "warning" then + put empty into tLabel + else + put " error" into tLabel + end if + + if tLine is 0 then + put "n/a" into tline + end if + + # Generate error messages that look something like this: + # Object: compilation error at line 10 (Expression: bad factor) near "blah", char 10 + local tErrorString + put tObject & ": " & tType & tLabel & " at line " & tLine & " (" & tDescription & ")" into tErrorString + if tToken is not empty then + put " near " & quote & tToken & quote after tErrorString + end if + if tPosition is not empty and tPosition is not 0 then + put ", char " & tPosition after tErrorString + end if + + + put tErrorString into field 1 of me + else + # tType may also be "noerror", in which case we just display this. + put "No errors occurred" into field 1 of me + end if + + local tIconId + put getIconId(tType) into tIconId + set the icon of button 1 of me to tIconId + + # Set some custom properties so that when the user selects this group, we know + # which error they want to display. + set the cObject of me to item 1 of pInfo + set the cLine of me to item 3 of pInfo + set the cPosition of me to item 4 of pInfo + set the cType of me to item 2 of pInfo + + resize +end itemInit + +command itemHilite + -- set the backgroundColor of field 1 of me to "210,210,210" + + # OK-2009-03-11 : Bug 7499 + local tHiliteColor + put sePrefGet("editor,hiliteColor") into tHiliteColor + if tHiliteColor is empty then + put the hiliteColor into tHiliteColor + end if + + if tHiliteColor is empty then + put "210,210,210" into tHiliteColor + end if + + if seGetPlatform() is not "MacOS" then + set the textColor of field 1 of me to "255,255,255" + end if + set the backgroundColor of field 1 of me to tHiliteColor +end itemHilite + +command itemUnhilite + if seGetPlatform() is not "MacOS" then + set the textColor of field 1 of me to "0,0,0" + end if + set the backgroundColor of field 1 of me to "255,255,255" +end itemUnhilite + + +# Description +# Sent by the parent when this object might be been resized. +# Updates the controls to reflect the current rect of the object. +command resize + set the topLeft of button 1 of me to the topLeft of me + set the width of field 1 of me to the width of me - the width of button 1 of me + set the topLeft of field 1 of me to the topRight of button 1 of me +end resize + +private function getIconId pType + if pType is "execution" then + return seGetIcon("errorsExecution") + end if + + if pType is "compilation" then + return seGetIcon("errorsCompilation") + end if + + if pType is "noerror" then + return seGetIcon("errorsNoError") + end if + + if pType is "warning" then + return 0 + end if +end getIconId + diff --git a/Toolset/palettes/script editor/behaviors/revsefindmaincardbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsefindmaincardbehavior.livecodescript new file mode 100644 index 0000000000..e52bf43981 --- /dev/null +++ b/Toolset/palettes/script editor/behaviors/revsefindmaincardbehavior.livecodescript @@ -0,0 +1,397 @@ +script "revSEFindMainCardBehavior" +local sCancelled = "false" + +# Returns +# The long id of the stack to use as a regular expression builder +function regularExpressionBuilder + local tPath + put revEnvironmentPluginsPath() & slash & "RegExBuilder 1.6.rev" into tPath + + if there is no file tPath then + return empty + else + return the long id of stack tPath + end if +end regularExpressionBuilder + +on preOpenCard + send "revSEFindInitialize" to (getCaller()) + --historyLoad + optionsHide + + --set the label of button "Toggle Options" of me to "+" + send "resetIcon" to button "Toggle Options" of me + statusSet empty + update + updateButtonStates +end preOpenCard + +on menuPick + updateButtonStates + pass menuPick +end menuPick + +on closeCard + historySave + local tCaller + put getCaller() into tCaller + if there is a stack tCaller then + send "revSEFindFinalize" to tCaller + end if + pass closeCard +end closeCard + +on escapeKey + close this stack +end escapeKey + +on commandKeyDown pKey + if pKey is not "v" then + pass commandKeyDown + end if + + # There are two possible pasting targets here, the find and replace combo boxes. In both these cases we have + # to ensure that multiple lines and formatted text cannot be pasted in. + local tTextToPaste + put line 1 of the clipboardData["text"] into tTextToPaste + + set the clipboardData["text"] to empty + set the clipboardData["html"] to empty + set the clipboardData["text"] to tTextToPaste + pass commandKeyDown +end commandKeyDown + +# Description +# Sets the properties of all controls on the card to their correct values according to the current context +command update + local tFindLabel + put getFindLabel() into tFindLabel + + local tFindText + put historyGet("find") into tFindText + if tFindLabel is not empty and tFindLabel is not among the lines of tFindText then + put tFindLabel & return & tFindText into tFindText + end if + + set the text of button "Find" of me to tFindText + set the label of button "Find" of me to "templabel" + set the label of button "Find" of me to tFindLabel + + local tReplaceLabel + put getReplaceLabel() into tReplaceLabel + + local tReplaceText + put historyGet("replace") into tReplaceText + if tReplaceLabel is not empty and tReplaceLabel is not among the lines of tReplaceText then + put tReplaceLabel & return & tReplaceText into tReplaceText + end if + + set the text of button "Replace" of me to tReplaceText + set the label of button "Replace" of me to "templabel" + set the label of button "Replace" of me to tReplaceLabel + + set the hilite of button "Case Sensitive Search" of me to sePrefGet("find,casesensitive") + set the hilite of button "Match Whole Words" of me to sePrefGet("find,wholematches") + set the hilite of button "regEx" of me to sePrefGet("find,regularexpressions") + if sePrefGet("find,wildcards") is true then + set the hilite of button "wildcards" of me to true + else + set the hilite of button "wildcards" of me to false + end if + + if sePrefGet("find,plaintext") is true then + set the hilite of button "plaintext" of me to true + else + set the hilite of button "plaintext" of me to false + end if + + ## Default + if the hilite of button "regEx" of me is false and the hilite of button "wildcards" of me is false and the hilite of button "plaintext" of me is false then + set the hilite of button "plaintext" of me to true + sePrefSet "find,plaintext", true + end if +end update + +# Updates the disabled state of the search action buttons according to the label of the target menu. +# This is needed because if searching all stacks, only replace all and find all are allowed. +command updateButtonStates + # If we are searching within objects in the script editor, we can do everything, otherwise, only + # find all and replace all are allowed. + if the label of button "Location" of me is "Current Tab" or the label of button "Location" of me is "All tabs" then + enable button "Find Next" of me + enable button "Replace one" of me + enable button "Find all" of me + enable button "Replace all" of me + enable button "Replace" of me + else + enable button "Find all" of me + + # Disable this for now as this feature could cause data-loss if not used properly + -- enable button "Replace all" of me + disable button "Replace all" of me + + disable button "Find Next" of me + disable button "Replace one" of me + disable button "Replace" of me + end if +end updateButtonStates + +private function getCaller + if there is a stack (the cCaller of the owner of me) then + return the long id of the cCaller of the owner of me + else + return empty + end if +end getCaller + +# Returns +# The label for the "Find" button. This is one of the following values if they exist, in order of preference: +# 1. The last selected text of the editor field in the script editor that called this stack +# 2. The last searched for term +# 3. empty +private function getFindLabel + send "revSEGetLastSelectedWord" to (getCaller()) + if the result is not empty then + return line 1 of the result + end if + + local tLastSearch + put line 1 of historyGet("find") into tLastSearch + if tLastSearch is not empty then + return tLastSearch + end if + + return empty +end getFindLabel + +# Returns +# The label for the "Replace" button. This is one of the following values if they exist, in order of preference: +# 1. The last term used to replace something +# 2. empty +private function getReplaceLabel + local tLastReplace + put line 1 of historyGet("replace") into tLastReplace + if tLastReplace is not empty then + return tLastReplace + end if + + return empty +end getReplaceLabel + +local sFindHistory +local sReplaceHistory +constant kHistorySize = 20 + +# Parameters +# pType : either "find" or "replace" +# Returns +# The history of the specified action type, one per line with most recent coming first. +private function historyGet pType + return seFindHistoryGet(pType) +end historyGet + +# Parameters +# pType : either "find" or "replace" +# pTerm: the find / replace term to add +# Description +# Adds the specified term to the history. +private command historyAdd pType, pTerm + seFindHistoryAdd pType, pTerm +end historyAdd + + +# Description +# Loads the history from the preferences +private command historyLoad + seFindHistoryLoad +end historyLoad + +# Description +# Saves the history to the preferences +private command historySave + seFindHistorySave +end historySave + +# Description +# Shows the find options +command optionsShow + lock screen + local tTop + put the top of the owner of me into tTop + set the height of the owner of me to the bottom of group "Options" of me + 5 + set the top of the owner of me to tTop + unlock screen +end optionsShow + +# Description +# Hides the find options +command optionsHide + lock screen + local tTop + put the top of the owner of me into tTop + set the height of the owner of me to the bottom of button "Find all" of me + 5 + set the top of the owner of me to tTop + unlock screen +end optionsHide + +command statusSet pStatus + set the text of field "Status" of me to pStatus +end statusSet + +private command getSearchContext @rQuery, @rReplace, @rRegularExpression, @rWildcards, @rWholeMatches, @rIgnoreCase, @rTarget + local tFindType + + put the label of button "Find" of me into rQuery + put the label of button "Replace" of me into rReplace + + put sePrefGet("find,regularexpressions") into rRegularExpression + put sePrefGet("find,wildcards") into rWildcards + + --put true into rWildcards + local tWholeMatches + put sePrefGet("find,wholematches") into rWholeMatches + put not sePrefGet("find,casesensitive") into rIgnoreCase + + switch the label of button "Location" of me + case "All tabs" + put "all" into rTarget + break + case "Current Tab" + put "current" into rTarget + break + case "Card" + put "card" into rTarget + break + case "Stack" + put "stack" into rTarget + break + case "Stack File" + put "stack file" into rTarget + break + case "All Stack Files" + put "all stacks" into rTarget + break + case "Stack File and its stackFiles" + put "stack file and stackfiles" into rTarget + break + case "All available stacks" + put "all available stacks" into rTarget + break + default + put "current" into rTarget + end switch +end getSearchContext + +local sLastQuery + +# Parameters +# pAction : either "findNext", "findAll", "replaceCurrent" or "replaceAll" +# Description +# Performs the specified find action, using the current values of the controls +# on this card to obtain all the required parameters +private command findAction pAction + statusSet empty + put false into sCancelled + + local tQuery, tReplace, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget + getSearchContext tQuery, tReplace, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget + + # Don't allow empty search requests to be sent to the script editor because it will + # assume that the user pressed a keyboard shortcut and will show the interactive find + # group. + if tQuery is empty then + exit findAction + end if + + switch pAction + case "findNext" + send "revSEFindNext tQuery, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget" to (getCaller()) + break + case "findAll" + local tCallback + put "findAllCallback" into tCallback + + local tCallbackTarget + put the long id of me into tCallbackTarget + + send "revSEFindAll tQuery, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget, tCallback, tCallbackTarget" to (getCaller()) + + statusSet empty + break + case "replaceCurrent" + send "revSEReplaceCurrent tQuery, tReplace, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget" to (getCaller()) + break + case "replaceAll" + put "replaceAllCallback" into tCallback + put the long id of me into tCallbackTarget + + local tReplacementCount + send "revSEReplaceAll tQuery, tReplace, tRegularExpression, tWildcards, tWholeMatches, tIgnoreCase, tTarget, tCallback, tCallbackTarget" to (getCaller()) + put the result into tReplacementCount + statusSet (tReplacementCount & " occurrences replaced") + break + end switch +end findAction + +# Description +# Finds the next ocurrence of the specified term and highlights it in the target script editor +command findNext + findAction "findNext" +end findNext + +# Description +# Replaces the currently highlighted ocurrence of the specified term with the contents of the replace button +# in the target script editor. +command replaceCurrent + findAction "replaceCurrent" +end replaceCurrent + +# Description +# Finds all matches for the specified term and displays them in the "Search Results" pane of the target script editor +command findAll + findAction "findAll" +end findAll + +# Description +# Replaces all matches for the specified term with the contents of the replace button +command replaceAll + findAction "replaceAll" +end replaceAll + +command findAllCallback pMessage + statusSet pMessage + + # This line allows any pending mouseUps on the cancel button to execute, + # allowing the search to be cancelled. + wait 1 millisecond with messages + + if sCancelled then + set the label of button "Find all" of me to empty + unlock cursor + put false into sCancelled + return "cancel" + else + return empty + end if +end findAllCallback + +command replaceAllCallback pMessage + statusSet pMessage + + # This line allows any pending mouseUps on the cancel button to execute, + # allowing the replace to be cancelled. + wait 1 millisecond with messages + + if sCancelled then + set the label of button "Replace all" of me to empty + unlock cursor + put false into sCancelled + return "cancel" + else + return empty + end if +end replaceAllCallback + +command cancelOperation + put true into sCancelled +end cancelOperation diff --git a/Toolset/palettes/script editor/behaviors/revsegutterbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsegutterbehavior.livecodescript index 8b9023c302..ad19de167f 100644 --- a/Toolset/palettes/script editor/behaviors/revsegutterbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsegutterbehavior.livecodescript @@ -33,9 +33,12 @@ local sErrors # Causes the gutter to update itself. command update pOffset, pSelectedLine, pOldNumber, pNewNumber, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw local tContext, tUpdateRequired + + lock screen put updateGetContext(pOffset, pSelectedLine, pOldNumber, pNewNumber, pTextChanged, pUpdateCompilationErrors, pForceBreakpointRedraw, tContext) into tUpdateRequired if not tUpdateRequired then + unlock screen exit update end if @@ -51,9 +54,7 @@ command update pOffset, pSelectedLine, pOldNumber, pNewNumber, pTextChanged, pUp put tContext["object"] into sLastObject end if - lock screen - - updateBreakpoints pOffset, pSelectedLine, pOldNumber, pNewNumber, pTextChanged, tContext + updateBreakpoints pOffset, pOldNumber, pNewNumber, pTextChanged, tContext updateLineNumbers pTextChanged, pOldNumber, pNewNumber, tContext updateCurrentLine tContext @@ -282,7 +283,7 @@ private command updateCurrentLine pContext put tArray["line number"] into tDebugLine end if - if (the long id of pContext["object"] is not the long id of tDebugObject) then + if (seGetRuggedId(pContext["object"]) is not seGetRuggedId(tDebugObject)) then exit updateCurrentLine end if @@ -310,6 +311,10 @@ end updateCurrentLine # Description # If there are not enough line numbers to add to the field command updateLineNumbers pTextEdited, pOldNumber, pNewNumber, pContext + + # only update if there's work to be done + if pContext["numberOfAdditions"] <= 0 then exit updateLineNumbers + # Add the lines in a non-locking manner, and after we've finished adding lines, the scroll # of the line numbers field should be updated. repeat pContext["numberOfAdditions"] times @@ -330,66 +335,67 @@ command addLines pNumberToAdd end addLines command updateCompilationErrors pContext - local tObject - if pContext["object"] is not empty then - put pContext["object"] into tObject - else - getObject - put the result into tObject - end if - if tObject is empty then - exit updateCompilationErrors - end if + local tObject + if pContext["object"] is not empty then + put pContext["object"] into tObject + else + getObject + put the result into tObject + end if - # Remove previous compilation errors - if pContext["errorImages"] is not empty then - repeat for each line tImageId in pContext["errorImages"] - delete image id tImageId of me - end repeat - else - clearCompilationErrors - end if + if there is not a tObject then + return "object does not exist" for error + end if + + # Remove previous compilation errors + if pContext["errorImages"] is not empty then + repeat for each line tImageId in pContext["errorImages"] + delete image id tImageId of me + end repeat + else + clearCompilationErrors + end if + + local tHorizontal + put item 1 of the loc of me into tHorizontal + + local tErrorNumber + put 1 into tErrorNumber - local tHorizontal - put item 1 of the loc of me into tHorizontal - - local tErrorNumber - put 1 into tErrorNumber - - local tVertical - local tDescription, tLine, tToken - repeat for each line tError in sErrors[seGetRuggedId(tObject)] - put seErrorDescription("compilation", item 1 of tError) into tDescription - put item 2 of tError into tLine - put item 4 to -1 of tError into tToken - put lineNumberToVerticalLoc(tLine) into tVertical - if tVertical is 0 then - # If 0 it means that the line number of the error is not within the gutter's current bounds - next repeat - end if - - local tImage - copy getErrorImageId() to group "Mutables" of me - put the long id of it into tImage - set the cError of tImage to true - set the cLine of tImage to tLine - set the tooltip of tImage to "Error (line " & tLine & "): " & tDescription - set the loc of tImage to tHorizontal, tVertical - set the name of tImage to "Error " & tErrorNumber - - add 1 to tErrorNumber - end repeat + local tVertical + local tDescription, tLine, tToken + repeat for each line tError in sErrors[seGetRuggedId(tObject)] + put seErrorDescription("compilation", item 1 of tError) into tDescription + put item 2 of tError into tLine + put item 4 to -1 of tError into tToken + put lineNumberToVerticalLoc(tLine) into tVertical + if tVertical is 0 then + # If 0 it means that the line number of the error is not within the gutter's current bounds + next repeat + end if + + local tImage + copy getErrorImageId() to group "Mutables" of me + put the long id of it into tImage + set the cError of tImage to true + set the cLine of tImage to tLine + set the tooltip of tImage to "Error (line " & tLine & "): " & tDescription + set the loc of tImage to tHorizontal, tVertical + set the name of tImage to "Error " & tErrorNumber + + add 1 to tErrorNumber + end repeat end updateCompilationErrors # Parameters # pObject : reference to the object to update breakpoint positions for -# pLine : the current line number +# pOffset : the offset of text replacement # pOldNumber : the number of lines previously in the script # pNewNumber : the number of lines now in the script # Description # Updates the the positions of breakpoints in response to the script being changed. -private command updateBreakpointPositions pObject, pOffset, pLine, pOldNumber, pNewNumber +private command updateBreakpointPositions pObject, pOffset, pOldNumber, pNewNumber local tNumber, tInsertion if pOldNumber = pNewNumber then @@ -399,56 +405,36 @@ private command updateBreakpointPositions pObject, pOffset, pLine, pOldNumber, p local tBreakpoints put revDebuggerListBreakpoints(pObject) into tBreakpoints + local tLineIndex + put the lineIndex of char pOffset of getScriptField() into tLineIndex + if pOldNumber < pNewNumber then repeat for each line tBreakpoint in tBreakpoints - # In the case that the line that contained the breakpoint was where the text replacement - # started, we have to check for one of three options. This is slow :( - if item -1 of tBreakpoint = pLine then - local tContext - put char 1 to pOffset of getScriptField() into tContext - local tNextChar - put char -1 of tContext into tNextChar + if item -1 of tBreakpoint = tLineIndex then + local tCharIndex + put the charIndex of line tLineIndex of getScriptField() into tCharIndex - local tPreviousChars - repeat with x = the number of chars of tContext - 1 down to 1 - if char x of tContext is empty or char x of tContext is return then - exit repeat - end if - put char x of tContext after tPreviousChars - end repeat + local tLine + put the text of line tLineIndex of getScriptField() into tLine - local tWhitespaceBefore - put matchText(tPreviousChars, "^\s*$") into tWhitespaceBefore - - local tEndofLine - put (tNextChar is return or tNextChar is empty) into tEndofLine - - # This means the user has split the line containing the breakpoint, in this case we leave the breakpoint as it was - if (not tWhitespaceBefore) and (not tEndofLine) then - next repeat - end if - - # This means that the user has added a return to the end of the line containing the breakpoint, again we ignore this - #if (tPreviousChar is not return and tPreviousChar is not empty) and (tNextChar is return or tNextChar is empty) then - if (not tWhitespaceBefore) and tEndofLine then - next repeat - end if + local tBefore + put char 1 to (pOffset - tCharIndex) of tLine into tBefore # This means that the user has added a return before the beginning of the line containing the breakpoint. We move the breakpoint # to follow the line. - if tWhitespaceBefore then + if word 1 of tBefore is empty then revDebuggerMoveBreakpoint item 1 to -2 of tBreakpoint, item -1 of tBreakpoint, item 1 to -2 of tBreakpoint, item -1 of tBreakpoint + (pNewNumber - pOldNumber) end if end if # If the line that contained the breakpoint was above the added text, leave it where it is - if item -1 of tBreakpoint < pLine then + if item -1 of tBreakpoint < tLineIndex then next repeat end if # If the line that contained the breakpoint was below the added text, move the breakpoint down by the number of lines added. - if item -1 of tBreakpoint > pLine then + if item -1 of tBreakpoint > tLineIndex then revDebuggerMoveBreakpoint item 1 to -2 of tBreakpoint, item -1 of tBreakpoint, item 1 to -2 of tBreakpoint, item -1 of tBreakpoint + (pNewNumber - pOldNumber) end if end repeat @@ -456,9 +442,9 @@ private command updateBreakpointPositions pObject, pOffset, pLine, pOldNumber, p local tScript put textGetScript() into tScript repeat for each line tBreakpoint in tBreakpoints - if (item -1 of tBreakpoint >= pLine and item -1 of tBreakpoint < (pLine - (pNewNumber - pOldNumber))) and revDebuggerNextAvailableBreakpoint(tScript, item -1 of tBreakpoint + (pNewNumber - pOldNumber)) <> item -1 of tBreakpoint + (pNewNumber - pOldNumber) then + if (item -1 of tBreakpoint > tLineIndex and item -1 of tBreakpoint <= (tLineIndex - (pNewNumber - pOldNumber))) and revDebuggerNextAvailableBreakpoint(tScript, item -1 of tBreakpoint - 1 + (pNewNumber - pOldNumber)) <> item -1 of tBreakpoint + (pNewNumber - pOldNumber) then revDebuggerRemoveBreakpoint item 1 to -2 of tBreakpoint, item -1 of tBreakpoint - else if item -1 of tBreakpoint > (pLine + pNewNumber - pOldNumber) then + else if item -1 of tBreakpoint >= (tLineIndex - (pNewNumber - pOldNumber)) then # If the breakpoint was below the removed lines, move it up revDebuggerMoveBreakpoint item 1 to -2 of tBreakpoint, item -1 of tBreakpoint, item 1 to -2 of tBreakpoint, item -1 of tBreakpoint + (pNewNumber - pOldNumber) end if @@ -466,7 +452,7 @@ private command updateBreakpointPositions pObject, pOffset, pLine, pOldNumber, p end if end updateBreakpointPositions -private command updateBreakpoints pOffset, pSelectedLine, pOldNumber, pNewNumber, pTextChanged, pContext +private command updateBreakpoints pOffset, pOldNumber, pNewNumber, pTextChanged, pContext clearMutableObjects local tObject @@ -477,8 +463,12 @@ private command updateBreakpoints pOffset, pSelectedLine, pOldNumber, pNewNumber put the result into tObject end if + if there is not a tObject then + return "object does not exist" for error + end if + if pTextChanged then - updateBreakpointPositions tObject, pOffset, pSelectedLine, pOldNumber, pNewNumber + updateBreakpointPositions tObject, pOffset, pOldNumber, pNewNumber end if # Get a list of the breakpoints set on the current object using revDebuggerListBreakpoints. @@ -668,38 +658,44 @@ on mouseUp pButtonNumber exit mouseUp end if + local tTarget, tClickLoc + put the long id of the target into tTarget + put the clickloc into tClickLoc + # 2017-08-01 bhall2001 + # bugfix 20214 handle changes to gutter directly + gutterMouseUp tTarget, tClickLoc +end mouseUp + +on gutterMouseUp pTarget, pClickLoc local tObject revSEGetCurrentObject put the result into tObject - if the cBreakpoint of the target or the short name of the target is "Current Line" then + if the cBreakpoint of pTarget or the short name of pTarget is "Current Line" then # The current line image doesn't do anything itself, but it can be above a breakpoint. # In this case we want it to be as though the user clicked on the breakpoint. This is done # simply by changing the tTarget variable to contain a reference to the breakpoint image # instead of the original target. - local tTarget - put the long id of the target into tTarget - local tBreakpointImage - put breakpointCovered(tTarget) into tBreakpointImage + put breakpointCovered(pTarget) into tBreakpointImage if tBreakpointImage is not empty then - put tBreakpointImage into tTarget + put tBreakpointImage into pTarget end if - if the cState of tTarget is "active" then - revDebuggerRemoveBreakpoint tObject, (the cLine of tTarget) + if the cState of pTarget is "active" then + revDebuggerRemoveBreakpoint tObject, (the cLine of pTarget) else # A breakpoint is invalid if it is not currently placed on a valid line of executable code, # e.g. a commented line, variable declaration etc. - if the cInvalid of tTarget or not revDebuggerEnabled() or seGetObjectState(tObject) is not "applied" then - revDebuggerRemoveBreakpoint tObject, (the cLine of tTarget) + if the cInvalid of pTarget or not revDebuggerEnabled() or seGetObjectState(tObject) is not "applied" then + revDebuggerRemoveBreakpoint tObject, (the cLine of pTarget) else - revDebuggerActivateBreakpoint tObject, (the cLine of tTarget) + revDebuggerActivateBreakpoint tObject, (the cLine of pTarget) end if end if else local tLineNumber - put verticalLocToLineNumber(item 2 of the clickLoc) into tLineNumber + put verticalLocToLineNumber(item 2 of pClickLoc) into tLineNumber if tLineNumber is not empty then # Adjust the line number to find the next available breakpoint @@ -721,12 +717,12 @@ on mouseUp pButtonNumber lock screen clearMutableObjects - updateBreakpoints 1, 1, 1, 1, false - # OK-2010-02-26: Avoid delays when updating breakpoints by only updating the breakpoints pane + updateBreakpoints 1, 1, 1, false + # OK-2010-02-26: Avoid delays when updating breakpoints by only updating the breakpoints pane -- sePanesUpdate seRefreshCurrentPaneIfItsBreakpoints unlock screen -end mouseUp +end gutterMouseUp on menuPick pItemName # The target appears to be wrong in this case. As there is only currently one menu @@ -761,7 +757,7 @@ on menuPick pItemName lock screen clearMutableObjects - updateBreakpoints 1, 1, 1, 1, false + updateBreakpoints 1, 1, 1, false # OK-2010-02-26: Avoid delays when updating breakpoints by only updating the breakpoints pane -- sePanesUpdate @@ -773,6 +769,10 @@ on rawKeyDown # Block this message as the gutter must only be scrolled in response to the main script field end rawKeyDown +on scrollBarDrag + # Block this message as the gutter must only be scrolled in response to the main script field +end scrollBarDrag + # Returns # A random name used for naming mutable controls. In particular, breakpoint images. private function controlRandomName diff --git a/Toolset/palettes/script editor/behaviors/revsehandlerlistbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsehandlerlistbehavior.livecodescript index e25c5bd61c..4f5c12574b 100644 --- a/Toolset/palettes/script editor/behaviors/revsehandlerlistbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsehandlerlistbehavior.livecodescript @@ -31,6 +31,11 @@ command initializeWithoutGrabbingFocus end initializeWithoutGrabbingFocus command updateSelectedHandler + if the cSelectedHandler of me is empty then + set the hilitedLines of field "Handlers" of me to empty + exit updateSelectedHandler + end if + local tLineNumber put 1 into tLineNumber @@ -124,6 +129,7 @@ function handlerTypeSortCallback pItem end switch end handlerTypeSortCallback +constant kDefaultHandlerTextColor = "#777777" # Description # Called when the group might need to be updated. Updates the handler list. Also resizes the group. @@ -133,6 +139,24 @@ command update call "revSEGetHandlerList" to the cCaller of me put the result into tHandlers + local tDefaultHandlers, tIndex + if sePrefGet("editor,showDefaultHandlers") then + put revSEDefaultHandlers() into tDefaultHandlers + end if + set the wholematches to false + + local tCanAdd + repeat for each line tLine in tDefaultHandlers + if lineOffset(tLine, tHandlers) is not 0 then + next repeat + end if + if tCanAdd is empty then + put tLine into tCanAdd + else + put return & tLine after tCanAdd + end if + end repeat + filterHandlerNames tHandlers if sePrefGet("editor,sortHandlerList") is "alphabetical" then @@ -148,26 +172,50 @@ command update sort tHandlers by handlerTypeSortCallback(word 1 of each) & word 2 of each end if + if tHandlers is not empty then + put return & return & return after tHandlers + end if + put tCanAdd after tHandlers + # Populate the handlers field with the formatted list of handlers local tText, tIcon repeat for each line tHandler in tHandlers - local tParseHandler + local tParseHandler, tHandlerExists + put true into tHandlerExists put word 1 to 2 of tHandler into tParseHandler + if the number of words in tHandler is 1 then + put false into tHandlerExists + -- Existing handler names have a space after the icon + put " " before tParseHandler + end if + put "<p>" after tText local tIsPrivate put false into tIsPrivate - if char 1 of tParseHandler is "P" then + if tHandlerExists and char 1 of tParseHandler is "P" then put true into tIsPrivate delete char 1 of tParseHandler end if - - put getIcon(char 1 of tParseHandler, tIsPrivate) into tIcon + + if tHandlerExists then + put getIcon(char 1 of tParseHandler, tIsPrivate) into tIcon + if tIcon is not empty then + delete char 1 of tParseHandler + end if + else + put the id of image "icon-add.png" of stack "revIcons" into tIcon + end if + if tIcon is not empty then put merge("<sup shift=2><img src=[[tICon]]></img></sup>") after tText end if - delete char 1 of tParseHandler + + if not tHandlerExists then + put merge("<font color='[[kDefaultHandlerTextColor]]'>[[tParseHandler]]</font>") \ + into tParseHandler + end if put tParseHandler & "</p>" after tText end repeat @@ -221,23 +269,45 @@ command resize unlock screen end resize -command closeAccept - lock screen - local tHandler - put line (the hilitedLine of field "Handlers" of me) of the cHandlers of field "Handlers" of me into tHandler - +command jumpToHandler pHandler, pAdded local tLineNumber - put word 3 of tHandler into tLineNumber + put word 3 of pHandler into tLineNumber # OK-2009-03-03: Bug 7450 - Also return the handler type, this will allow us to detect # if the handler line number is wrong (due to uncompiling script). - set the cChoice of me to tLineNumber & comma & word 2 of tHandler & comma & word 1 of tHandler + set the cChoice of me to tLineNumber & comma & word 2 of pHandler & comma & word 1 of pHandler if the cCallback of me is not empty then - send the cCallback of me to the cCallbackTarget of me + send the cCallback of me && pAdded to the cCallbackTarget of me end if hideGroup +end jumpToHandler + +command handlerPicked pHandler + local tAdded + put false into tAdded + if the number of words in pHandler is 1 then + put true into tAdded + -- Adding a default handler + revSEAddDefaultHandler pHandler + update + set the wholematches to false + local tLine + put lineOffset(pHandler, the cHandlers of field "Handlers" of me) into tLine + select line tLine of field "Handlers" of me + put line tLine of the cHandlers of field "Handlers" of me into pHandler + end if + + -- Select the (now) extant handler + jumpToHandler pHandler, tAdded +end handlerPicked + +command closeAccept + lock screen + local tHandler + put line (the hilitedLine of field "Handlers" of me) of the cHandlers of field "Handlers" of me into tHandler + handlerPicked tHandler unlock screen end closeAccept diff --git a/Toolset/palettes/script editor/behaviors/revseinteractivefindbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revseinteractivefindbehavior.livecodescript index ead9125d43..46e35dbdb6 100644 --- a/Toolset/palettes/script editor/behaviors/revseinteractivefindbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revseinteractivefindbehavior.livecodescript @@ -7,10 +7,14 @@ command openControl # OK-2009-03-10 : Bug 7070 - The match case check box should take the current preference value. set the hilite of button "Case" of me to (sePrefGet("find,casesensitive") is true) - local tLastSearch - put line 1 of seFindHistoryGet("find") into tLastSearch - if tLastSearch is not empty then - put tLastSearch into field "Find" of me + local tSearch + put revSEGetSelectedText() into tSearch + if tSearch is empty then + put line 1 of seFindHistoryGet("find") into tSearch + end if + + if tSearch is not empty then + put tSearch into field "Find" of me else put empty into field "Find" of me end if diff --git a/Toolset/palettes/script editor/behaviors/revseleftbarbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revseleftbarbehavior.livecodescript index de3f603711..9fcb15b232 100644 --- a/Toolset/palettes/script editor/behaviors/revseleftbarbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revseleftbarbehavior.livecodescript @@ -98,7 +98,7 @@ end updateSelectedHandler # Description # Callback for the handler list object. This is called when the stack is closed # which either means the user has chosen a handler, or dismissed the stack. -on handlerSelected +on handlerSelected pNewlyAdded local tObject put the long id of group "Left Handler List" of me into tObject @@ -115,6 +115,13 @@ on handlerSelected # the handler correctly we call this function which will check if tLine is wrong, and attempt to adjust it. put seLocateHandler(tHandler, tLine, tType) into tLine - send "goLine tLine, true" to group "Editor" + -- If we just added this handler, select at the (empty) line after the handler decl. + if pNewlyAdded then + add 1 to tLine + send "goLine tLine, after" to group "Editor" + else + send "goLine tLine, true" to group "Editor" + end if + seUpdateToolbar end handlerSelected diff --git a/Toolset/palettes/script editor/behaviors/revsemenubarbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsemenubarbehavior.livecodescript index d3547afc28..ccd6222d22 100644 --- a/Toolset/palettes/script editor/behaviors/revsemenubarbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsemenubarbehavior.livecodescript @@ -2,7 +2,15 @@ # Description # Sent by the parent when the menubar group may need to resize itself command resize - # Nothing to do at the moment + lock screen + local tTopLeft + put the topLeft of button "File" of me into tTopLeft + repeat for each item tButton in "File,Edit,Debug,Handler,Window,Help" + set the width of button tButton of me to the formattedWidth of button tButton of me + set the topLeft of button tButton of me to tTopLeft + put the topRight of button tButton of me into tTopLeft + end repeat + unlock screen end resize # Description @@ -117,22 +125,32 @@ private command buildEditMenu pContext end if put "Paste/V" & return & \ - "Select All/A" & return & \ - "Revert" & return & \ - "-" & return & \ - "Comment/-" & return & \ - "Uncomment/_" & return & \ - "-" & return & \ - "Quick Find/F" & return & \ - "Find and Replace.../^@F" & return & \ - "Find Selection/^#F" & return & \ - "Go.../L" & return after tEdit + "Select All/A" & return & \ + "Revert" & return & \ + "-" & return & \ + "Comment/-" & return & \ + "Uncomment/_" & return & \ + "-" & return & \ + "Quick Find/F" & return & \ + "Find and Replace.../^@F" & return & \ + "Find Selection/^#F" & return & \ + "Go.../L" & return after tEdit + + if revEnvironmentEditionProperty("autocomplete_pro") then + put "Autocomplete Snippets..." & return after tEdit + end if - if sePrefGet("explicitVariables") then - put "!cVariable Checking" & return after tEdit - else - put "!nVariable Checking" & return after tEdit + put "Options" & return after tEdit + put toggleMenuItem(tab & "Variable Checking", sePrefGet("explicitVariables")) & return after tEdit + put toggleMenuItem(tab & "Live Errors", sePrefGet("editor,liveerrors")) & return after tEdit + put toggleMenuItem(tab & "Bracket Completion", sePrefGet("editor,bracketcompletion")) & return after tEdit + put toggleMenuItem(tab & "Bracket Highlighting", sePrefGet("editor,brackethighlighting")) & return after tEdit + put toggleMenuItem(tab & "Control Structure Completion", sePrefGet("editor,autocomplete")) & return after tEdit + + if revEnvironmentEditionProperty("autocomplete") then + put toggleMenuItem(tab & "Autocomplete", sePrefGet("editor,providercompletion")) & return after tEdit end if + put toggleMenuItem(tab & "Autoformat", sePrefGet("editor,autoformat")) & return after tEdit put "-" & return & \ "Preferences" after tEdit @@ -275,18 +293,41 @@ private command buildHandlerMenu pContext local tFormattedHandlers repeat for each line tHandler in tHandlers - put word 2 of tHandler & return after tFormattedHandlers + put tab & word 2 of tHandler & return after tFormattedHandlers end repeat delete the last char of tFormattedHandlers - if the number of lines of tHandlers = 0 then - put "(No Handlers" into tFormattedHandlers - set the cHandlers of me to empty + local tDefaultHandlers + put revSEDefaultHandlers() into tDefaultHandlers + + local tFormattedDefaultHandlers + repeat for each line tHandler in tDefaultHandlers + put tab & tHandler & return after tFormattedDefaultHandlers + end repeat + delete the last char of tFormattedDefaultHandlers + + local tShowDefaultHandlers + dispatch function "sePrefGet" to me with "editor,showDefaultHandlers" + put the result into tShowDefaultHandlers + + local tMenu + if tHandlers is not empty then + put enableMenuItem("Go to handler...", true) into tMenu + put return & tFormattedHandlers after tMenu + else + put enableMenuItem("Go to handler...", false) into tMenu + end if + if tDefaultHandlers is not empty then + put return & enableMenuItem("Add default handler...", true) after tMenu + put return & tFormattedDefaultHandlers after tMenu else - set the cHandlers of me to tHandlers + put return & enableMenuItem("Add default handler...", false) after tMenu end if + put return & toggleMenuItem("Show default handlers", tShowDefaultHandlers) after tMenu - set the text of button "Handler" of me to modifyMenu("Handler", tFormattedHandlers) + set the cHandlers of me to tHandlers + + set the text of button "Handler" of me to modifyMenu("Handler", tMenu) end buildHandlerMenu on menuPick pItemName @@ -321,15 +362,31 @@ private command handleHandlerMenuPick pItemName exit handleHandlerMenuPick end if - local tLineNumber - put the menuHistory of button "Handler" of me into tLineNumber - - local tHandler - put line tLineNumber of the cHandlers of me into tHandler + set the itemdelimiter to "|" + switch item 1 of pItemName + case "Go to handler..." + local tPick, tHandlerInfo + put item 2 of pItemName into tPick + if not matchText(the cHandlers of me, "(.* " & tPick & " .*)", \ + tHandlerInfo) then + exit handleHandlerMenuPick + end if + + dispatch "handlerPicked" to group "Left Handler List" \ + with tHandlerInfo + break + case "Add default handler..." + dispatch "handlerPicked" to group "Left Handler List" \ + with item 2 of pItemName + break + case "Show default handlers" + local tShowDefaultHandlers + dispatch function "sePrefGet" to me with "editor,showDefaultHandlers" + put the result into tShowDefaultHandlers + dispatch "sePrefSet" to me with "editor,showDefaultHandlers", not tShowDefaultHandlers + break + end switch - local tScriptLineNumber - put word 3 of tHandler into tScriptLineNumber - send "goLine tScriptLineNumber, true" to group "Editor" seUpdateLeftBar seUpdateToolbar end handleHandlerMenuPick @@ -403,12 +460,33 @@ private command handleEditMenuPick pItemName case "Revert" actionRevert break - case "Variable Checking" + case "Options|Variable Checking" sePrefSet "explicitVariables", (not sePrefGet("explicitVariables")) break + case "Options|Live Errors" + sePrefSet "editor,liveerrors", (not sePrefGet("editor,liveerrors")) + break + case "Options|Bracket Completion" + sePrefSet "editor,bracketcompletion", (not sePrefGet("editor,bracketcompletion")) + break + case "Options|Bracket Highlighting" + sePrefSet "editor,brackethighlighting", (not sePrefGet("editor,brackethighlighting")) + break + case "Options|Control Structure Completion" + sePrefSet "editor,autocomplete", (not sePrefGet("editor,autocomplete")) + break + case "Options|Autocomplete" + sePrefSet "editor,providercompletion", (not sePrefGet("editor,providercompletion")) + break + case "Options|Autoformat" + sePrefSet "editor,autoformat", (not sePrefGet("editor,autoformat")) + break case "Preferences" actionShowPreferences break + case "Autocomplete Snippets..." + actionAutocompleteSnippetManager + break end switch end handleEditMenuPick @@ -500,6 +578,7 @@ private command handleHelpMenuPick pItemName case "Resource Center" case "Start Center" revIDEOpenPalette pItemName + break case "User Guide" revIDELaunchResource pItemName break @@ -511,6 +590,20 @@ end handleHelpMenuPick ######### +private function toggleMenuItem pItem, pHilited + if pHilited then + return "!c" & pItem + end if + return "!n" & pItem +end toggleMenuItem + +private function enableMenuItem pItem, pEnabled + if pEnabled then + return pItem + end if + return "(" & pItem +end enableMenuItem + private function modifyMenu pMenuName, pMenu if the last char of pMenu is not return then put return after pMenu diff --git a/Toolset/palettes/script editor/behaviors/revsescripttabsbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsescripttabsbehavior.livecodescript index e174ee34a9..735e5b2ff7 100644 --- a/Toolset/palettes/script editor/behaviors/revsescripttabsbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsescripttabsbehavior.livecodescript @@ -317,7 +317,7 @@ command addTab pObject put tControl into sTabButtonMap[the number of lines of the keys of sTabMap] set the cRawLabel of tControl to tFriendlyName set the visible of tControl to true - set the cTooltip of tControl to the long name of tObject + set the cTooltip of tControl to revDebuggerObjectLongName(tObject) local tNewWidth put min(kMaxTabWidth, the cFormattedWidth of tControl + 5) into tNewWidth @@ -759,7 +759,7 @@ private command contextMenuPick pItemName switch pItemName case "Close tab" - revSERemoveTargetObject sTabMap[tTabNumber] + deleteTab tTabNumber break case "Close other tabs" @@ -807,7 +807,7 @@ private command contextMenuPick pItemName lock screen local tObjectToMove put sTabMap[tTabNumber] into tObjectToMove - revSERemoveTargetObject tObjectToMove + deleteTab tTabNumber revEditScriptInNewWindow tObjectToMove break @@ -882,7 +882,7 @@ on mouseUp pButtonNumber if the long id of the target is the long id of button "Close" of me then lock screen - revSERemoveTargetObject sTabMap[sSelectedTab] + deleteTab sSelectedTab unlock screen exit mouseUp end if @@ -915,7 +915,7 @@ on mouseUp pButtonNumber # The icon on the left of the tabs is a close button if the short name of the target is "Tab Icon" then - revSERemoveTargetObject sTabMap[tClickedTabNumber] + deleteTab tClickedTabNumber else # Clicking anywhere else in the tab selects it @@ -932,6 +932,10 @@ on mouseUp pButtonNumber unlock screen end mouseUp +private command deleteTab pWhich + send "revSERemoveTargetObject sTabMap[pWhich]" to me in 0 millisecs +end deleteTab + private command updateToggleIcon local tMode revSEGetMode diff --git a/Toolset/palettes/script editor/behaviors/revsestackbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsestackbehavior.livecodescript index a21714c760..1ad593b3c7 100644 --- a/Toolset/palettes/script editor/behaviors/revsestackbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsestackbehavior.livecodescript @@ -11,12 +11,16 @@ on setBehaviors set the behavior of group "Variables" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("variablespane") set the behavior of group "Documentation" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("documentationpane") set the behavior of group "Breakpoints" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("breakpointpane") + set the behavior of group "Errors" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("errorspane") set the behavior of field "Filter" of group "Variables" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("filterfield") set the behavior of button "Show Globals" of group "Variables" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("variablescheckbox") set the behavior of button "Show Environment Vars" of group "Variables" of group "Panes" of me to the long id of stack revIDEScriptEditorBehavior("variablescheckbox") set the behavior of group "Gutter" of group "Editor" of me to the long id of stack revIDEScriptEditorBehavior("gutter") set the behavior of group "Interactive Find" of group "Editor" of me to the long id of stack revIDEScriptEditorBehavior("interactive find") set the behavior of stack "revSEEditBreakpoint" of me to the long id of stack revIDEScriptEditorBehavior("edit breakpoint") + set the behavior of group "Error Template" of card "Templates" of me to the long id of stack revIDEScriptEditorBehavior("error template") + set the behavior of stack revIDEScriptEditorBehavior("editor") to the long id of stack revIDEScriptEditorBehavior("common editor") + set the behavior of card "main" of stack "revSEFind" to the long id of stack revIDEScriptEditorBehavior("find main card") end setBehaviors # Which metadata type to store the script editor data as. @@ -718,6 +722,10 @@ function seDebugContexts end seDebugContexts local sDebugContext +function seGetSelectedDebugContext + return sDebugContext +end seGetSelectedDebugContext + function seGetDebugContext local tMode revSEGetMode @@ -794,6 +802,17 @@ end seGetObjectState # Stores the specified state for the object for later use. And updates any # script editor components that may depend on this information. command seSetObjectState pObject, pState + if pState is "edited" then + local tObj + put the long id of pObject into tObj + if not revIDEObjectIsOnIDEStack(tObj) then + local tParams + put the text of field "Script" into tParams[1] + put tObj into tParams[2] + send "ideMessageSendWithParameters" && "ideScriptEdited, tObj, tParams" to stack "revIDELibrary" in 0 milliseconds + end if + end if + # Small optimization, if pState is equal to the current state, don't do anything if pState is sObjectStates[seGetRuggedId(pObject)] then exit seSetObjectState @@ -848,7 +867,7 @@ command sePanesUpdate # OK-2008-09-11 : Refactored to prevent direct interaction with the Documentation pane. This needs further work # as it will soon be possible to have multiple panes open. if tToken is not empty then - if ideDocsFetchLCSData(tToken) is not empty then + if ideDocsFetchScriptData(tToken) is not empty then sePrefSet "documentation,lastLoadedDoc", tToken sePrefSet "documentation,lastMatchingSearch", tToken sePrefSet "documentation,lastLoadedAlternativeDocs", tToken @@ -895,11 +914,11 @@ end sePaneMaximumHeight # Parameters # pType : either "compilation", "execution" or "warning" -# pErrorId : the id of an error as returned by the engine. +# pErrorId : the error string # Returns # The description of the specified error. -function seErrorDescription pType, pErrorId - return revIDELookupError(pType, pErrorId) +function seErrorDescription pType, pError + return revIDELookupError(pType, pError) end seErrorDescription # Parameters @@ -907,17 +926,7 @@ end seErrorDescription # Description # Returns a friendly form of the object name suitable for displaying on tabs, etc. function seFriendlyObject pObject - local tFriendlyName - put word 1 of the name of pObject & space into tFriendlyName - - # This means that the object essentially has no name, eg its name is: card id 1002 or similar. - if the name of pObject is the short name of pObject then - put word -1 of the short name of pObject after tFriendlyName - else - put quote & the short name of pObject & quote after tFriendlyName - end if - - return tFriendlyName + return revDebuggerObjectName(pObject) end seFriendlyObject # Parameters @@ -1246,106 +1255,59 @@ function seFriendlyShortcut pAction end seFriendlyShortcut # Parameters -# pText : the word to search for, note this is not necessarily a variable / handler name +# pText : the word to search for, note this is not necessarily a handler name # pObject : reference to the object containing the text # pHandler : the handler that the matching text was found in in the form <type>,<name> (or empty) # Returns -# A list, one per line, of the matching definitions (either variable declarations or handler names) +# A list, one per line, of the matching handler definitions # for pText. Empty if none could be found. # Note that for now, only handler definitions are returned. function seMatchingDefinitions pText, pObject, pHandler - # It is possible in Revolution to have variables and handlers with the same names, so we simply - # search both variable names and handler names for pText, and return the whole list, the user can - # then disambiguate from this. - -- local tVariables - -- if pHandler is not empty then - -- put the effective revAvailableVariables[pHandler] of pObject into tVariables - -- else - -- put the effective revAvailableVariables of pObject into tVariables - -- end if + local tObject - local tHandlers - put the effective revAvailableHandlers of pObject into tHandlers + local tUses + put the revBehaviorUses of pObject into tUses + if exists(tUses[1]) then + put tUses[1] into tObject + else + put pObject into tObject + end if - local tMatches + local tDescription + put the effective revScriptDescription of tObject into tDescription - # First search the variables. Its not possible to have two variables with the same name, so we simply return the first - # one we find, after getting as much information as possible about it. - -- local tLineNumber, tItemNumber - -- set the wholeMatches to true - -- put 1 into tLineNumber - -- repeat for each line tLine in tVariables - - -- put itemOffset(pText, tLine) into tItemNumber - -- if tItemNumber <> 0 then - -- exit repeat - -- end if - - -- add 1 to tLineNumber - -- end repeat - - -- if tItemNumber is not empty and tItemNumber is not 0 then - -- put "variable," into tMatches - - -- if pHandler is not empty then - -- switch tLineNumber - -- case 1 - -- put "parameter" after tMatches - -- break - -- case 2 - -- put "local" after tMatches - -- break - -- case 3 - -- put "script local" after tMatches - -- break - -- case 4 - -- put "global" after tMatches - -- break - -- end switch - -- else - -- switch tLineNumber - -- case 1 - -- return "script local" - -- break - -- case 2 - -- return "global" - -- break - -- end switch - -- end if - -- put comma after tMatches - - -- put item tItemNumber of line tLineNumber of tVariables after tMatches - -- put comma & the long id of pObject after tMatches - -- put return after tMatches - -- end if + local tObjectDescription + if pObject is not tObject then + put the revScriptDescription of pObject into tObjectDescription + end if - # Next search the handlers. We return all applicable handlers, even if they have the same name, and let the user disambiguate. - local tObject, tResult - repeat for each line tHandler in tHandlers - if word 5 to -1 of tHandler is not empty then - put word 5 to -1 of tHandler into tObject - end if - - if word 2 of tHandler is not pText then - next repeat + local tMatches + repeat with tIndex = 1 to the number of elements of tDescription + if pObject is not tObject then + if tDescription[tIndex]["object"] is the long id of tObject and \ + tDescription[tIndex]["description"]["handlers"][pText]["is_private"] then + next repeat + end if + + if tDescription[tIndex]["object"] is the long id of pObject then + put tObjectDescription into tDescription[tIndex]["description"] + end if end if - put "handler," into tResult - - local tIsPrivate, tType - if char 1 of word 1 of tHandler is "P" then - put true into tIsPrivate - put char 2 of word 1 of tHandler into tType - else - put false into tIsPrivate - put char 1 of word 1 of tHandler into tType + if tDescription[tIndex]["description"]["handlers"][pText] is an array then + local tType + if tDescription[tIndex]["description"]["handlers"][pText]["is_private"] then + put "private" && tDescription[tIndex]["description"]["handlers"][pText]["type"] into tType + else + put tDescription[tIndex]["description"]["handlers"][pText]["type"] into tType + end if + + put "handler", \ + tType, \ + pText, \ + tDescription[tIndex]["description"]["handlers"][pText]["start_line"], \ + tDescription[tIndex]["object"] & return after tMatches end if - - put seFriendlyHandlerType(tType, tIsPrivate) & comma after tResult - put word 2 of tHandler & comma after tResult - put word 3 of tHandler & comma after tResult - put tObject after tResult - put tResult & return after tMatches end repeat delete the last char of tMatches @@ -1546,7 +1508,7 @@ private command applyScript pObject, pIgnoreErrors, @rCompilationErrors local tStack put revTargetStack(pObject) into tStack - revSetEdited tStack + revIDESetEdited tStack # OK-2008-08-19 : Bug 6947 - The script checksum is updated regardless of whether or not the compilation succeeded, # as the script is still set if it failed. If there was an execution error of course, it won't have been set. This is typically @@ -1598,7 +1560,7 @@ private command compileScript pObject, pIgnoreErrors send "setCompilationErrors line 1 of tCompilationResult, pObject" to group "Editor" of me # If there were errors and the errors pane is folded down, expand it to make the errors clear. - # Don't do this is there weren't any as the "no error occured" message is less important. + # Don't do this is there weren't any as the "no error occurred" message is less important. if sePrefGet("showerrors") then send "expandCurrentPane" to group "Panes" of me end if @@ -1929,12 +1891,6 @@ command actionPreviousScriptTab send "goPreviousTab" to group "Script Tabs" of me end actionPreviousScriptTab -# Description -# Launches the message box -command actionLaunchMessageBox - revIDEShowMessageBox -end actionLaunchMessageBox - # Description # Sends the current window to the back. command actionSendWindowToBack @@ -2184,6 +2140,14 @@ command actionQuit quit end actionQuit +command actionAutocompleteSnippetManager + modeless "com.livecode.palette.autocomplete-pro" +end actionAutocompleteSnippetManager + +command actionLaunchMessageBox + revIDEOpenPalette "Message Box" +end actionLaunchMessageBox + ################################################################################ # # Keyboard shortcut handling @@ -2309,6 +2273,8 @@ command seFinalize seFindHistorySave sePrefSave seHistorySave + + put empty into sDebugContext end seFinalize # Returns @@ -2646,7 +2612,12 @@ end closeStackRequest # This handles tabKey based keyboard shortcuts. The only one by default is to switch between tabs # Note that only command + tab shortcuts are allowed to prevent interference with other functions. on tabKey - if the commandKey is not "down" then + # bhall2001-2017-07-18: Bug 18366 On MacOS, Use control+tab to cycle between tabs + if (the commandKey is not "down") and (the platform is not "MacOS") then + pass tabKey + end if + + if (the platform is "MacOS") and (the controlKey is not "down") then pass tabKey end if @@ -2813,7 +2784,7 @@ end seUpdateWindowTitle # The title that the script editor window should have if pObject is the current object # being edited. function seCreateWindowTitle pObject - return the long name of pObject & " - Code Editor" + return revDebuggerObjectLongName(pObject) & " - Code Editor" end seCreateWindowTitle command seUpdateCheckSum pObject, @pScript @@ -2937,6 +2908,142 @@ on revSESetScript pScript dispatch "textSetScript" to field "Script" of me with pScript end revSESetScript +function revSEGetScript pScript + dispatch function "textGetScript" to field "Script" of me + return the result +end revSEGetScript + on revSEIndentScript dispatch "scriptFormat" to field "Script" of me with "script" end revSEIndentScript + +on revSEApply pIgnoreErrors + actionCompile pIgnoreErrors +end revSEApply + +function revSEGetSelectedText + return the selectedText of field "Script" of me +end revSEGetSelectedText + +private command appendToList @xList, pValue + if xList is not empty then + put return & pValue after xList + else + put pValue into xList + end if +end appendToList + +local sHandlersA +private function getHandlerList pObjType + get the keys of sHandlersA[pObjType] + sort it + return it +end getHandlerList + +private function revSEDefaultHandlerInfoForObjectType pObjType + if sHandlersA[pObjType] is not empty then + return getHandlerList (pObjType) + end if + + local tMessages + put ideDocsFetchLCSElementsOfType("message") into tMessages + + local tMessageList + repeat for each element tElement in tMessages + local tAssociations + put tElement["Associations"] into tAssociations + filter elements of tAssociations with pObjType + if tAssociations is not empty then + put tElement into tMessageList[tElement["display name"]] + end if + end repeat + put tMessageList into sHandlersA[pObjType] + return getHandlerList(pObjType) +end revSEDefaultHandlerInfoForObjectType + +private function revSEDefaultHandlerInfoForWidget pWidgetKind + if sHandlersA[pWidgetKind] is not empty then + return getHandlerList(pWidgetKind) + end if + local tMessages + put ideDocsFetchExtensionElementsOfType(pWidgetKind, "message") into tMessages + + local tMessageList + repeat for each element tElement in tMessages + put tElement into tMessageList[tElement["display name"]] + end repeat + put tMessageList into sHandlersA[pWidgetKind] + return getHandlerList(pWidgetKind) +end revSEDefaultHandlerInfoForWidget + +function revSEDefaultHandlers + local tObject + revSEGetCurrentObject + put the result into tObject + if tObject is empty then + return empty + end if + return revSEDefaultHandlersForObject(tObject) +end revSEDefaultHandlers + +function revSEDefaultHandlersForObject pObj + local tType + put word 1 of the name of pObj into tType + if tType is "widget" then + local tKind + put the kind of pObj into tKind + return revSEDefaultHandlerInfoForWidget(tKind) + end if + + return revSEDefaultHandlerInfoForObjectType(tType) +end revSEDefaultHandlersForObject + +function revSEConstructDefaultScript pObj, pHandler + local tType + put word 1 of the name of pObj into tType + if tType is "widget" then + put the kind of pObj into tType + end if + + local tInfo + put sHandlersA[tType][pHandler] into tInfo + + local tScript + -- Don't include summary for now as it has some docs specific markup + --put "--" && tInfo["Summary"] & return into tScript + put "on" && pHandler after tScript + repeat with x = 1 to the number of elements in tInfo["params"] + if x is not 1 then + put "," after tScript + end if + put " " & tInfo["params"][x]["name"] after tScript + end repeat + local tIndent + repeat for sePrefGet("editor,tabdepth") + put space after tIndent + end repeat + put return & tIndent & return & "end" && pHandler after tScript + return tScript +end revSEConstructDefaultScript + +command revSEAddDefaultHandler pHandler + local tDefaultScript, tObject + revSEGetCurrentObject + put the result into tObject + put revIDEDefaultScript(tObject, pHandler) into tDefaultScript + + if tDefaultScript is empty then + put revSEConstructDefaultScript(tObject, pHandler) into tDefaultScript + end if + + local tNewScript + put revSEGetScript() into tNewScript + if tNewScript is not empty then + if the last line of tNewScript is not empty then + put return after tNewScript + end if + put return after tNewScript + end if + put tDefaultScript after tNewScript + revSESetScript(tNewScript) +end revSEAddDefaultHandler diff --git a/Toolset/palettes/script editor/behaviors/revsetoolbarbehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsetoolbarbehavior.livecodescript index cf9343f94c..f01ff06736 100644 --- a/Toolset/palettes/script editor/behaviors/revsetoolbarbehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsetoolbarbehavior.livecodescript @@ -276,13 +276,9 @@ private function debugContextShort pContext local tArray put revDebuggerParseExecutionContext(pContext) into tArray - local tControl, tCommand, tName, tResult - --put item 2 to -3 of pContext into tControl - put tArray["object"] into tControl - put "put the name of tControl into tName" into tCommand - do tCommand + local tName, tResult + put seFriendlyObject(tArray["object"]) into tName - --put tName & comma & " line " & item -1 of pContext into tResult put tName & comma & " line " & tArray["line number"] into tResult return tResult diff --git a/Toolset/palettes/script editor/behaviors/revseutilities.livecodescript b/Toolset/palettes/script editor/behaviors/revseutilities.livecodescript index affbe131b0..7a6c99db65 100644 --- a/Toolset/palettes/script editor/behaviors/revseutilities.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revseutilities.livecodescript @@ -400,7 +400,12 @@ end seSendCallbacks # Returns # The value of the preference setting, or empty if not found. function sePrefGet pTag - return sPrefs[pTag] + if pTag is "editor,font" and \ + sPrefs[pTag] is empty and \ + "Source Code Pro" is among the lines of the fontNames then + return "Source Code Pro" + end if + return sPrefs[pTag] end sePrefGet # Parameters @@ -577,7 +582,6 @@ command sePrefGetDefaults put "166,202,240" into tPrefs["editor,selectbackgroundcolor"] put "255,255,255" into tPrefs["editor,backgroundcolor"] put "255,255,255" into tPrefs["editor,debugBackgroundcolor"] - put "true" into tPrefs["editor,autocomplete"] put "true" into tPrefs["editor,hscrollbar"] put "false" into tPrefs["editor,useInteractiveFind"] @@ -659,6 +663,17 @@ command sePrefGetDefaults put 7 into tPrefs["print,textSize"] + put true into tPrefs["editor,showDefaultHandlers"] + + put true into tPrefs["editor,liveerrors"] + put true into tPrefs["editor,bracketcompletion"] + put true into tPrefs["editor,brackethighlighting"] + put "255,200,200" into tPrefs["editor,brackethighlightcolor"] + -- autocomplete is legacy control structure completion + put true into tPrefs["editor,autocomplete"] + -- autocomplete is completions list + put true into tPrefs["editor,providercompletion"] + return tPrefs end sePrefGetDefaults @@ -1029,7 +1044,7 @@ command revSEColorizeField pField, pStart, pEnd end if if pEnd is empty then - put the number of chars of pField into pEnd + put the number of chars in the text of pField into pEnd end if sePrefInit @@ -1096,16 +1111,24 @@ end getFirstIndentLevel # The default script that the script editor should use for objects of the specified # type if they have no script set. Returns empty if no default script is to be used. function seDefaultScript pObjectType, pStyle + # AL-2015-09-21: [[ Bug 15961 ]] Add default mouseup handler to opaque button + local tIndent + put getFirstIndentLevel() into tIndent switch pObjectType - case "button" - # AL-2015-09-21: [[ Bug 15961 ]] Add default mouseup handler to opaque button - local tIndent - put getFirstIndentLevel() into tIndent + case "button" if pStyle is among the items of "standard,rectangle,checkbox,radiobutton,transparent,opaque" then return "on mouseUp" & return & tIndent & return & "end mouseUp" else if pStyle is "menu" then return "on menuPick pItemName" & return & tIndent & "switch pItemName" & return & tIndent & tIndent & return & tIndent & "end switch" & return & "end menuPick" end if + break + case "scrollbar" + if pStyle is among the items of "scale,scrollbar" then + return "local sStartValue" & return & return & "on mouseDown --save the initial value" & return &\ + tIndent & "put the thumbPos of me into sStartValue" & return & "end mouseDown" & return & return &\ + "on scrollbarDrag newValue -- save the final value" & return & tIndent & return & "end scrollbarDrag" + end if + break case "widget" return revIDEWidgetDefaultScript(pStyle) break diff --git a/Toolset/palettes/script editor/behaviors/revsevariablespanebehavior.livecodescript b/Toolset/palettes/script editor/behaviors/revsevariablespanebehavior.livecodescript index f6efa1ba1f..25be631b9a 100644 --- a/Toolset/palettes/script editor/behaviors/revsevariablespanebehavior.livecodescript +++ b/Toolset/palettes/script editor/behaviors/revsevariablespanebehavior.livecodescript @@ -6,6 +6,10 @@ local sTimes local sVisualizationObjects local sVisualizationObjectCount = 0 +local sContext +local sLastUpdateContext +local sUpdateHasRun = "false" + command paneOpenControl setDefaultsAndCallbacks refresh @@ -29,23 +33,11 @@ command paneResizeControl resize end paneResizeControl -local sContext - -local sLastUpdateContext -local sUpdateHasRun = "false" - command update pEnvironmentChanged - local tCurrentContext - put seGetDebugContext() & the width of me & the height of me into tCurrentContext + put seGetDebugContext() into sContext + put sContext & the width of me & the height of me into sLastUpdateContext - put tCurrentContext into sLastUpdateContext - updateDo pEnvironmentChanged - put true into sUpdateHasRun -end update - -private command updateDo pEnvironmentChanged lock screen - put seGetDebugContext() into sContext if pEnvironmentChanged is not "false" then applyPreferences @@ -58,7 +50,9 @@ private command updateDo pEnvironmentChanged updateVisualizationObjects unlock screen -end updateDo + + put true into sUpdateHasRun +end update command refresh update @@ -133,8 +127,6 @@ private command applyPreferences */ end applyPreferences -local sDebugContext - private function buildTree local tTreeA, tTopNodes @@ -182,9 +174,9 @@ private function buildTopNodes end repeat delete the last char of tTopNodes end if - + # Show the remaining variables only in debugging mode. - if seGetDebugContext() is not empty then + if sContext is not empty then if the cShowGlobals of me is true then # All global variables are currently being shown, so we only need to add the local variables to the list get processVariableNames(revDebuggerLocalNames(sContext)) @@ -257,6 +249,7 @@ end flattenVariableList private on pathToVariableComponents pPath, @rVariableName, @rDimensions local tCount + set the itemdel to the pathDelimiter of widget "tree" of me repeat for each item tItem in pPath add 1 to tCount if tCount is 1 then @@ -326,12 +319,16 @@ private on nodeCreateVisualizationObject pPathToNode revMetadataSet the name of stack tStack, "general", "visualizer", true -- generate variable visualizer UI + local tOldDefaultStack + put the defaultStack into tOldDefaultStack set the defaultStack to the short name of tStack reset the templateButton set the height of the templateButton to 23 create button "Apply" reset the templateField + set the vScrollbar of the templateField to true create field "Value" + reset the templateField set the lockText of the templateField to true create field "Name" @@ -346,6 +343,7 @@ private on nodeCreateVisualizationObject pPathToNode reset the templateButton reset the templateField set the lockMessages to tOldLock + set the defaultStack to tOldDefaultStack return tStack end nodeCreateVisualizationObject @@ -380,12 +378,9 @@ end visualizationObjectSetValue private function friendlyNodeReference pNodeReference local tString - local tVariable, tDimensions pathToVariableComponents pNodeReference, tVariable, tDimensions - put tVariable into tString - repeat with x = 1 to the number of elements of tDimensions put "[" & friendlyKey(tDimensions[x]) & "]" after tString end repeat @@ -532,4 +527,7 @@ private command setDefaultsAndCallbacks set the cCallback of tFilter to "filterChanged" set the cCallbackTarget of tFilter to the long id of me set the cPlaceholderText of tFilter to "Search variables..." + + set the pathDelimiter of widget "tree" of me to numToCodepoint(0) + set the sortType of widget "tree" of me to "numeric" end setDefaultsAndCallbacks diff --git a/Toolset/palettes/script editor/revscripteditor.8.rev b/Toolset/palettes/script editor/revscripteditor.8.rev old mode 100755 new mode 100644 index 00c4081e2f..a894191841 Binary files a/Toolset/palettes/script editor/revscripteditor.8.rev and b/Toolset/palettes/script editor/revscripteditor.8.rev differ diff --git a/Toolset/palettes/snippet viewer/behaviors/revidesnippetviewerbehavior.livecodescript b/Toolset/palettes/snippet viewer/behaviors/revidesnippetviewerbehavior.livecodescript new file mode 100644 index 0000000000..9d4ae8c7fe --- /dev/null +++ b/Toolset/palettes/snippet viewer/behaviors/revidesnippetviewerbehavior.livecodescript @@ -0,0 +1,93 @@ +script "revIDESnippetViewerBehavior" +command setAsBehavior pTarget + set the behavior of pTarget to the long id of this me +end setAsBehavior + +command revIDESnippetViewerColor + dispatch "revSEColorizeField" to stack "revSEUtilities" \ + with the long id of field "Snippet" of me +end revIDESnippetViewerColor + +private function _GetSnippetText + return the text of field "Snippet" of me +end _GetSnippetText + +command revIDESnippetViewerSetSnippet pText + put pText into field "Snippet" of me + revIDESnippetViewerColor +end revIDESnippetViewerSetSnippet + +constant kMargin = 5 +command revIDESnippetViewerResize + local tCopyToClipboard, tCopyToSE, tSnippet + put the long id of button "Copy to clipboard" of me \ + into tCopyToClipboard + put the long id of button "Copy to Script Editor" of me \ + into tCopyToSE + put the long id of field "Snippet" of me into tSnippet + + local tCardRect + put the rect of card 1 of me into tCardRect + + local tFieldWidth + put item 3 of tCardRect - item 1 of tCardRect - 2*kMargin into tFieldWidth + + local tButtonWidth + put (tFieldWidth - kMargin) / 2 into tButtonWidth + + set the width of tCopyToClipboard to tButtonWidth + set the width of tCopyToSE to tButtonWidth + + set the bottomleft of tCopyToClipboard to \ + item 1 of tCardRect + kMargin, \ + item 4 of tCardRect - kMargin + + set the bottomright of tCopyToSE to \ + item 3 of tCardRect - kMargin, \ + item 4 of tCardRect - kMargin + + set the rect of tSnippet to \ + item 1 of tCardRect + kMargin, \ + item 2 of tCardRect + kMargin, \ + item 3 of tCardRect - kMargin, \ + the top of tCopyToSE - kMargin + unlock screen +end revIDESnippetViewerResize + +command revIDESnippetViewerCopyToClipboard + lock clipboard + set the rawClipboardData["text"] to _GetSnippetText() + unlock clipboard +end revIDESnippetViewerCopyToClipboard + +command revIDESnippetViewerCopyToScriptEditor pEditor + local tNewScript + dispatch function "revSEGetScript" to stack pEditor + put the result into tNewScript + + if tNewScript is not empty then + if the last line of tNewScript is not empty then + put return after tNewScript + end if + put return after tNewScript + end if + put _GetSnippetText() after tNewScript + dispatch "revSESetScript" to stack pEditor with tNewScript +end revIDESnippetViewerCopyToScriptEditor + +on mouseUp + switch the short name of the target + case "Copy to clipboard" + revIDESnippetViewerCopyToClipboard + break + case "Copy to Script Editor" + local tScriptEditors + put revListScriptEditors() into tScriptEditors + if tScriptEditors is empty then + answer error "No script editor window to copy snippet to" + else + revIDESnippetViewerCopyToScriptEditor line 1 of tScriptEditors + end if + break + end switch +end mouseUp diff --git a/Toolset/palettes/snippet viewer/revidesnippetviewer.livecode b/Toolset/palettes/snippet viewer/revidesnippetviewer.livecode new file mode 100644 index 0000000000..4227c8afe8 Binary files /dev/null and b/Toolset/palettes/snippet viewer/revidesnippetviewer.livecode differ diff --git a/Toolset/palettes/splash/revSplash.livecode b/Toolset/palettes/splash/revSplash.livecode index 93ea85573c..b2fa58e7ce 100644 Binary files a/Toolset/palettes/splash/revSplash.livecode and b/Toolset/palettes/splash/revSplash.livecode differ diff --git a/Toolset/palettes/splash/revsplashstackbehavior.livecodescript b/Toolset/palettes/splash/revsplashstackbehavior.livecodescript new file mode 100644 index 0000000000..635bd6c58c --- /dev/null +++ b/Toolset/palettes/splash/revsplashstackbehavior.livecodescript @@ -0,0 +1,23 @@ +script "revSplashStackBehavior" +on preOpenStack + local tSplashPath + + lock messages + put revEnvironmentEditionProperty("skin") & "/splash.png" into tSplashPath + set the textColor of this card to revEnvironmentEditionProperty("revsplash_text_color") + set the textAlign of field "status" to "center" + set the top of field "status" to 270 + set the width of field "status" to the width of card 1 of me * 0.8 + set the left of field "status" of me to the width of card 1 of me * 0.1 + set the filename of image "Splash" to tSplashPath + set the id of image "Splash" to the id of stack "revIcons" + set the location of me to the screenLoc + + set the htmlText of field "License" to revEnvironmentEditionProperty("splash_strap") + + unlock messages +end preOpenStack + +setProp statusMessage pMessage + put pMessage into field "status" of me +end statusMessage diff --git a/Toolset/palettes/standalone settings/revstandalonesettings.8.rev b/Toolset/palettes/standalone settings/revstandalonesettings.8.rev old mode 100755 new mode 100644 index 3116973432..3221f81dc9 Binary files a/Toolset/palettes/standalone settings/revstandalonesettings.8.rev and b/Toolset/palettes/standalone settings/revstandalonesettings.8.rev differ diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsandroidbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsandroidbehavior.livecodescript index de79c37a90..12d5d42fb2 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsandroidbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsandroidbehavior.livecodescript @@ -7,8 +7,19 @@ end preOpenCard on initialize local tSettings put getSettings() into tSettings - set the hilite of button "Build for Android" to tSettings["android"] is true - set the enabled of button "Build for Android" to true + local tEnabled = false + repeat for each item tItem in revSBPlatformArchitectures("Android") + set the hilite of button ("Android" && tItem) of group "Android targets" of me to tSettings["Android",tItem] is true + if tSettings["Android",tItem] then + put true into tEnabled + end if + end repeat + + if not tEnabled and tSettings["android"] is true then + set the hilite of button "Android armv7" of group "Android targets" of me to true + put true into tSettings["Android,armv7"] + setSettings tSettings + end if -- PM-2014-03-17: [[ In App Purchasing Updates ]] Port over old style in app purchasing permissions. if "BILLING" is among the keys of tSettings["android,application permissions"] then @@ -40,7 +51,7 @@ on updateSettings --put computeDefault(tSettings["android,label"], tSettings["name"]) into field "Label" - set the unicodeText of field "Label" to uniEncode(computeDefault(tSettings["android,label"], tSettings["name"]), "UTF8") + set the text of field "Label" to computeDefault(tSettings["android,label"], tSettings["name"]) put computeDefault(tSettings["android,identifier"], "com.yourcompany.yourapp") into field "Identifier" put computeDefault(tSettings["android,version name"], "1.0.0") into field "Version Name" @@ -78,6 +89,14 @@ on updateSettings put computeDefault(tSettings["android,hardware accelerated"], false) into tHardwareAccelerated set the hilited of button "Hardware Accelerated" to tHardwareAccelerated + local tNFC + put computeDefault(tSettings["android,nfc"], false) into tNFC + set the hilited of button "NFC Tag Reading" to tNFC + + local tAllowHttpConnections + put computeDefault(tSettings["android,allow http"], false) into tAllowHttpConnections + set the hilited of button "Allow Http Connections" to tAllowHttpConnections + repeat with i = 1 to the number of groups of group "device capabilities" get tSettings["android,device capabilities"][the short name of group i of group "Device Capabilities"] if it is "true" then @@ -101,11 +120,49 @@ on updateSettings end updateSettings on updateAndroidSettingState - set the enabled of group "Android Settings" of me to (the hilite of button "Build for Android" of me) - set the visible of button "Androidchecked" to (the hilite of button "Build for Android" of me) + local tSettings + put getSettings() into tSettings + local tEnabled = false + repeat for each item tItem in revSBPlatformArchitectures("Android") + if tSettings["Android",tItem] then + put true into tEnabled + end if + end repeat + set the enabled of group "Android Settings" of me to tEnabled + set the visible of button "Androidchecked" to tEnabled set the opaque of button "Androidchecked" to false + + -- splash screen is not supported in Indy and Business editions + if revLicenseType() is "commercial" \ + or revLicenseType() is "professional" then + set the enabled of button "Splash Chooser" of group "Android Settings" of me to false + end if end updateAndroidSettingState +on updateAndroidArch pArch, pBuild + local tSettingsA + put getSettings() into tSettingsA + + put pBuild into tSettingsA["Android",pArch] + + local tEnabled = false + repeat for each item tItem in revSBPlatformArchitectures("Android") + if tSettingsA["Android",tItem] then + put true into tEnabled + exit repeat + end if + end repeat + put tEnabled into tSettingsA["Android"] + setSettings tSettingsA + + if tEnabled then + buildForEnabled "android" + end if + + revSetEdit + updateAndroidSettingState +end updateAndroidArch + -- PM-2014-03-17: [[ In App Purchasing Updates ]] Updated UI to support new store types. on updateInAppPurchaseSettings local tSettings diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsbehavior.livecodescript index 96b5034720..ed6a0d9c27 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsbehavior.livecodescript @@ -31,7 +31,8 @@ private command updateTabButtons pSettings end repeat set the visible of button "OSXchecked" of group "checks" of me to tEnableMacTick - set the visible of button "Windowschecked" of group "checks" of me to pSettings["Windows"] = true + set the visible of button "Windowschecked" of group "checks" of me to pSettings["Windows"] = true or \ + pSettings["Windows x86-64"] = true // SN-2015-01-13: [[ Bug 14373 ]] Check also if Linux 64 or Linux ARM are checked set the visible of button "UnixChecked" of group "checks" of me to pSettings["Linux"] = true \ or pSettings["Linux x64"] = true \ @@ -144,11 +145,10 @@ on revStandaloneSettings pStack end revStandaloneSettings on revSetEdit pStack - global gRevStackStatus if pStack = "" then put getTargetStackName() into pStack end if - put "edited" into gRevStackStatus[pStack] + revIDESetEdited pStack end revSetEdit constant kButtonWidth = 66 @@ -176,9 +176,13 @@ command updateCardSize end updateCardSize on resumeStack - if the short name of this stack is "revStandaloneSettings" then - send "preOpenCard" to the current card - end if + if the short name of this stack is "revStandaloneSettings" then + local tMainstack + put the mainStack of the topStack into tMainstack + if tMainstack is getTargetStack() then + send "preOpenCard" to this card of me in 0 millisecs + end if + end if end resumeStack # Parameters @@ -218,16 +222,7 @@ function getImageDimensions pImageFile end getImageDimensions function validateIdentifier pIdentifier - local tValid - - put true into tValid - set the itemDelimiter to "." - repeat for each item tItem in pIdentifier - if tItem is a number then - put false into tValid - end if - end repeat - return tValid + return matchText(pIdentifier, "(?i)^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$") end validateIdentifier on revUpdateStandaloneProgress pMessage @@ -373,7 +368,7 @@ on revRecursiveRemoveStackFiles pStack,pRemoveList, @xStackFileList put tRef&cr after tNewStackFiles if the effective fileName of stack item 1 of tRef is not among the lines of xStackFileList then put the effective fileName of stack item 1 of tRef & cr after xStackFileList - revRecursiveRemoveStackFiles the effective fileName of stack item 1 of tRef,pRemoveList + revRecursiveRemoveStackFiles the effective fileName of stack item 1 of tRef,pRemoveList,xStackFileList end if end if end if @@ -392,7 +387,7 @@ on revRecursiveRemoveStackFiles pStack,pRemoveList, @xStackFileList put tRef&cr after tNewStackFiles if the effective fileName of stack item 1 of tRef is not among the lines of xStackFileList then put the effective fileName of stack item 1 of tRef & cr after xStackFileList - revRecursiveRemoveStackFiles the effective fileName of stack item 1 of tRef,pRemoveList + revRecursiveRemoveStackFiles the effective fileName of stack item 1 of tRef,pRemoveList,xStackFileList end if end if end if diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsgeneralbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsgeneralbehavior.livecodescript index 812b99ff22..baedbed408 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsgeneralbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsgeneralbehavior.livecodescript @@ -44,7 +44,7 @@ on preOpenCard set the text of field "Default Build Folder" of me to tStandaloneSettingsA["defaultBuildFolder"] set the hilite of button "Automatically Build here" of me to (tStandaloneSettingsA["automaticallyBuildInDefaultFolder"] is true) - set the enabled of group "profiles" to not tStandaloneSettingsA["ios"] + enable group "profiles" local tTipLastShown, tShowTip diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsinclusionsrowbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsinclusionsrowbehavior.livecodescript new file mode 100644 index 0000000000..647b993ba3 --- /dev/null +++ b/Toolset/palettes/standalone settings/revstandalonesettingsinclusionsrowbehavior.livecodescript @@ -0,0 +1,138 @@ +script "revStandaloneSettingsInclusionsRowBehavior" +constant kPlatforms = "emscripten,android,ios,linux,windows,macosx" +on FillInData pDataA, pRow + # Map pDataA values to physical controls... + local tVersion + + set the cTypeID of me to pDataA["id"] + + local tLabel, tAuthor + if pDataA["title"] is not empty then put pDataA["title"] into tLabel + else if pDataA["label"] is not empty then put pDataA["label"] into tLabel + if tLabel is empty then put "Extension Title" into tLabel + + set the cLabel of me to tLabel + + if pDataA["author"] is not empty then put pDataA["author"] into tAuthor + if tAuthor is empty then put "Unknown Author" into tAuthor + + put tLabel into field "description" of me + + local tIconName, tIconPath + revIDEExtensionIconFromType pDataA["type"], pDataA["id"], tIconName, tIconPath + + if tIconPath is not empty then + set the iconPath of widget "icon" of me to tIconPath + else + set the iconPresetName of widget "icon" of me to tIconName + end if + + repeat for each item tItem in kPlatforms + if tItem is among the items of pDataA["platforms"] then + show image tItem of me + else + hide image tItem of me + end if + end repeat + + if revIDEExtensionStandaloneSettingsInfo(pDataA["id"]) \ + is not empty then + show widget "Settings" of me + else + hide widget "Settings" of me + end if + + set the cRow of me to pRow +end FillInData + +on LayoutControl pControlRect + + local tMargin, tPadding, tIconLoc + + # Resize controls/row + put 6 into tMargin + put 6 into tPadding + + set the rect of graphic "background" of me to pControlRect + set the width of graphic "border" of me to (item 3 of pControlRect - item 1 of pControlRect) + set the bottomLeft of graphic "border" of me to item 1 of pControlRect, item 4 of pControlRect + put the loc of me into tIconLoc + put item 1 of pControlRect + (17 + tMargin) into item 1 of tIconLoc + set the loc of widget "icon" of me to tIconLoc + + --set the width of field "description" of me to (item 3 of pControlRect - item 1 of pControlRect) - the width of image "icon" of me - the width of button "uninstall" of me + set the width of field "description" of me to the formattedWidth of field "description" of me + set the height of field "description" of me to the formattedHeight of field "description" of me + set the loc of field "description" of me to the loc of me + set the left of field "description" of me to the right of widget "icon" of me + tPadding + + set the textColor of line 1 of field "description" of me to revIDEColor("text_1") + set the textColor of line 2 of field "description" of me to revIDEColor("text_2") + + local tRight + put the right of me into tRight + subtract tMargin from tRight + set the loc of button "Check" of me to the loc of me + set the right of button "Check" of me to tRight + put the left of button "Check" of me into tRight + subtract tPadding from tRight + + repeat for each item tItem in kPlatforms + subtract tPadding from tRight + set the loc of image tItem of me to the loc of me + set the right of image tItem of me to tRight + put the left of image tItem of me into tRight + end repeat + + subtract 2*tPadding from tRight + set the right of widget "Settings" of me to tRight +end LayoutControl + +on mouseUp + if the long id of the target is \ + the long id of widget "Settings" of me then + popupExtensionStandaloneSettings the cTypeId of me, the mouseLoc + else + dispatch "rowClicked" to card "inclusions" of this stack with the cRow of me + end if +end mouseUp + +command popupExtensionStandaloneSettings pId, pClickLoc + -- TODO: Fetch existing value! + set the behavior of the long id of widget "Settings" of me \ + to the long id of stack revIDEPaletteResourcePath("behaviors/revinspectoreditorbehavior.livecodescript", the long ID of stack "revInspector") + set the rowLabel of me to the cLabel of me && "Standalone Settings" + local tPropertyInfo, tPropData, tStack + dispatch function "getTargetStack" to me + put the result into tStack + put "Extension Standalone Settings" into tPropertyInfo["property_name"] + put revIDEStandaloneSettingsInfoOfExtension(pId) \ + into tPropertyInfo["popup"] + set the editorPropertyInfo of widget "Settings" of me to tPropertyInfo + set the editorPopupData of widget "Settings" of me to \ + revIDEStandaloneSettingsOfExtension(tStack, pId) + send "editorPopup pClickLoc" to widget "Settings" of me +end popupExtensionStandaloneSettings + +on valueChanged pProp, pValue + -- extension standalone settings don't get set directly + -- they live in cRevStandaloneSettings[<ext id>][key] + -- and get merged at build time + local tSettings + dispatch function "getSettings" to me + put the result into tSettings + put pValue into tSettings[the cTypeId of me][pProp] + dispatch "setSettings" to me with tSettings +end valueChanged + +on mouseDown + +end mouseDown + +getProp dvRowControl + return the long id of me +end dvRowControl + +setProp dvHilite[pHiliteColor] pBoolean + set the hilite of button "check" of me to pBoolean +end dvHilite diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsiosbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsiosbehavior.livecodescript index 85a88b2422..a34b90c643 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsiosbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsiosbehavior.livecodescript @@ -28,6 +28,8 @@ on initialize set the enabled of group "iOS Settings" to false end if + relayer button "iOSTabMenu" after group "cards" + updateIosSettingState local tTipLastShown, tShowTip @@ -35,7 +37,7 @@ on initialize put the cIDE_SAIOSTipShow of stack "revPreferences" into tShowTip put the cIDE_SAIOSTipLastShown of stack "revPreferences" into tTipLastShown - if revLicenseType() is "commercial" or revLicenseType() is "professional" then + if revLicenseType() is not "community" then put false into tShowTip set the cIDE_SAGeneralTipShow of stack "revPreferences" to false end if @@ -62,9 +64,29 @@ on updateSettings local tSettings put getSettings() into tSettings + local tScreen + put computeDefault(tSettings["ios,active menu"], "Basic Settings") into tScreen + repeat for each line tLine in the text of button "iOSTabMenu" + if tLine is tScreen then + if tScreen is "Requirements" then + put "Requirement" into tScreen + end if + show group tScreen + set the menuHistory of button "iOSTabMenu" to lineOffset(tScreen, the text of button "iOSTabMenu") + else + local tToHide + put tLine into tToHide + if tToHide is "Requirements" then + put "Requirement" into tToHide + end if + hide group tToHide + end if + end repeat + put computeDefault(tSettings["ios,display name"], tSettings["name"]) into field "Display Name" put computeDefault(tSettings["ios,bundle id"], "com.yourcompany.yourapp") into field "Bundle Id" put computeDefault(tSettings["ios,bundle version"], "1.0.0") into field "Bundle Version" + put computeDefault(tSettings["ios,bundle build"],"1") into field "Build Number" -- SN-2015-03-30: [[ Bug 14794 ]] Initialise the value for 32-bit only build if tSettings["ios,32-bit only"] then @@ -79,6 +101,12 @@ on updateSettings set the hilite of button "beta_version" to false end if + if tSettings["ios,supports dark mode"] is not empty and tSettings["ios,supports dark mode"] then + set the hilite of button "supports dark mode" to true + else + set the hilite of button "supports dark mode" to false + end if + -- MM-2011-09-28: Attempt to port previous icon and splash settings and then remove. -- if tSettings["ios,icon"] is not empty then @@ -107,57 +135,37 @@ on updateSettings storeSetting "icon", empty end if - if tSettings["ios,splash"] is not empty then - local tSplash - put stripSuffix(tSettings["ios,splash"], ".png,-@2x.png,-Landscape.png,-Portrait") into tSplash - if not (tSplash begins with slash) then - put utilityTargetStackPath() & slash before tSplash - end if - - get tSplash & ".png" - if there is a file it and getImageDimensions(it) is "320,480" then - put it into tSettings["ios,iphone splash"] - storeSetting("iphone splash", utilityMakePathRelative(it, utilityTargetStackPath())) - end if - get tSplash & "@2x.png" - if there is a file it and getImageDimensions(it) is "640,960" then - put it into tSettings["ios,retina splash"] - storeSetting("retina splash", utilityMakePathRelative(it, utilityTargetStackPath())) - end if - get tSplash & "-Portrait.png" - if there is a file it and getImageDimensions(it) is "768,1024" then - put it into tSettings["ios,ipad landscape splash"] - storeSetting("ipad landscape splash", utilityMakePathRelative(it, utilityTargetStackPath())) - end if - get tSplash & "-Landscape.png" - if there is a file it and getImageDimensions(it) is "1024,768" then - put it into tSettings["ios,ipad portrait splash"] - storeSetting("ipad portrait splash", utilityMakePathRelative(it, utilityTargetStackPath())) - end if - - storeSetting "splash", empty - end if - -- MM-2011-09-28: Sepearate out the icons and splash screens so the user can specify the values per device. -- + put computeDefault(tSettings["ios,AppStore icon"], empty) into field "AppStore Icon" put computeDefault(tSettings["ios,iphone icon"], empty) into field "iPhone Icon" put computeDefault(tSettings["ios,retina icon"], empty) into field "Retina Icon" put computeDefault(tSettings["ios,iOS 7 retina icon"], empty) into field "iOS 7 Retina Icon" put computeDefault(tSettings["ios,iPhone 6 Plus icon"], empty) into field "iPhone 6 Plus Icon" + put computeDefault(tSettings["ios,iPhone X icon"], empty) into field "iPhone X Icon" put computeDefault(tSettings["ios,ipad icon"], empty) into field "iPad Icon" put computeDefault(tSettings["ios,ipad retina icon"], empty) into field "iPad Retina Icon" put computeDefault(tSettings["ios,iOS 7 ipad icon"], empty) into field "iOS 7 iPad Icon" put computeDefault(tSettings["ios,iOS 7 ipad retina icon"], empty) into field "iOS 7 iPad Retina Icon" - put computeDefault(tSettings["ios,iphone splash"], empty) into field "iPhone Splash" - put computeDefault(tSettings["ios,retina splash"], empty) into field "Retina Splash" - put computeDefault(tSettings["ios,iphone 4inch splash"], empty) into field "iPhone 4Inch Splash" - put computeDefault(tSettings["ios,iPhone 6 splash"], empty) into field "iPhone 6 Splash" - put computeDefault(tSettings["ios,iPhone 6 Plus Portrait splash"], empty) into field "iPhone 6 Plus Portrait Splash" - put computeDefault(tSettings["ios,iPhone 6 Plus Landscape splash"], empty) into field "iPhone 6 Plus Landscape Splash" - put computeDefault(tSettings["ios,ipad portrait splash"], empty) into field "iPad Portrait Splash" - put computeDefault(tSettings["ios,ipad landscape splash"], empty) into field "iPad Landscape Splash" - put computeDefault(tSettings["ios,ipad retina portrait splash"], empty) into field "iPad Retina Portrait Splash" - put computeDefault(tSettings["ios,ipad retina landscape splash"], empty) into field "iPad Retina Landscape Splash" + put computeDefault(tSettings["ios,iPad Pro 12.9 icon"], empty) into field "iPad Pro 12.9 Icon" + put computeDefault(tSettings["ios,iPad Pro 11 icon"], empty) into field "iPad Pro 11 Icon" + + put computeDefault(tSettings["ios,launch-image-light-1x"], empty) into field "launch-image-light-1x" + put computeDefault(tSettings["ios,launch-image-light-2x"], empty) into field "launch-image-light-2x" + put computeDefault(tSettings["ios,launch-image-light-3x"], empty) into field "launch-image-light-3x" + put computeDefault(tSettings["ios,launch-image-dark-1x"], empty) into field "launch-image-dark-1x" + put computeDefault(tSettings["ios,launch-image-dark-2x"], empty) into field "launch-image-dark-2x" + put computeDefault(tSettings["ios,launch-image-dark-3x"], empty) into field "launch-image-dark-3x" + + local tAppTrackingTransparency + put computeDefault(tSettings["ios,AppTrackingTransparency"], false) into tAppTrackingTransparency + set the hilite of button "App Tracking Transparency Check" to tAppTrackingTransparency + put computeDefault(tSettings["ios,AppTrackingTransparencyMessage"], empty) into field "App Tracking Transparency Message" + set the enabled of field "App Tracking Transparency Message" to tAppTrackingTransparency + + set the opaque of graphic "launch-backcolor" to tSettings["ios,launch-backcolor"] is not empty + set the hilite of button "Use system background color" to tSettings["ios,launch-backcolor"] is empty + set the backColor of graphic "launch-backcolor" to tSettings["ios,launch-backcolor"] local tProfiles, tProfileIndex put empty into tProfileIndex @@ -206,22 +214,29 @@ on updateSettings end if set the label of button "Supported Devices" to it - -- SN-2015-02-04: [[ Bug 14422 ]] We only support iOS 5.1.1 and later - -- MM-2013-09-23: We only support iOS 4.3 and later - -- - if tSettings["ios,minimum version"] is not empty and tSettings["ios,minimum version"] <= "5.1" then + -- We only support iOS 8.0 and later + if tSettings["ios,minimum version"] is not empty and tSettings["ios,minimum version"] < "8.0" then put empty into tSettings["ios,minimum version"] end if - set the label of button "Minimum iOS Version" to computeDefault(tSettings["ios,minimum version"], "5.1.1") && "or later" + set the label of button "Minimum iOS Version" to computeDefault(tSettings["ios,minimum version"], "8.0") && "or later" set the hilite of button "Persistent WiFi" to computeDefault(tSettings["ios,persistent wifi"], "false") set the hilite of button "Background Audio" to computeDefault(tSettings["ios,background audio"], "false") - set the hilite of button "Exits on Suspend" to computeDefault(tSettings["ios,exits on suspend"], "true") + set the hilite of button "Location Update" to computeDefault(tSettings["ios,background location update"], "false") + set the hilite of button "VoIP" to computeDefault(tSettings["ios,background voip"], "false") + set the hilite of button "Newsstand Downloads" to computeDefault(tSettings["ios,background newsstand downloads"], "false") + set the hilite of button "ExAcComn" to computeDefault(tSettings["ios,external acc comn"], "false") + set the hilite of button "UseBTLE" to computeDefault(tSettings["ios,use bt le"], "false") + set the hilite of button "Acts as BT LE Acc" to computeDefault(tSettings["ios,acts as bt le"], "false") + set the hilite of button "Background Fetch" to computeDefault(tSettings["ios,background fetch"], "false") + set the hilite of button "Remote Notifications" to computeDefault(tSettings["ios,remote notifications"], "false") set the hilite of button "File Sharing" to computeDefault(tSettings["ios,file sharing"], "false") set the hilite of button "Prerendered Icon" to computeDefault(tSettings["ios,prerendered icon"], "false") set the hilite of button "Disable ATS" to computeDefault(tSettings["ios,disable ATS"], "false") set the label of button "Build Type" to computeDefault(tSettings["ios,build type"], "Universal") + put computeDefault(tSettings["ios,urlwhitelist"],"") into fld "urlwhitelist" + repeat with i = 1 to 18 get tSettings["ios,device capabilities"][the short name of group i of group "Device Capabilities"] if it is "true" then @@ -304,21 +319,6 @@ command updateOrientationSettings set the hilite of button i of group "iPad Initial Orientations" to \ it is among the items of tSupportedOrientations end repeat - - -- Set the enabled of the iPad splash screens selectors based on the orientations set. - -- Possibly turn this off, might be quite annoying. - -- - if the enabled of group "iPad Initial Orientations" then - set the enabled of group "iPad Portrait Splash" to (tSupportedOrientations contains "portrait") - set the enabled of group "iPad Landscape Splash" to (tSupportedOrientations contains "landscape") - set the enabled of group "iPad Retina Portrait Splash" to (tSupportedOrientations contains "portrait") - set the enabled of group "iPad Retina Landscape Splash" to (tSupportedOrientations contains "landscape") - end if - - if the enabled of button "iPhone Intial Orientation" then - set the enabled of group "iPhone 6 Plus Portrait Splash" to tInitialOrientation contains "portrait" - set the enabled of group "iPhone 6 Plus Landscape Splash" to tInitialOrientation contains "landscape" - end if end updateOrientationSettings -- MM-2011-09-28: Enable/disable setting device specif settings based on the currently selected device list. @@ -331,21 +331,13 @@ command enableDeviceSpecificSettings pDevices set the enabled of group "Retina Icon" to (1 is among the items of pDevices) set the enabled of group "iOS 7 Retina Icon" to (1 is among the items of pDevices) set the enabled of group "iPhone 6 Plus Icon" to (1 is among the items of pDevices) + set the enabled of group "iPhone X Icon" to (1 is among the items of pDevices) set the enabled of group "iPad Icon" to (2 is among the items of pDevices) set the enabled of group "iPad Retina Icon" to (2 is among the items of pDevices) set the enabled of group "iOS 7 iPad Icon" to (2 is among the items of pDevices) set the enabled of group "iOS 7 iPad Retina Icon" to (2 is among the items of pDevices) - set the enabled of group "iOS 7 iPad Retina Icon" to (2 is among the items of pDevices) - set the enabled of group "iPhone Splash" to (1 is among the items of pDevices) - set the enabled of group "Retina Splash" to (1 is among the items of pDevices) - set the enabled of group "iPhone 4Inch Splash" to (1 is among the items of pDevices) - set the enabled of group "iPhone 6 Splash" to (1 is among the items of pDevices) - set the enabled of group "iPhone 6 Plus Portrait Splash" to (1 is among the items of pDevices) - set the enabled of group "iPhone 6 Plus Landscape Splash" to (1 is among the items of pDevices) - set the enabled of group "iPad Portrait Splash" to (2 is among the items of pDevices) - set the enabled of group "iPad Landscape Splash" to (2 is among the items of pDevices) - set the enabled of group "iPad Retina Portrait Splash" to (2 is among the items of pDevices) - set the enabled of group "iPad Retina Landscape Splash" to (2 is among the items of pDevices) + set the enabled of group "iPad Pro 12.9 Icon" to (2 is among the items of pDevices) + set the enabled of group "iPad Pro 11 Icon" to (2 is among the items of pDevices) set the enabled of button "iPhone Intial Orientation" to (1 is among the items of pDevices) set the enabled of group "iPad Initial Orientations" to (2 is among the items of pDevices) @@ -354,9 +346,83 @@ command enableDeviceSpecificSettings pDevices end enableDeviceSpecificSettings on storeSetting pName, pValue + checkSettingsCompatible pName, pValue setSetting "ios," & pName, pValue end storeSetting +on checkSettingsCompatible pName, pValue + if pName is "minimum version" and pValue > 10.3 then + if getSetting("ios,32-bit only") is true then + answer error "32-bit only apps are not supported on iOS 11.0 and above" + end if + end if + + if pName is "32-bit only" and pValue is true then + if getSetting("ios,minimum version") > 10.3 then + answer error "32-bit only apps are not supported on iOS 11.0 and above" + end if + end if + + if pName is "profile" then + local tAppID + put getSetting("ios,bundle id") into tAppID + + local tProfile + repeat for each element tProfile in sProfiles + if tProfile["id"] is pValue then + set the itemDelimiter to "." + delete item 1 of tProfile["appid"] + + local tID + if tAppID is empty then + if tProfile["appid"] is "*" then + -- do nothing as we are already default + exit repeat + end if + else + filter tAppID with tProfile["appid"] into tID + if tID is not empty then + -- already matches so do nothing + exit repeat + end if + end if + + if tProfile["appid"] contains "*" then + repeat with tIndex = 1 to max(3, the number of items of tProfile["appid"]) + get item tIndex of tProfile["appid"] + if it is empty or it is "*" then + if tIndex > 3 then + -- if we have a long wildcard just keep apending `id` for * + put "id" into item tIndex of tID + else + put item tIndex of "com.yourcompany.yourapp" into item tIndex of tID + end if + else + put it into item tIndex of tID + end if + end repeat + else + put tProfile["appid"] into tID + end if + + local tVars + put tProfile["appid"] into tVars[1] + put tID into tVars[2] + + answer error revIDELocalise("The chosen provisioning profile requires an app ID matching %1" & return & return & \ + "Would you like to change to %2", tVars) with revIDELocalise("OK") or revIDELocalise("Cancel") + + if it is "OK" then + setSetting "ios,bundle id", tID + put tID into field "Bundle Id" + end if + + exit repeat + end if + end repeat + end if +end checkSettingsCompatible + function fetchSetting pName return getSetting("ios," & pName) end fetchSetting @@ -371,12 +437,19 @@ function getProfiles end getProfiles on updateIosSettingState - set the enabled of group "iOS Settings" of me to (the hilite of button "Build for iOS" of me) - set the visible of button "iOSChecked" to (the hilite of button "Build for iOS" of me) - set the opaque of button "iOSChecked" to false -- SN-2015-03-30: [[ Bug 14794 ]] Add a checkbox for disable the 64-bit slice -- which is only valid for 5.1.1 built (for iPad 1). set the enabled of button "32bit_only" to (the hilite of button "Build for iOS") + set the enabled of group "iOS Settings" of me to (the hilite of button "Build for iOS" of me) + set the visible of button "iOSChecked" to (the hilite of button "Build for iOS" of me) + set the enabled of button "iOSTabMenu" to (the hilite of button "Build for iOS") + set the enabled of group "Basic Settings" to (the hilite of button "Build for iOS") + set the enabled of group "Requirement" to (the hilite of button "Build for iOS") + set the enabled of group "Background Modes" to (the hilite of button "Build for iOS") + set the enabled of group "Icons" to (the hilite of button "Build for iOS") + set the enabled of group "Splash" to (the hilite of button "Build for iOS") + set the enabled of button "Supported Devices" to (the hilite of button "Build for iOS") + set the enabled of button "Minimum iOS Version" to (the hilite of button "Build for iOS") end updateIosSettingState on chooseImageFile pType @@ -411,13 +484,29 @@ end chooseImageFileWithDimension on tipDisplayUpdate if the visible of group "iOSCommercialTip" then - set the topLeft of group "iosBuild" to 12,136 - set the topLeft of group "iOS Settings" to -1,136 - set the cSize of this card to 1024,726 + set the topLeft of group "buildbutton" to 50,127 + set the topLeft of group "iOS Settings" to 5,127 + repeat for each line tLine in the text of button "iOSTabMenu" + local tName + put tLine into tName + if tName is "Requirements" then + put "Requirement" into tName + end if + set the topLeft of group tName to 12,178 + end repeat + set the cSize of this card to 754,670 else - set the topLeft of group "iOS Settings" to -1,67 - set the topLeft of group "iosBuild" to 12,68 - set the cSize of this card to 1024,676 + set the topLeft of group "buildbutton" to 50,60 + set the topLeft of group "iOS Settings" to 5,57 + repeat for each line tLine in the text of button "iOSTabMenu" + local tName2 + put tLine into tName2 + if tName2 is "Requirements" then + put "Requirement" into tName2 + end if + set the topLeft of group tName2 to 12,108 + end repeat + set the cSize of this card to 754,600 end if updateCardSize end tipDisplayUpdate @@ -442,7 +531,7 @@ function getIosProvisioningProfiles local tProfiles repeat for each line tProfile in tProfileFiles - local tContents, tAppId, tIsDist, tName, tId + local tContents, tPrefix, tIsDist, tName, tId, tExpirationDate put url ("file:" & tProfile) into tContents set the itemDelimiter to "." @@ -462,7 +551,7 @@ function getIosProvisioningProfiles end if get word 1 to -1 of line it + 2 of tContents get char 9 to -10 of it - put it into tAppId + put it into tPrefix get lineOffset("<key>Name</key>", tContents) if it is 0 then @@ -471,10 +560,33 @@ function getIosProvisioningProfiles get word 1 to -1 of line it + 1 of tContents put char 9 to -10 of it into tName + get lineOffset("<key>ExpirationDate</key>", tContents) + if it is 0 then + next repeat + end if + get word 1 to -1 of line it + 1 of tContents + // "it" is of the form e.g <date>2013-12-31T00:20:45Z</date> + put char 7 to 16 of it into tExpirationDate + local tDaysLeft + put getProfileDaysRemaining(tExpirationDate) into tDaysLeft + if tDaysLeft is 0 then + next repeat + end if + + local tAppID + get lineOffset("<key>application-identifier</key>", tContents) + if it is 0 then + next repeat + end if + get word 1 to -1 of line it + 1 of tContents + put char 9 to -10 of it into tAppID + put tId into tProfiles[tId]["id"] put tName into tProfiles[tId]["name"] - put tAppId into tProfiles[tId]["appid"] + put tPrefix into tProfiles[tId]["prefix"] + put tAppID into tProfiles[tId]["appid"] put tIsDist into tProfiles[tId]["store"] + put tDaysLeft into tProfiles[tId]["days remaining"] end repeat local tIndex @@ -489,3 +601,30 @@ function getIosProvisioningProfiles return tProfiles end getIosProvisioningProfiles + +// Calculates if the Provisioning Profile is valid +// pExpirationDate is fetched from the .mobileprovision file, in YYYY-MM-DD format +function getProfileDaysRemaining pExpirationDate + local tToday, tExpires + put the date into tToday + convert tToday to seconds + + put pExpirationDate into tExpires + // tExpires is of YYYY-MM-DD format + // Convert this to english format ( MM/DD/YY) + set the itemdel to "-" + put item 2 of tExpires & slash & item 3 of tExpires & slash & char 3 to 4 of item 1 of tExpires into tExpires + convert tExpires from english date to seconds + + if tToday > tExpires then + -- "Expired" + return 0 + else + -- "Valid" + local tSecondsLeft, tDaysLeft + put tExpires - tToday into tSecondsLeft + set numberFormat to "#." + put round (tSecondsLeft/86400) into tDaysLeft + return tDaysLeft + end if +end getProfileDaysRemaining diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsmacbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsmacbehavior.livecodescript index 976ee0b650..fff7a00538 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsmacbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsmacbehavior.livecodescript @@ -7,12 +7,17 @@ on preOpenCard -- and replace with Intel. if tStandaloneSettingsA["MacOSX"] then delete variable tStandaloneSettingsA["MacOSX"] - put true into tStandaloneSettingsA["MacOSX x86-32"] + put true into tStandaloneSettingsA["MacOSX x86-64"] end if if tStandaloneSettingsA["MacOSX PowerPC-32"] then delete variable tStandaloneSettingsA["MacOSX PowerPC-32"] - put true into tStandaloneSettingsA["MacOSX x86-32"] + put true into tStandaloneSettingsA["MacOSX x86-64"] + end if + + if tStandaloneSettingsA["MacOSX x86-32"] then + delete variable tStandaloneSettingsA["MacOSX x86-32"] + put true into tStandaloneSettingsA["MacOSX x86-64"] end if setSettings tStandaloneSettingsA diff --git a/Toolset/palettes/standalone settings/revstandalonesettingsstacksbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingsstacksbehavior.livecodescript index 7e3ff13cff..8752664ec9 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingsstacksbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingsstacksbehavior.livecodescript @@ -8,7 +8,7 @@ on preOpenCard set the enabled of group "Advanced Options" to tEnabled -- Disable the stack encryption options in Community edition - put (tEnabled and revLicenseType() is not "community") into tEnabled + put (tEnabled and revEnvironmentEditionProperty("password_protection")) into tEnabled set the enabled of button "encrypt" to tEnabled set the enabled of field "encrypt" to tEnabled diff --git a/Toolset/palettes/standalone settings/revstandalonesettingswindowsbehavior.livecodescript b/Toolset/palettes/standalone settings/revstandalonesettingswindowsbehavior.livecodescript index 640bfbfbab..4adddb8d60 100644 --- a/Toolset/palettes/standalone settings/revstandalonesettingswindowsbehavior.livecodescript +++ b/Toolset/palettes/standalone settings/revstandalonesettingswindowsbehavior.livecodescript @@ -2,8 +2,15 @@ on preOpenCard local tStandaloneSettingsA put getSettings() into tStandaloneSettingsA - set the hilite of btn "Windows" of group "platforms" to tStandaloneSettingsA["Windows"] = true - set the enabled of group "Windows" to tStandaloneSettingsA["Windows"] = true + set the itemdelimiter to "," + local tEnabled + put false into tEnabled + repeat for each item tItem in "Windows,Windows x86-64" + put tStandaloneSettingsA[tItem] = true or tEnabled into tEnabled + set the hilite of btn tItem of group "platforms" to tStandaloneSettingsA[tItem] = true + end repeat + + set the enabled of group "Windows" to tEnabled put tStandaloneSettingsA["Windows,iconFile"] into fld "iconFile" put tStandaloneSettingsA["Windows,documenticonFile"] into fld "documenticonFile" put tStandaloneSettingsA["Windows,fileDescription"] into fld "fileDescription" diff --git a/Toolset/palettes/start center/revStartCenter.livecode b/Toolset/palettes/start center/revStartCenter.livecode index 3d478ec633..b726292a6e 100755 Binary files a/Toolset/palettes/start center/revStartCenter.livecode and b/Toolset/palettes/start center/revStartCenter.livecode differ diff --git a/Toolset/palettes/start center/revStartCenterBehavior.livecodescript b/Toolset/palettes/start center/revStartCenterBehavior.livecodescript index 2687cb5027..1702785b25 100644 --- a/Toolset/palettes/start center/revStartCenterBehavior.livecodescript +++ b/Toolset/palettes/start center/revStartCenterBehavior.livecodescript @@ -3,7 +3,10 @@ constant kAllSocialMedia = "facebook,twitter,github,linkedin,youtube,stackoverfl constant kSocialMedia = "github,stackoverflow,youtube,facebook,twitter,linkedin" on openStack + revIDESubscribe "ideDesktopChanged" + ## Set up the Start Center UI + initialiseInterface ## Logo logoInitialise @@ -41,14 +44,20 @@ on openStack else set the iconPresetName of widget "startupCheckbox" to "lc-checkbox-unchecked" end if +end openStack + +command initialiseInterface + hide group "Upgrade" of me ## First run if revIDEGetPreference("StartCenterClassic") is true then ## Not first run hide group "firstRun" - show group"topPanel" + show group "topPanel" --show group "tiles" set the top of group "recentFiles" to 0 + + showUpgradeMini else ## First run hide group "banner" @@ -59,12 +68,21 @@ on openStack set the layer of group "firstRun" to top show group "firstRun" + hide group "UpgradeMini" of me + if there is a widget "UpgradeMini" of me then + hide widget "UpgradeMini" of me + end if end if -end openStack +end initialiseInterface + +on firstRunVisible pVisible + revIDESetPreference "StartCenterClassic", not pVisible + initialiseInterface +end firstRunVisible -on desktopChanged +on ideDesktopChanged set the loc of me to revIDEStackScreenLoc(the short name of me) -end desktopChanged +end ideDesktopChanged on ideNewStack startCenterClose @@ -75,7 +93,14 @@ on ideOpenStack pTarget exit ideOpenStack end if - if the short name of ideStackOfObject(pTarget) is not the short name of me then + local tTargetStack + put the short name of ideStackOfObject(pTarget) into tTargetStack + + if the filename of stack (the mainstack of stack tTargetStack) is among the lines of revIDEGetAllPlugins() then + exit ideOpenStack + end if + + if tTargetStack is not the short name of me then startCenterClose end if end ideOpenStack @@ -145,8 +170,8 @@ end socialMediaUnhiliteAll command recentFilesInitialise set the dgProps["hilite color"] of group "recentFiles" to uiColor("edition") - set the linkColor to uiColor("edition") - set the underlineLinks to false + set the linkColor of this stack to uiColor("edition") + set the underlineLinks of this stack to false end recentFilesInitialise command recentFilesSet @@ -163,18 +188,11 @@ command recentFileOpen end recentFileOpen command tilesInitialise - local tArray, tSourceColor, tEdition, tColorStep, tTileNumber + local tArray, tSourceColor, tColorStep, tTileNumber ## Set the colors of the tiles put uiColor("edition") into tSourceColor - put revLicenseType() into tEdition - - ## The Start Color depends on the edition - if tEdition is "commercial" or tEdition is "professional" then - put 0 into tColorStep - else - put -9 into tColorStep - end if + put revEnvironmentEditionProperty("start_center_tile_color_step") into tColorStep repeat with tTileNumber = 1 to 8 add 1 to tColorStep @@ -260,6 +278,48 @@ function tilesArray pState put "lc-person" into tArray[8]["icon"] put "lc-person-filled" into tArray[8]["hoverIcon"] break + case "interactive_welcome" + put "1. User Interface" into tArray[1]["label"] + put "tutorial_list_ui" into tArray[1]["tag"] + put "tablet" into tArray[1]["icon"] + put "tablet" into tArray[1]["hoverIcon"] + put "2. Coding" into tArray[2]["label"] + put "tutorial_list_coding" into tArray[2]["tag"] + put "terminal" into tArray[2]["icon"] + put "terminal" into tArray[2]["hoverIcon"] + break + case "tutorial_list_ui" + put "1. Hello World" into tArray[1]["label"] + put "tutorial_hello_world" into tArray[1]["tag"] + put "lc-hello-world" into tArray[1]["icon"] + put "lc-hello-world-filled" into tArray[1]["hoverIcon"] + put "2. To Do List" into tArray[2]["label"] + put "tutorial_todo_list" into tArray[2]["tag"] + put "lc-todo-list" into tArray[2]["icon"] + put "lc-todo-list-filled" into tArray[2]["hoverIcon"] + put "3. BMI Calculator" into tArray[3]["label"] + put "tutorial_bmi_calculator" into tArray[3]["tag"] + put "lc-bmi-calculator" into tArray[3]["icon"] + put "lc-bmi-calculator-filled" into tArray[3]["hoverIcon"] + put "1. Hello World" into tArray[1]["label"] + put "tutorial_hello_world" into tArray[1]["tag"] + put "lc-hello-world" into tArray[1]["icon"] + put "lc-hello-world-filled" into tArray[1]["hoverIcon"] + put "2. To Do List" into tArray[2]["label"] + put "tutorial_todo_list" into tArray[2]["tag"] + put "lc-todo-list" into tArray[2]["icon"] + put "lc-todo-list-filled" into tArray[2]["hoverIcon"] + break + case "tutorial_list_coding" + put "1. Combining Text" into tArray[1]["label"] + put "tutorial_combining_text" into tArray[1]["tag"] + put "font" into tArray[1]["icon"] + put "font" into tArray[1]["hoverIcon"] + put "2. Timers" into tArray[2]["label"] + put "tutorial_timers" into tArray[2]["tag"] + put "hourglass" into tArray[2]["icon"] + put "hourglass" into tArray[2]["hoverIcon"] + break case "new" put "New Stack" into tArray[1]["label"] put "newStackDefault" into tArray[1]["tag"] @@ -277,7 +337,7 @@ function tilesArray pState put "lc-ipad-portrait-filled" into tArray[3]["hoverIcon"] put "Tablet Landscape" into tArray[4]["label"] - put "newTabletPortrait" into tArray[4]["tag"] + put "newTabletLandscape" into tArray[4]["tag"] put "lc-ipad-landscape" into tArray[4]["icon"] put "lc-ipad-landscape-filled" into tArray[4]["hoverIcon"] @@ -380,11 +440,55 @@ command tilesUpdate pArray send "startCenterSetState 1, pArray" to me in 0 milliseconds end tilesUpdate +on breadcrumbLinkClicked pLink + if pLink is "home" then + setState "home" + else if pLink is "Interactive Welcome" then + setState "interactive_welcome" + end if +end breadcrumbLinkClicked + on startCenterAction pAction local tStackName, tArray switch pAction case "interactive_welcome" - tourStart + --tourStart + put "Home / Interactive Welcome" into field "breadcrumb" + set the textStyle of word 1 of field "breadcrumb" to "link" + put tilesArray(pAction) into tArray + tilesUpdate tArray + hideUpgradeBrowser + break + case "tutorial_list_ui" + put "Home / Interactive Welcome / User Interface" into field "breadcrumb" + set the textStyle of word 1 of field "breadcrumb" to "link" + set the textStyle of word 3 to 4 of field "breadcrumb" to "link" + put tilesArray(pAction) into tArray + tilesUpdate tArray + hideUpgradeBrowser + break + case "tutorial_list_coding" + put "Home / Interactive Welcome / Coding" into field "breadcrumb" + set the textStyle of word 1 of field "breadcrumb" to "link" + set the textStyle of word 3 to 4 of field "breadcrumb" to "link" + put tilesArray(pAction) into tArray + tilesUpdate tArray + hideUpgradeBrowser + break + case "tutorial_hello_world" + tutorialStart "Hello World" + break + case "tutorial_todo_list" + tutorialStart "To Do List" + break + case "tutorial_bmi_calculator" + tutorialStart "BMI Calculator" + break + case "tutorial_combining_text" + tutorialStart "Combining Text" + break + case "tutorial_timers" + tutorialStart "Timers" break case "new" put "Home / New" into field "breadcrumb" @@ -464,44 +568,49 @@ on startCenterAction pAction end switch end startCenterAction -command setStateHome +command setState pState local tArray - put tilesArray("home") into tArray + + put tilesArray(pState) into tArray put empty into field "breadcrumb" - set the textStyle of word 1 of field "breadcrumb" to empty + if pState is "home" then + set the textStyle of word 1 of field "breadcrumb" to empty + showUpgradeMini + else if pState is "interactive_welcome" then + hideUpgradeBrowser + put "Home / Interactive Welcome" into field "breadcrumb" + set the textStyle of word 1 of field "breadcrumb" to "link" + end if tilesUpdate tArray -end setStateHome +end setState -command firstRunVisible pValue +command tourStart lock screen - - if pValue is true then - show group "firstRun" - hide group"topPanel" - --hide group "tiles" - else if pValue is false then - hide group "firstRun" - show group"topPanel" - repeat with x = 1 to 8 - set the hoverState of widget ("tile" & x) to false - end repeat - --show group "tiles" - - revIDESetPreference "StartCenterClassic", "true" - end if - + tutorialStart "Hello World", "App Lesson" unlock screen -end firstRunVisible +end tourStart -command tourStart +command tutorialStart pTutorial lock screen - revIDEStartTutorial "First Run", "BMI Calculator", "App Lesson" + set the cTutorialOverride of me to true + revIDEStartTutorial "First Run", pTutorial, "App Lesson" revIDESetPreference "StartCenterClassic", "true" + revIDESubscribe "ideTutorialProgressChanged" startCenterClose unlock screen -end tourStart +end tutorialStart + +on ideTutorialProgressChanged + if revIDETutorialInProgress() is empty then + revIDEUnsubscribe "ideTutorialProgressChanged" + lock screen + revIDEOpenPalette "start center" + startCenterAction "interactive_welcome" + unlock screen + end if +end ideTutorialProgressChanged ## Banner command bannerInitialise @@ -575,12 +684,9 @@ function uiColor pColor return "255,255,255" break case "tileFGHover" - --return "128,128,128" - if tEdition is "commercial" or tEdition is "professional" then - return revIDEColor("edition_color") - else - return tileColor(revIDEColor("edition_color"), -8) - end if + local tColorStep + put revEnvironmentEditionProperty("start_center_tile_color_step") into tColorStep + return tileColor(revIDEColor("edition_color"), tColorStep) break end switch end uiColor @@ -613,7 +719,7 @@ function textProperty pType, pStyle end if break case "stackLabel" - if pStyle is "font" then + if pStyle is "font" then else if pStyle is "size" then @@ -628,3 +734,84 @@ function textProperty pType, pStyle end switch end textProperty + +-- Actions triggered by the browser widgets related to upgrade +on ideAction pAction, pUrl + switch pAction + case "launchAdWithUrl" + launchUpgradeBrowserWithUrl revEnvironmentEditionProperty("upgrade_url") + break + case "closeBrowser" + hide widget "Upgrade" of me + hide group "Upgrade" of me + showBrowser "UpgradeMini", \ + revEnvironmentEditionProperty("upgrade_mini_url") + break + case "launchExternalUrl" + launch url pUrl + break + end switch +end ideAction + +private command showUpgradeMini + if ideCanShowUpgradeOptions() and \ + the cTutorialOverride of me is not true then + showBrowser "UpgradeMini", \ + revEnvironmentEditionProperty("upgrade_mini_url") + else + set the cTutorialOverride of me to false + hide group "UpgradeMini" of me + if there is a widget "UpgradeMini" of me then + hide widget "UpgradeMini" of me + end if + end if +end showUpgradeMini + +command showBrowser pBrowserName, pUrl + local tBrowser + if there is no widget pBrowserName then + create invisible widget pBrowserName as "com.livecode.widget.browser" + end if + put the long id of widget pBrowserName of me into tBrowser + if the url of tBrowser is empty then + -- show the browser's loading placeholder + show group pBrowserName of me + hide tBrowser + if pBrowserName is "UpgradeMini" then + set the rect of tBrowser to "-1,-1,504,320" + else + set the rect of tBrowser to "-1,0,800,572" + end if + set the javascripthandlers of tBrowser to "ideAction" + set the cLoading of tBrowser to true + set the url of tBrowser to pUrl + else + show tBrowser + end if +end showBrowser + +command launchUpgradeBrowserWithUrl pUrl + hideUpgradeBrowser + showBrowser "Upgrade", pUrl +end launchUpgradeBrowserWithUrl + +on browserNavigateComplete + if the cLoading of the target is true then + show the target + set the cLoading of the target to false + end if +end browserNavigateComplete + +on browserLoadFailed + set the cLoading of the target to false + hide group "Upgrade" of me + hide group "UpgradeMini" of me +end browserLoadFailed + +private command hideUpgradeBrowser + -- Don't auto-show the mini upgrade browser when the + -- upgrade browser is launched from elsewhere + hide widget "UpgradeMini" of me + hide group "UpgradeMini" of me + set the cLoading of widget "UpgradeMini" of me to false +end hideUpgradeBrowser diff --git a/Toolset/palettes/tools/revtools.livecodescript b/Toolset/palettes/tools/revtools.livecodescript index 5fda80b7af..e8e89a9f31 100644 --- a/Toolset/palettes/tools/revtools.livecodescript +++ b/Toolset/palettes/tools/revtools.livecodescript @@ -1,14 +1,16 @@ script "revTools" constant BLOCK_SIZE = 20 +constant kToolsColumnCountDefault = 3 on preOpenStack dispatch "setAsBehavior" to revIDEFrameBehavior() with the long id of me set the title of me to "Tools" # Preferences - if revIDEGetPreference("revTools_columns") is not a number then revIDESetPreference "revTools_columns", 2 + if revIDEGetPreference("revTools_columns") is not a number then revIDESetPreference "revTools_columns", kToolsColumnCountDefault addFrameItem "revTools_columns", "header", "preference", "View Columns", "enum","2,3,4", "framePreferenceSelected", the long id of me + addFrameItem "add_widget","header", "action", "Find More Widgets", "plus", "plus","findMoreWidgets", the long id of me # Look at the preference setting and validate the entries against the tool data local tAllViewList, tObjectData @@ -62,10 +64,17 @@ on registerForMessages ### Messages revIDESubscribe "idePreferenceChanged:revTools_columns" revIDESubscribe "idePreferenceChanged:revTools_show" + revIDESubscribe "idePreferenceOfSetChanged" revIDESubscribe "ideToolChanged" revIDESubscribe "ideExtensionsChanged" end registerForMessages +on findMoreWidgets + lock screen + revIDEFindMoreWidgets + unlock screen + end findMoreWidgets + on ideExtensionsChanged lock screen generatePalette @@ -89,6 +98,16 @@ on idePreferenceChanged pPreference end switch end idePreferenceChanged +on idePreferenceOfSetChanged pSet, pPreference + switch pPreference + case "uservisible" + -- Regenerate tools palette after visible of widget changed + generatePalette + resizeStack + break + end switch +end idePreferenceOfSetChanged + constant kPolygonMenu = "Rectangle Tool\nRounded Rectangle Tool\nOval Tool\nRegular Polygon Tool\nPolygon Tool" on ideToolChanged local tTool @@ -119,16 +138,17 @@ on framePreferenceSelected pPreference, pValue revIDESetPreference "revTools_columns", pValue break case "revTools_show" - local tCurrentPreferenceValue, tPreferencePosition + local tCurrentPreferenceValue, tPreferencePosition, tItemOffset put revIDEGetPreference("revTools_show") into tCurrentPreferenceValue - if pValue is among the items of tCurrentPreferenceValue then - repeat with x = the number of items of tCurrentPreferenceValue down to 1 - if item x of tCurrentPreferenceValue is pValue then - delete item x of tCurrentPreferenceValue - end if - end repeat + put itemOffset(pValue, tCurrentPreferenceValue) into tItemOffset + if tItemOffset is not 0 then + delete item tItemOffset of tCurrentPreferenceValue else - put "," & pValue after tCurrentPreferenceValue + if tCurrentPreferenceValue is empty then + put pValue into tCurrentPreferenceValue + else + put comma & pValue after tCurrentPreferenceValue + end if end if revIDESetPreference "revTools_show", tCurrentPreferenceValue break @@ -150,6 +170,7 @@ on generatePalette repeat while there is a group "contents" delete group "contents" end repeat + reset the templateGroup create group "contents" # Clear the error group @@ -273,29 +294,22 @@ on generatePalette set the id of it to revIDENewIconID() end if - local tImageID + local tImageID, tFilename if sViewsData[tView][tControlTypeID]["icon"] is not empty then - set the name of the templateimage to tControlTypeID & ".icon.png" - set the visible of the templateimage to false - set the filename of the templateimage to sViewsData[tView][tControlTypeID]["icon"] - create image in group "images" of group "contents" - set the id of it to revIDENewIconID() - put the long id of image (tControlTypeID & ".icon.png") of group "images" of group "contents" into tImageID - revIDEResizeImageInBounds tImageID, BLOCK_SIZE * 2,BLOCK_SIZE - set the icon of the templatebutton to the ID of tImageID + put sViewsData[tView][tControlTypeID]["icon"] into tFilename else if there is a file (tThemePath & slash & tControlTypeID & ".icon.png") then - # If we can find an icon file in the theme, create it - set the name of the templateimage to tControlTypeID & ".icon.png" - set the visible of the templateimage to false - set the filename of the templateimage to tThemePath & slash & tControlTypeID & ".icon.png" - create image in group "images" of group "contents" - set the id of it to revIDENewIconID() - put the long id of image (tControlTypeID & ".icon.png") of group "images" of group "contents" into tImageID - revIDEResizeImageInBounds tImageID, BLOCK_SIZE * 2,BLOCK_SIZE - set the icon of the templatebutton to the ID of tImageID - else - set the icon of the templatebutton to empty + put tThemePath & slash & tControlTypeID & ".icon.png" into tFilename + else + put revIDEDefaultExtensionIcon("widget") into tFilename end if + set the name of the templateimage to tControlTypeID & ".icon.png" + set the visible of the templateimage to false + set the filename of the templateimage to tFilename + create image in group "images" of group "contents" + set the id of it to revIDENewIconID() + put the long id of image (tControlTypeID & ".icon.png") of group "images" of group "contents" into tImageID + revIDEResizeImageInBounds tImageID, BLOCK_SIZE * 2,BLOCK_SIZE + set the icon of the templatebutton to the ID of tImageID # If the object is a tool, set the key custom properties to make it behave like a tool local tToolType @@ -337,6 +351,7 @@ on generatePalette if sViewsData[tView][tControlTypeID]["svgicon"] is empty then create button tControlTypeID in group tView of group "contents" + set the cType of button tControlTypeID to tView else create widget tControlTypeID as "com.livecode.widget.svgpath" in group tView of group "contents" set the width of widget tControlTypeID to BLOCK_SIZE * 2 @@ -639,6 +654,8 @@ on mouseDown pButton local tTargetStack, tTargetStackIndex, tScreenmouseloc repeat while the mouse is down + // Tickle the event queue to ensure screenmouseloc is always updated + wait for 0 put the screenmouseloc into tScreenmouseloc set the loc of this stack to tScreenmouseloc @@ -681,7 +698,7 @@ on mouseDown pButton unlock messages - # Check if mouse up occured over a valid drop stack + # Check if mouse up occurred over a valid drop stack local tLeft, tTop, tCreateObjectID repeat with x = 1 to the number of elements in tValidDropStacks if tDropScreenLocation is within tValidDropStacks[x]["rect"] then @@ -1235,3 +1252,8 @@ on revToolsConfigurePolygon pTool end if revToolsConfigurePaint end revToolsConfigurePolygon + +on moveStack + ideSetWindowBoundingRect + pass moveStack +end moveStack diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/BMI Calculator/lessons/App Lesson.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/BMI Calculator/lessons/App Lesson.txt index 0c3be49556..846544712f 100644 --- a/Toolset/palettes/tutorial/courses/First Run/tutorials/BMI Calculator/lessons/App Lesson.txt +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/BMI Calculator/lessons/App Lesson.txt @@ -90,6 +90,14 @@ action add guide "Stack" with rect "0,0,320,480" to stack "Mainstack" highlight guide "Stack" wait until stack "Mainstack" fits guide "Stack" with tolerance 5 + go to step "Select Stack For Inspector" +end step + +step "Select Stack For Inspector" + Ensure this is the active stack, by clicking on it. +action + highlight stack "Mainstack" + wait until stack "Mainstack" is selected go to step "Set Stack Properties" end step @@ -154,6 +162,16 @@ action highlight tool "Create com.livecode.widget.headerBar" capture the next new widget of stack "Mainstack" as "Header" wait until there is a widget "Header" + go to step "Select Header 1" +end step + +step "Select Header 1" + Select the header bar widget by clicking on it. + + The selection handles will show around the widget. +action + highlight widget "Header" + wait until widget "Header" is selected go to step "Set Header Rect" end step @@ -163,6 +181,16 @@ action add guide "Header" with rect "1,1,319,64" to stack "Mainstack" highlight guide "Header" wait until widget "Header" fits guide "Header" with tolerance 5 + go to step "Select Header For Inspector" +end step + +step "Select Header For Inspector" + Select the header bar widget by clicking on it. + + The selection handles will show around the widget. +action + highlight widget "Header" + wait until widget "Header" is selected go to step "Open Property Inspector" end step @@ -237,6 +265,16 @@ action highlight tool "Create com.livecode.widget.navbar" capture the next new widget of stack "Mainstack" as "Footer" wait until there is a widget "Footer" + go to step "Select Footer 1" +end step + +step "Select Footer 1" + Select the navigation bar widget by clicking on it. + + The selection handles will show around the widget. +action + highlight widget "Footer" + wait until widget "Footer" is selected go to step "Set Footer Rect" end step @@ -247,6 +285,16 @@ action add guide "Footer" with rect "1,430,319,479" to stack "Mainstack" highlight guide "Footer" wait until widget "Footer" fits guide "Footer" with tolerance 5 + go to step "Select Footer For Inspector" +end step + +step "Select Footer For Inspector" + Select the navigation bar widget by clicking on it. + + The selection handles will show around the widget. +action + highlight widget "Footer" + wait until widget "Footer" is selected go to step "Set Footer Properties" end step @@ -259,10 +307,11 @@ action end step step "Set Footer Label" - Remove all but one of the lines of the navigation bar's 'Navigation - Data' by clicking on the delete icons. + Delete the second, third and fourth lines of the navigation bar's + 'Navigation Data' by clicking on the delete icons. - Then change the label of the remaining one to "Calculator". + Then change the label of the remaining one from "Contacts" to + "Calculator". action highlight property "itemArray" of section "Basic" wait until the itemLabels of widget "Footer" is "Calculator" @@ -298,6 +347,16 @@ action highlight tool "Create Round Rect Graphic" capture the next new graphic of stack "Mainstack" as "Entry Background" wait until there is a graphic "Entry Background" + go to step "Select Entry Background 1" +end step + +step "Select Entry Background 1" + Select the graphic by clicking on it. + + The selection handles will show around the graphic. +action + highlight graphic "Entry Background" + wait until graphic "Entry Background" is selected go to step "Set Entry Background Rect" end step @@ -307,6 +366,16 @@ action add guide "Background" with rect "14,74,308,228" to stack "Mainstack" highlight guide "Background" wait until graphic "Entry Background" fits guide "Background" with tolerance 5 + go to step "Select Entry Background For Inspector" +end step + +step "Select Entry Background For Inspector" + Select the graphic by clicking on it. + + The selection handles will show around the graphic. +action + highlight graphic "Entry Background" + wait until graphic "Entry Background" is selected go to step "Set Entry Background Properties" end step @@ -338,7 +407,7 @@ end step step "Set Entry Background Blend Level" Set the 'Blend Level' of the graphic to "50". The blend level determines how opaque the background of the graphic is, with 0 - begin fully opaque and 100 being fully transparent. + being fully opaque and 100 being fully transparent. action highlight property "blendLevel" of section "Colors" wait until the blendLevel of graphic "Entry Background" is "50" @@ -351,6 +420,14 @@ action highlight tool "Create Label Field" capture the next new field of stack "Mainstack" as "Height Label" wait until there is a field "Height Label" + go to step "Select Height Label 1" +end step + +step "Select Height Label 1" + Select the field by clicking on it. +action + highlight field "Height Label" + wait until field "Height Label" is selected go to step "Set Height Label Rect" end step @@ -360,6 +437,14 @@ action add guide "Label" with rect "28,87,164,117" to stack "Mainstack" highlight guide "Label" wait until field "Height Label" fits guide "Label" with tolerance 3 + go to step "Select Height Label For Inspector" +end step + +step "Select Height Label For Inspector" + Select the field by clicking on it. +action + highlight field "Height Label" + wait until field "Height Label" is selected go to step "Set Height Label Properties" end step @@ -386,6 +471,14 @@ action highlight tool "Create Label Field" capture the next new field of stack "Mainstack" as "Weight Label" wait until there is a field "Weight Label" + go to step "Select Weight Label 1" +end step + +step "Select Weight Label 1" + Select the field by clicking on it. +action + highlight field "Weight Label" + wait until field "Weight Label" is selected go to step "Set Weight Label Rect" end step @@ -395,6 +488,14 @@ action add guide "Label" with rect "28,127,164,157" to stack "Mainstack" highlight guide "Label" wait until field "Weight Label" fits guide "Label" with tolerance 3 + go to step "Select Weight Label For Inspector" +end step + +step "Select Weight Label For Inspector" + Select the field by clicking on it. +action + highlight field "Weight Label" + wait until field "Weight Label" is selected go to step "Set Weight Label Properties" end step @@ -421,6 +522,14 @@ action highlight tool "Create Field" capture the next new field of stack "Mainstack" as "Height Field" wait until there is a field "Height Field" + go to step "Select Height Field 1" +end step + +step "Select Height Field 1" + Select the field by clicking on it. +action + highlight field "Height Field" + wait until field "Height Field" is selected go to step "Set Height Field Rect" end step @@ -443,6 +552,14 @@ step "Name Interlude" name that's descriptive of what it represents. action interlude + go to step "Select Height Field For Inspector" +end step + +step "Select Height Field For Inspector" + Select the field by clicking on it. +action + highlight field "Height Field" + wait until field "Height Field" is selected go to step "Set Height Field Properties" end step @@ -469,6 +586,14 @@ action highlight tool "Create Field" capture the next new field of stack "Mainstack" as "Weight Field" wait until there is a field "Weight Field" + go to step "Select Weight Field 1" +end step + +step "Select Weight Field 1" + Select the field by clicking on it. +action + highlight field "Weight Field" + wait until field "Weight Field" is selected go to step "Set Weight Field Rect" end step @@ -478,6 +603,14 @@ action add guide "Entry Field" with rect "185,127,253,157" to stack "Mainstack" highlight guide "Entry Field" wait until field "Weight Field" fits guide "Entry Field" with tolerance 3 + go to step "Select Weight Field For Inspector" +end step + +step "Select Weight Field For Inspector" + Select the field by clicking on it. +action + highlight field "Weight Field" + wait until field "Weight Field" is selected go to step "Set Weight Field Properties" end step @@ -499,12 +632,20 @@ action end step step "Create Calculate Graphic" - Drag a rounded rectangle graphic from the tools palette onto your + Drag a rounded rectangle graphic from the tools palette onto your stack. action highlight tool "Create Round Rect Graphic" capture the next new graphic of stack "Mainstack" as "Calculate Background" wait until there is a graphic "Calculate Background" + go to step "Select Calculate Graphic 1" +end step + +step "Select Calculate Graphic 1" + Select the graphic by clicking on it. +action + highlight graphic "Calculate Background" + wait until graphic "Calculate Background" is selected go to step "Set Calculate Graphic Rect" end step @@ -514,6 +655,14 @@ action add guide "Calculate Graphic" with rect "23,178,300,216" to stack "Mainstack" highlight guide "Calculate Graphic" wait until graphic "Calculate Background" fits guide "Calculate Graphic" with tolerance 5 + go to step "Select Calculate Graphic For Inspector" +end step + +step "Select Calculate Graphic For Inspector" + Select the graphic by clicking on it. +action + highlight graphic "Calculate Background" + wait until graphic "Calculate Background" is selected go to step "Set Calculate Graphic Properties" end step @@ -539,6 +688,14 @@ action highlight tool "Create Button" capture the next new button of stack "Mainstack" as "Calculate" wait until there is a button "Calculate" + go to step "Select Calculate Button 1" +end step + +step "Select Calculate Button 1" + Select the button by clicking on it. +action + highlight button "Calculate" + wait until button "Calculate" is selected go to step "Set Calculate Button Rect" end step @@ -548,6 +705,14 @@ action add guide "Calculate" with rect "23,178,300,216" to stack "Mainstack" highlight guide "Calculate" wait until button "Calculate" fits guide "Calculate" with tolerance 3 + go to step "Select Calculate Button For Inspector" +end step + +step "Select Calculate Button For Inspector" + Select the button by clicking on it. +action + highlight button "Calculate" + wait until button "Calculate" is selected go to step "Set Calculate Button Properties" end step @@ -591,6 +756,14 @@ action highlight tool "Create Round Rect Graphic" capture the next new graphic of stack "Mainstack" as "Results Background" wait until there is a graphic "Results Background" + go to step "Select Results Background 1" +end step + +step "Select Results Background 1" + Select the graphic by clicking on it. +action + highlight graphic "Results Background" + wait until graphic "Results Background" is selected go to step "Set Results Background Rect" end step @@ -600,6 +773,14 @@ action add guide "Background" with rect "14,240,308,422" to stack "Mainstack" highlight guide "Background" wait until graphic "Results Background" fits guide "Background" with tolerance 5 + go to step "Select Results Background For Inspector" +end step + +step "Select Results Background For Inspector" + Select the graphic by clicking on it. +action + highlight graphic "Results Background" + wait until graphic "Results Background" is selected go to step "Set Results Background Properties" end step @@ -642,6 +823,14 @@ action highlight tool "Create Label Field" capture the next new field of stack "Mainstack" as "Results Label" wait until there is a field "Results Label" + go to step "Select Results Label 1" +end step + +step "Select Results Label 1" + Select the field by clicking on it. +action + highlight field "Results Label" + wait until field "Results Label" is selected go to step "Set Results Label Rect" end step @@ -654,6 +843,14 @@ action go to step "Set Results Label Properties" end step +step "Select Results Label For Inspector" + Select the field by clicking on it. +action + highlight field "Results Label" + wait until field "Results Label" is selected + go to step "Set Results Label Properties" +end step + step "Set Results Label Properties" Open the property inspector for the label field. action @@ -693,6 +890,14 @@ action highlight tool "Create Label Field" capture the next new field of stack "Mainstack" as "Results" wait until there is a field "Results" + go to step "Select Results Field 1" +end step + +step "Select Results Field 1" + Select the field by clicking on it. +action + highlight field "Results" + wait until field "Results" is selected go to step "Set Results Rect" end step @@ -702,6 +907,14 @@ action add guide "Label" with rect "22,287,300,325" to stack "Mainstack" highlight guide "Label" wait until field "Results" fits guide "Label" with tolerance 3 + go to step "Select Results Field For Inspector" +end step + +step "Select Results Field For Inspector" + Select the field by clicking on it. +action + highlight field "Results" + wait until field "Results" is selected go to step "Set Results Properties" end step @@ -745,6 +958,14 @@ action highlight menu item "Duplicate Objects" of menu "Edit" capture the next new field of stack "Mainstack" as "Advice" wait until there is a field "Advice" + go to step "Select Advice Field 1" +end step + +step "Select Advice Field 1" + Select the field. +action + highlight field "Advice" + wait until field "Advice" is selected go to step "Set Advice Rect" end step @@ -754,6 +975,14 @@ action add guide "Label" with rect "22,327,300,417" to stack "Mainstack" highlight guide "Label" wait until field "Advice" fits guide "Label" with tolerance 3 + go to step "Select Advice Field For Inspector" +end step + +step "Select Advice Field For Inspector" + Select the field. +action + highlight field "Advice" + wait until field "Advice" is selected go to step "Set Advice Properties" end step @@ -855,6 +1084,14 @@ action capture the next new group of stack "Mainstack" as "Background Group" capture set widget "Header", widget "Footer" as "Shared Controls" wait until set "Shared Controls" is grouped + go to step "Select Group For Inspector" +end step + +step "Select Group For Inspector" + Select the new group. +action + highlight group "Background Group" + wait until group "Background Group" is selected go to step "Set Group Properties" end step @@ -915,6 +1152,14 @@ action highlight menu item "Graph from CSV File" of menu item "Import As Control" of menu "File" capture the next new widget of stack "Mainstack" as "BMI Chart" wait until there is a widget "BMI Chart" + go to step "Select Chart For Inspector" +end step + +step "Select Chart For Inspector" + Select the new chart widget. +action + highlight widget "BMI Chart" + wait until widget "BMI Chart" is selected go to step "Set Chart Properties" end step @@ -1010,7 +1255,7 @@ action end step step "Set Item Icon" - Click the grey icon on the new row of the Navigation Data, to bring + Click the left hand icon on the new row of the Navigation Data, to bring up the icon picker, and set the icon of the new navigation item to the "bar chart" icon. action @@ -1020,8 +1265,8 @@ action end step step "Set Item Name" - Set the name of the new item by changing the 'Navigation Names' of - the navigation bar from "Calculator,new item" to "Calculator,Chart", + Change the name of the new item in the second field of the + 'Navigation Names' property of the navigation bar to "Chart", and press <Return>. action highlight property "itemNames" of section "Basic" @@ -1036,6 +1281,14 @@ step "Navigation Bar Script Interlude" user to navigate between the Chart and Calculator cards. action interlude + go to step "Select Navigation Bar For Editor" +end step + +step "Select Navigation Bar For Editor" + Select the navigation bar. +action + highlight widget "Footer" + wait until widget "Footer" is selected go to step "Open Navigation Bar Script Editor" end step @@ -1173,6 +1426,14 @@ step "Function Interlude" corresponding BMI. action interlude + go to step "Select Stack For Editor" +end step + +step "Select Stack For Editor" + Ensure this is the active stack, by clicking on it. +action + highlight stack "Mainstack" + wait until stack "Mainstack" is selected go to step "Open Stack Script" end step @@ -1355,7 +1616,7 @@ end step step "Open Calculator Card Script" We are going to store the calculated BMI using a custom property on - out stack, called 'cBMI'. We are also going to store the height and + our stack, called 'cBMI'. We are also going to store the height and weight in custom properties 'cHeight' and 'cWeight'. To do this we will add a custom command to the card script which @@ -1697,7 +1958,7 @@ skip point step "Dictionary Interlude" The dictionary contains information about all the syntax available - in LiveCode. There is also a guides tab which contains all the user + in LiveCode. There is also a Guide tab which contains all the user guides available. action interlude @@ -1968,6 +2229,14 @@ action highlight tool "Create com.livecode.widget.browser" capture the next new widget of stack "Mainstack" as "Browser" wait until there is a widget "Browser" + go to step "Select Browser 1" +end step + +step "Select Browser 1" + Select the browser widget. +action + highlight widget "Browser" + wait until widget "Browser" is selected go to step "Set Browser Rect" end step @@ -1977,6 +2246,14 @@ action add guide "Browser" with rect "0,62,320,432" to stack "Mainstack" highlight guide "Browser" wait until widget "Browser" fits guide "Browser" with tolerance 5 + go to step "Select Browser For Inspector" +end step + +step "Select Browser For Inspector" + Select the browser widget. +action + highlight widget "Browser" + wait until widget "Browser" is selected go to step "Open Browser Inspector" end step diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/_resources/videoChoice.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/_resources/videoChoice.png new file mode 100644 index 0000000000..19228f694b Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/_resources/videoChoice.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson 0.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson 0.txt new file mode 100755 index 0000000000..02e36c095f --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson 0.txt @@ -0,0 +1,377 @@ +tutorial "Combining Text" + +prologue + LiveCode's uniquely powerful text handling capabilities comes in handy for a wide range of applications. Common tasks include: + + - Mail merging a form email + + - Creating a leaflet for print + + - Building an invoice +end prologue + +step "Create Mainstack" + +action + highlight menu item "Default size" of menu item "New Stack" of menu "File" + capture the next new stack as "Mainstack" + capture the next new card of stack "Mainstack" as "home" + wait until there is a stack "Mainstack" + go to step "Set Stack Properties" +end step + +step "Set Stack Properties" + Click on the Inspector icon on the toolbar to open the property + inspector. +action + highlight toolbar "Inspector" + wait until there is an inspector for stack "Mainstack" + go to step "Set Stack Title" +end step + +step "Set Stack Title" + Set the 'Title' of the stack to "Combine Text". +action + highlight property "title" of section "basic" + wait until the title of stack "Mainstack" is "Combine Text" + go to step "Set Stack Rect" +end step + +step "Set Stack Rect" + Resize the stack so that it has width 700 and height 500. +action + add guide "Stack" with rect "0,0,700,500" to stack "Mainstack" + highlight guide "Stack" + wait until stack "Mainstack" fits guide "Stack" with tolerance 5 + go to step "Set Stack Color" +end step + +step "Set Stack Color" + We want the stack to have a white background so set the 'Background fill' of the stack to white (255,255,255). +action + highlight property "backgroundColor" of section "colors" + wait until the backgroundColor of stack "mainstack" is "255,255,255" + go to step "Create template label" +end step + +step "Create template label" + Drag a label field from the tools palette onto your stack. +action + highlight tool "Create Label Field" + capture the next new field of stack "Mainstack" as "TemplateLabel" + wait until there is a field "TemplateLabel" + go to step "Set TemplateLabel Location" +end step + +step "Set TemplateLabel Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "TemplateLabelLoc" with rect "8,7,108,31" to stack "Mainstack" + highlight guide "TemplateLabelLoc" + wait until field "TemplateLabel" fits guide "TemplateLabelLoc" with tolerance 5 + go to step "TemplateLabel Property Inspector" +end step + +step "TemplateLabel Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "TemplateLabel" + wait until there is an inspector for field "TemplateLabel" + go to step "Set TemplateLabel name" +end step + +step "Set TemplateLabel name" + Set the 'Name' of the field to "TemplateLabel". +action + highlight property "name" of section "Basic" + wait until the name of field "TemplateLabel" is "TemplateLabel" + go to step "Set TemplateLabel Text" +end step + +step "Set TemplateLabel Text" + Set the 'Name' of the field to "TemplateLabel". +action + wait until the text of field "TemplateLabel" is "Template" + go to step "Set TemplateLabel Text Size" +end step + +step "Set TemplateLabel text size" + Set the 'Text Size' of the field to 16. +action + highlight property "textSize" of section "Text" + wait until the textSize of field "TemplateLabel" is "16" + go to step "Set TemplateLabel text align" +end step + +step "Set TemplateLabel text align" + Set the 'Text Align' of the field to left. +action + highlight property "textAlign" of section "Text" + wait until the textAlign of field "TemplateLabel" is "left" + go to step "Create template field" +end step + +step "Create template field" + Import the "template" text file onto your stack. +file + template.txt +action + highlight menu item "Text File..." of menu item "Import as Control" of menu "File" + capture the next new field of stack "Mainstack" as "template" + wait until there is a field "template" + go to step "Set template Location" +end step + +step "Set template Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "templateLoc" with rect "10,34,345,232" to stack "Mainstack" + highlight guide "templateLoc" + wait until field "template" fits guide "templateLoc" with tolerance 5 + go to step "Template Property Inspector" +end step + +step "Template Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "template" + wait until there is an inspector for field "template" + go to step "Set template name" +end step + +step "Set template name" + Set the 'Name' of the field to "template". +action + highlight property "name" of section "Basic" + wait until the name of field "template" is "template" + go to step "Create record label field" +end step + +step "Create record label field" + Drag a label field from the tools palette onto your stack. +action + highlight tool "Create Label Field" + capture the next new field of stack "Mainstack" as "RecordLabel" + wait until there is a field "RecordLabel" + go to step "Set RecordLabel Location" +end step + +step "Set RecordLabel Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "RecordLabelLoc" with rect "355,7,455,30" to stack "Mainstack" + highlight guide "RecordLabelLoc" + wait until field "RecordLabel" fits guide "RecordLabelLoc" with tolerance 5 + go to step "RecordLabel Property Inspector" +end step + +step "RecordLabel Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "RecordLabel" + wait until there is an inspector for field "RecordLabel" + go to step "Set RecordLabel name" +end step + +step "Set RecordLabel name" + Set the 'Name' of the field to "RecordLabel". +action + highlight property "name" of section "Basic" + wait until the name of field "RecordLabel" is "RecordLabel" + go to step "Set RecordLabel Text" +end step + +step "Set RecordLabel Text" + Set the 'Name' of the field to "RecordLabel". +action + wait until the text of field "RecordLabel" is "Record" + go to step "Set RecordLabel Text Size" +end step + +step "Set RecordLabel text size" + Set the 'Text Size' of the field to 16. +action + highlight property "textSize" of section "Text" + wait until the textSize of field "RecordLabel" is "16" + go to step "Set RecordLabel text align" +end step + +step "Set RecordLabel text align" + Set the 'Text Align' of the field to left. +action + highlight property "textAlign" of section "Text" + wait until the textAlign of field "RecordLabel" is "left" + go to step "Create record field" +end step + +step "Create record field" + Import the "record" text file onto your stack. +file + record.txt +action + highlight menu item "Text File..." of menu item "Import as Control" of menu "File" + capture the next new field of stack "Mainstack" as "record" + wait until there is a field "record" + go to step "Set record Location" +end step + +step "Set record Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "recordLoc" with rect "355,33,690,232" to stack "Mainstack" + highlight guide "recordLoc" + wait until field "record" fits guide "recordLoc" with tolerance 5 + go to step "Record Property Inspector" +end step + +step "Record Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "record" + wait until there is an inspector for field "record" + go to step "Set record name" +end step + +step "Set record name" + Set the 'Name' of the field to "record". +action + highlight property "name" of section "Basic" + wait until the name of field "record" is "record" + go to step "Create OutputLabel field" +end step + +step "Create OutputLabel field" + Drag a label field from the tools palette onto your stack. +action + highlight tool "Create Label Field" + capture the next new field of stack "Mainstack" as "OutputLabel" + wait until there is a field "OutputLabel" + go to step "Set OutputLabel Location" +end step + +step "Set OutputLabel Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "OutputLabelLoc" with rect "8,265,108,289" to stack "Mainstack" + highlight guide "OutputLabelLoc" + wait until field "OutputLabel" fits guide "OutputLabelLoc" with tolerance 5 + go to step "OutputLabel Property Inspector" +end step + +step "OutputLabel Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "OutputLabel" + wait until there is an inspector for field "OutputLabel" + go to step "Set OutputLabel name" +end step + +step "Set OutputLabel name" + Set the 'Name' of the field to "OutputLabel". +action + highlight property "name" of section "Basic" + wait until the name of field "OutputLabel" is "OutputLabel" + go to step "Set OutputLabel Text" +end step + +step "Set OutputLabel Text" + Set the 'Name' of the field to "OutputLabel". +action + wait until the text of field "OutputLabel" is "Output" + go to step "Set OutputLabel Text Size" +end step + +step "Set OutputLabel text size" + Set the 'Text Size' of the field to 16. +action + highlight property "textSize" of section "Text" + wait until the textSize of field "OutputLabel" is "16" + go to step "Set OutputLabel text align" +end step + +step "Set OutputLabel text align" + Set the 'Text Align' of the field to left. +action + highlight property "textAlign" of section "Text" + wait until the textAlign of field "OutputLabel" is "left" + go to step "Create output field" +end step + +step "Create output field" + Drag a field from the tools palette onto your stack. +action + highlight tool "Create Field" + capture the next new field of stack "Mainstack" as "output" + wait until there is a field "output" + go to step "Set output Location" +end step + +step "Set output Location" + Resize and position the field, as shown by dragging the resize handle. +action + add guide "outputLoc" with rect "10,290,690,490" to stack "Mainstack" + highlight guide "outputLoc" + wait until field "output" fits guide "outputLoc" with tolerance 5 + go to step "Output Property Inspector" +end step + +step "Output Property Inspector" + Select the field and open the Inspector from the Menubar. +action + highlight field "output" + wait until there is an inspector for field "output" + go to step "Set output name" +end step + +step "Set output name" + Set the 'Name' of the field to "output". +action + highlight property "name" of section "Basic" + wait until the name of field "output" is "output" + go to step "Create create button" +end step + +step "Create create button" + Drag a button from the tools palette onto your stack. +action + highlight tool "Create button" + capture the next new button of stack "Mainstack" as "Create" + wait until there is a button "create" + go to step "Set create Location" +end step + +step "Set create Location" + Resize and position the button, as shown by dragging the resize handle. +action + add guide "createLoc" with rect "565,237,691,262" to stack "Mainstack" + highlight guide "createLoc" + wait until button "create" fits guide "createLoc" with tolerance 5 + go to step "Open Button Property Inspector" +end step + +step "Open Button Property Inspector" + Select the button and open the Inspector from the Menubar. +action + highlight button "Create" + wait until there is an inspector for button "Create" + go to step "Set Create Button Name" +end step + +step "Set Create button Name" + Set the 'Name' of the button to "Create email". +action + highlight property "name" of section "Basic" + wait until the name of button "Create" is "Create email" +end step + +epilogue + Congratulations. You have learned how to + + - Work with words and lines + + - Combine texts together + + - Make decisions + + - Insert variables into your output +end epilogue diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson.txt new file mode 100755 index 0000000000..ffb0c3762e --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/lessons/App Lesson.txt @@ -0,0 +1,280 @@ +tutorial "Combining Text" + +prologue + LiveCode's uniquely powerful text handling capabilities comes in handy for a wide range of applications. Common tasks include: + + - Mail merging a form email + + - Creating a leaflet for print + + - Building an invoice +end prologue + +step "Tutorial Intro 1" + In this tutorial, you'll learn how to: + + - Work with words and lines + + - Combine texts together + + - Make decisions + + - Insert variables into your output +action + interlude + go to step "Load stack" +end step + +step "Load stack" + Some text +action + load lesson "App Lesson 0" + go to step "Tutorial Intro 2" +end step + +step "Tutorial Intro 2" + In this tutorial, we will have a template email, which is placed in a field called "template", a record, which is placed in a field called "record", and an output field, which is called "output". We also have a button called "Create email". +action + interlude + go to step "Address by name 1" +end step + +step "Address by name 1" + We want to create a personalized email by combining the email template with the personal details in the "record" field. + + The first step is to start our email with "Dear Mr Miller". To do this we need to add some code to the button. +action + interlude + go to step "Address by name 2" +end step + +step "Address by name 2" + To make changes first ensure you are in 'Edit' mode. +action + highlight tool "Edit Mode" + wait until the tool is edit + go to step "Address by name 2b" +end step + +step "Address by name 2b" + Select the "Create email" button. +action + highlight button "create" + wait until button "create" is selected + go to step "Address by name 3" +end step + +step "Address by name 3" + Open the Script editor for the button by clicking the 'Code' button in the Toolbar. +action + highlight toolbar "Code" + wait until there is a script editor for button "Create" + go to step "Address by name 4" +end step + +step "Address by name 4" + Add this handler to the button script. We will explain this line by line in a moment. + + Don't forget to click the 'Apply' button when you have finished. +script + on mouseUp + put field "template" into field "output" + put field "record" into tRecord + put line 2 of tRecord && word -1 of line 1 of tRecord & comma into tName + put tName after line 1 of field "output" + end mouseUp +action + highlight script editor for button "Create" + wait until button "Create" is scripted + go to step "Address by name 5" +end step + +step "Address by name 5" + The first line of code puts the contents of the "template" field (our email text) into the "output" field. +action + interlude + highlight line "into field" of script editor for button "create" + go to step "Address by name 6" +end step + +step "Address by name 6" + The second line of code puts the contents of the "record" field into a variable we're calling 'tRecord' - this makes it easier to work with. +action + interlude + highlight line "into tRecord" of script editor for button "create" + go to step "Address by name 7" +end step + +step "Address by name 7" + The third line of code combines 3 pieces of text and puts them into another variable, 'tName'. + + - the whole of line 2 of our record (Mr) + + - then the last word of line 1 of our record (Miller) + + - then a comma + + A single ampersand '&' tells LiveCode to combine text together and a double ampersand '&& tells it insert a space when it does so. +action + interlude + highlight line "put line 2 of tRecord" of script editor for button "create" + go to step "Address by name 8" +end step + +step "Address by name 8" + Finally, we put 'tName' into the "output" field, after line 1. +action + interlude + highlight line "put tName after" of script editor for button "create" + go to step "Run mode 1" +end step + +step "Run mode 1" + Take a look at what this does by switching into 'Run' mode on the Tools palette. You will see a personalized email to Mr Miller in the "output" field. + + Select 'Run mode' in the Tools Palette. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Test 1" +end step + +step "Test 1" + Click on the 'Create email' button to see the customized message. +action + highlight button "create" + wait until the text of field "output" is changed with default "Dear Mr Miller" + go to step "Video choice 1" +end step + +step "Video choice 1" + Next we will add some more personal information to the final email. + + We want to decide whether to show section (1) or section (2) of the email. Do we want to say "We noticed you watched X videos so far" or do we want to say "We notice you haven't watched any videos so far"? + + The number of videos watched is the fifth line of the record. +image + videoChoice.png +action + interlude + go to step "Video choice 2" +end step + +step "Video choice 2" + To do this we need to add some more code to the button. + + Select 'Edit' mode in the Tools Palette. +action + highlight tool "Edit Mode" + wait until the tool is edit + go to step "Video choice 2a" +end step + +step "Video choice 2a" + Select the "Create email" button. +action + highlight button "create" + wait until button "create" is selected + go to step "Video choice 3" +end step + +step "Video choice 3" + Open the Script editor for the button by clicking the 'Code' button in the Toolbar. +action + highlight toolbar "Code" + wait until there is a script editor for button "Create" + go to step "Video choice 4" +end step + +step "Video choice 4" + Add this handler to the button script. We will explain this line by line in a moment. + + Don't forget to click the 'Apply' button when you have finished. +script + on mouseUp + put field "template" into field "output" + put field "record" into tRecord + put line 2 of tRecord && word -1 of line 1 of tRecord & comma into tName + put tName after line 1 of field "output" + + if line 5 of tRecord > 0 then + delete line 9 to 12 of field "output" + put line 5 of tRecord into word 5 of line 5 of field "output" + else + delete line 5 to 8 of field "output" + end if + end mouseUp +action + highlight script editor for button "Create" + wait until button "Create" is scripted + go to step "Video choice 5" +end step + +step "Video choice 5" + The first step is to check how many videos have been watched, and use an 'if statement' to execute different blocks of code depending on the number. + + - If at least one video has been watched we will use the first block of text from the template, and put the correct number of videos in the text. + + - If no videos have been watched we will use the second block of text from the template. +action + interlude + highlight line "if line 5 of theRecord" of script editor for button "create" + go to step "Video choice 7" +end step + +step "Video choice 7" + If line 5 of 'tRecord' is greater than zero we know that the customer has watched some videos, so we delete lines 9 to 12 of the email, which say "We notice you haven't watched any videos so far". +action + interlude + highlight line "delete line 9 to 12" of script editor for button "create" + go to step "Video choice 8" +end step + +step "Video choice 8" + Then we put line 5 of 'tRecord', the number of videos watched, into word 5 of line 5 of our email, replacing the placeholder "X" in "We noticed you watched X videos so far". +action + interlude + highlight line "put line 5 of tRecord" of script editor for button "create" + go to step "Video choice 9" +end step + +skip point + +step "Video choice 9" + If line 5 of 'tRecord' is 0 (or less), we delete line 5 to 8 of the output email. +action + interlude + highlight line "delete line 5 to 8" of script editor for button "create" + go to step "Run mode 2" +end step + +step "Run mode 2" + Take a look at what this does by switching into 'Run' mode on the Tools palette. + + Select 'Run mode' in the Tools Palette. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Test 2" +end step + +step "Test 2" + Click on the 'Create email' button to see the updated message. + + You will see that the "output" field now displays the relevant message for the number of watched videos stored in the profile. +action + highlight button "create" + wait until the text of field "output" is changed with default "We notice you've watched 3 videos so far." +end step + +epilogue + Congratulations. You have learned how to + + - Work with words and lines + + - Combine texts together + + - Make decisions + + - Insert variables into your output +end epilogue diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/record.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/record.txt new file mode 100644 index 0000000000..5fe2c91d5e --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/record.txt @@ -0,0 +1,5 @@ +Kevin P. Miller +Mr +kevin@livecode.com +ID3928 +3 \ No newline at end of file diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/template.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/template.txt new file mode 100644 index 0000000000..715e9c2d95 --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Combining Text/resources/template.txt @@ -0,0 +1,19 @@ +Dear + +Thank you for participating in the LiveCode Business Academy. + +We notice you've watched X videos so far. + +We really value your feedback. Please tell us what you think of the course so far by visiting: + +We notice you haven't watched any videos so far. + +Please tell us why you haven't viewed any videos so far by visiting: + +http://www.livecode.com/feedback/academy?a= + +Best regards, + +The LiveCode Team + +This email was sent by LiveCode Ltd. \ No newline at end of file diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Hello World/lessons/App Lesson.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Hello World/lessons/App Lesson.txt new file mode 100755 index 0000000000..9ea6928ed4 --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Hello World/lessons/App Lesson.txt @@ -0,0 +1,284 @@ +tutorial "Hello World" + +prologue + Welcome to LiveCode, to help you get started this Interactive Tutorial will + show you how to create a simple 'Hello World' app. +end prologue + +step "Tutorials Intro" + You can keep track of how much of the tutorial you have completed + with this progress bar, and exit the tutorial at any time by + clicking on the stop button. + + Clicking the fast-forward button will skip to the next important + concept being introduced in the tutorial. Use this if you've got the + idea about something or don't want to have to create every last + part of the user interface, for example. + + The tutorial will also help you out by disabling any options you + don't need for the current step. +action + interlude + highlight toolbar "tutorial" + go to step "Stack Interlude" +end step + +skip point + +step "Stack Interlude" + We start by creating the User Interface (UI) for the Hello World app. + + The first step is to create a new LiveCode app at the default size. + + Click on the File menu, and select 'New Stack' → 'Default Size'. +action + highlight menu item "Default Size" of menu item "New Stack" of menu "File" + capture the next new stack as "Mainstack" + capture the next new card of stack "Mainstack" as "HelloWorld" + wait until there is a stack "Mainstack" + go to step "Properties interlude" +end step + +skip point + +step "Properties interlude" + Every object in LiveCode has a set of properties associated with it. These + properties control the appearance, location and behavior of the objects + in your app. + + The Property Inspector is a window that allows you to control these properties. +action + interlude + go to step "Select Stack" +end step + +step "Select Stack" + Ensure this is the active stack, by clicking on it. +action + highlight stack "Mainstack" + wait until stack "Mainstack" is selected + go to step "Set Stack Properties" +end step + +step "Set Stack Properties" + Click on the 'Inspector' icon on the Toolbar to open the Property + Inspector. +action + highlight toolbar "Inspector" + wait until there is an inspector for stack "Mainstack" + go to step "Set Stack Title" +end step + +step "Set Stack Title" + Set the 'Title' property of the stack to "Hello World" and press + the <Return> key. + + You will see the title of the stack change after you set the property. +action + highlight property "title" of section "basic" + wait until the title of stack "Mainstack" is "Hello World" + go to step "Tools Palette Interlude" +end step + +skip point + +step "Tools Palette Interlude" + The next step is to add some objects to your stack. + + This is the Tools Palette. It contains all the built-in objects that + you can drag out onto your stack, such as buttons, text fields and + scrollbars. It also contains more complex controls including a header bar, + navigation bar, browser and line graph. +action + interlude + highlight tools + go to step "Create Button" +end step + +step "Create Button" + The first object we will add is a button. Clicking on this button will + show a message to the user. + + Drag a button from the tools palette onto your stack. +action + highlight tool "Create Button" + capture the next new button of stack "Mainstack" as "hello" + wait until there is a button "hello" + go to step "Select Button 1" +end step + +step "Select Button 1" + Select the button by clicking on it. + + The selection handles should show around the button. +action + highlight button "hello" + wait until button "hello" is selected + go to step "Set Button Location" +end step + +step "Set Button Location" + Position the button, as shown. +action + add guide "buttonLoc" with rect "159,119,241,142" to stack "Mainstack" + highlight guide "buttonLoc" + wait until button "hello" fits guide "buttonLoc" with tolerance 5 + go to step "Select Button For Inspector" +end step + +step "Select Button For Inspector" + Select the button by clicking on it. + + The selection handles should show around the button. +action + highlight button "hello" + wait until button "hello" is selected + go to step "Open Property Inspector" +end step + +step "Open Property Inspector" + Click on the 'Inspector' icon in the Toolbar to open the Property Inspector + for the button. + + Remember that properties control how objects look and behave and can be set using the Property Inspector. +action + highlight toolbar "Inspector" + wait until there is an inspector for button "hello" + go to step "Set button name" +end step + +step "Set button name" + Set the 'Name' property of the button to "Say Hello" and press + the <Return> key. You will see the Name appear on the button. +action + highlight property "name" of section "Basic" + wait until the name of button "Hello" is "Say Hello" + go to step "Events and messages interlude" +end step + +skip point + +step "Events and messages interlude" + Now that the UI is complete the next stage is to add code to the app + to make it interactive. + + LiveCode apps work by responding to 'messages', which are usually triggered by some kind of user action. A message might tell the app that the user has + clicked on a button or typed in a field. You add code to tell the app what + to do when a message is received. + + Each object has it's own individual code, so different buttons can respond to + messages in different ways. +action + interlude + go to step "Select Button For Editor" +end step + +step "Select Button For Editor" + Select the button by clicking on it. + + The selection handles should show around the button. +action + highlight button "hello" + wait until button "hello" is selected + go to step "Open Add Script" +end step + +step "Open Add Script" + Select the button and click the 'Code' button in the Toolbar. +action + highlight toolbar "Code" + wait until there is a script editor for button "Hello" + go to step "Script Editor Interlude" +end step + +step "Script Editor Interlude" + The Script Editor is a window that allows you to add code to the + objects on your stack. + + Any code you have added in the Script Editor does not become live + until you click on the 'Apply' button. When this is clicked, you will + get feedback about whether the code you have written has any + errors in it or not. +action + interlude + highlight "Apply" of script editor for button "Hello" + go to step "mouseUp message" +end step + +skip point + +step "mouseUp message" + The message we will respond to is 'mouseUp'. This message is sent when the + user clicks on the button. + + We will add code to display a message to the user saying "Hello World!" + + Add this handler to the button script. + + Don't forget to click the 'Apply' button when you have finished. +script + on mouseUp + answer "Hello World!" + end mouseUp +action + highlight script editor for button "Hello" + wait until button "Hello" is scripted + go to step "Edit Tool Interlude" +end step + +skip point + +step "Edit Tool Interlude" + LiveCode has two modes: Edit mode and Run mode. + + Up until now you have been in Edit mode all the time. In Edit mode + you can add, edit and move objects on your stack. You can also select objects + to change their properties or add code to them. +action + interlude + highlight tool "Edit Mode" + go to step "Run Tool Interlude" +end step + +step "Run Tool Interlude" + In Run mode your app is live - objects will behave as they would for + the app user. For example, clicking on the 'Say Hello' button will show a hello message. + + To test the code you have just added, we are going to enter Run mode and click the button. + + Select 'Run mode' in the Tools Palette. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Test Button" +end step + +step "Test Button" + Click on the 'Say Hello' button to see the message. +action + highlight button "hello" + wait until button "hello" pops up answer dialog + go to step "Next Steps" +end step + +step "Next Steps" + That's it, you have finished your app. + + Why don't you try customizing it by changing the message or adding multiple buttons that display different messages. + + To learn more about LiveCode development why not try a more advanced tutorial or take a look at some of the lessons in our Lessons portal. +action + interlude + highlight toolbar "Tutorials" + go to step "Using in FileMaker" +end step + +epilogue + Congratulations on completing your first LiveCode app. You have learned + + - How to build the User Interface(UI) of an app by dragging and dropping objects + + - The basics of coding in LiveCode to add interactivity to your app + + - How to use the features of the LiveCode Integrated Development Environment (IDE) +end epilogue diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson 0.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson 0.txt new file mode 100755 index 0000000000..ff6563cc9d --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson 0.txt @@ -0,0 +1,147 @@ +tutorial "Using Timers" + +prologue + text +end prologue + +step "Create Mainstack" + +action + highlight menu item "Default size" of menu item "New Stack" of menu "File" + capture the next new stack as "Mainstack" + capture the next new card of stack "Mainstack" as "home" + wait until there is a stack "Mainstack" + go to step "Set Stack Properties" +end step + +step "Set Stack Properties" + Click on the Inspector icon on the toolbar to open the property + inspector. +action + highlight toolbar "Inspector" + wait until there is an inspector for stack "Mainstack" + go to step "Set Stack Title" +end step + +step "Set Stack Title" + Set the 'Title' of the stack to "Timer". +action + highlight property "title" of section "basic" + wait until the title of stack "Mainstack" is "Timer" + go to step "Set stack color" +end step + +step "Set stack color" + Set the 'Background fill' of the graphic to white (255,255,255). +action + highlight property "backgroundColor" of section "Colors" + wait until the backgroundColor of stack "Mainstack" is "255,255,255" + go to step "Create start button" +end step + +step "Create start button" + Drag a button from the tools palette onto your stack. +action + highlight tool "Create Button" + capture the next new button of stack "Mainstack" as "start" + wait until there is a button "start" + go to step "Set start location" +end step + +step "Set start Location" + Resize and position the button, as shown. +action + add guide "startLoc" with rect "159,39,241,62" to stack "Mainstack" + highlight guide "startLoc" + wait until button "start" fits guide "startLoc" with tolerance 5 + go to step "Start Property Inspector" +end step + +step "Start Property Inspector" + Select the button and open the Inspector from the Menubar. +action + highlight button "start" + wait until there is an inspector for button "start" + go to step "Set start name" +end step + +step "Set start name" + Set the 'Name' of the button to "Start". +action + highlight property "name" of section "Basic" + wait until the name of button "start" is "Start" + go to step "Create clock background" +end step + +step "Create clock background" + Import the clock background image file onto your stack. +file + clockBackground.png +action + highlight menu item "Image File..." of menu item "Import as Control" of menu "File" + capture the next new image of stack "Mainstack" as "background" + wait until there is a image "background" + go to step "Create seconds graphic" +end step + +step "Create seconds graphic" + Drag an oval graphic from the tools palette onto your stack. +action + highlight tool "Create Oval Graphic" + capture the next new graphic of stack "Mainstack" as "seconds" + wait until there is a graphic "seconds" + go to step "Set seconds Location" +end step + +step "Set seconds Location" + Resize and position the graphic, as shown by dragging the resize handle. +action + add guide "secondsLoc" with rect "142,143,256,257" to stack "Mainstack" + highlight guide "secondsLoc" + wait until graphic "seconds" fits guide "secondsLoc" with tolerance 5 + go to step "Seconds Property Inspector" +end step + +step "Seconds Property Inspector" + Select the graphic and open the Inspector from the Menubar. +action + highlight graphic "seconds" + wait until there is an inspector for graphic "seconds" + go to step "Set seconds name" +end step + +step "Set seconds name" + Set the 'Name' of the graphic to "seconds". +action + highlight property "name" of section "Basic" + wait until the name of graphic "seconds" is "seconds" + go to step "Set seconds line thickness" +end step + +step "Set seconds line thickness" + Set the 'Line thickness' of the graphic to 0. +action + highlight property "lineSize" of section "Basic" + wait until the lineSize of graphic "seconds" is "0" + go to step "Set seconds color" +end step + +step "Set seconds color" + Set the 'Background fill' of the graphic to purple (127,127,255). +action + highlight property "backgroundColor" of section "Colors" + wait until the backgroundColor of graphic "seconds" is "127,127,255" + go to step "Set seconds arc" +end step + +step "Set seconds arc" + Set the 'Arc' of the graphic to 6. +action + highlight property "arcAngle" of section "Basic" + wait until the arcAngle of graphic "seconds" is "8" + go to step "Start button code 1" +end step + +epilogue + epilogue +end epilogue diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson.txt new file mode 100755 index 0000000000..ce36386eed --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/lessons/App Lesson.txt @@ -0,0 +1,252 @@ +tutorial "Using Timers" + +prologue + In this tutorial we're going to look at using timers to update the screen. You might want to + + - Check and display the progress of a task + + - Set events and reminders + + - Draw animation +end prologue + +step "Introduction" + You'll learn to + + - Use a timer to move the seconds hand on a clock + + - Cancel timers +action + interlude + go to step "Load stack" +end step + +step "Load stack" + +action + load lesson "App Lesson 0" + go to step "Start button code 1" +end step + +step "Start button code 1" + The stack consists of a clock background image, a graphic used as the "seconds" hand and a "Start/Stop" button to start the seconds hand ticking. + + We will be creating the motion of the second hand by adjusting the Start angle on the "seconds" graphic to give us the effect of movement. + + To start the seconds hand ticking we will add code to the "Start" button. +action + interlude + go to step "Start button code 2" +end step + +step "Start button code 2" + To make changes select 'Edit' mode. +action + highlight tool "Edit Mode" + wait until the tool is edit + go to step "Start button code 2b" +end step + +step "Start button code 2b" + Select the "Start" button . +action + highlight button "start" + wait until button "start" is selected + go to step "Start button code 3" +end step + +step "Start button code 3" + Open the Script editor for the button by clicking the 'Code' button in the Toolbar. +action + highlight toolbar "Code" + wait until there is a script editor for button "start" + go to step "Start button code 4" +end step + +step "Start button code 4" + Add this handler to the button script. We'll go through the code one line at a time next. + + Don't forget to click the 'Apply' button when you have finished. +script + local sTimerID + + on mouseUp + if the label of me is "Start" then + updateClock + set the label of me to "Stop" + else + cancel sTimerID + set the label of me to "Start" + end if + end mouseUp +action + highlight script editor for button "start" + wait until button "start" is scripted + go to step "Start button code 5" +end step + +step "Start button code 5" + When the mouse is clicked, first we check that the timer isn't already running by checking the label of the button. +action + interlude + highlight line "if the label of me" of script editor for button "start" + go to step "Start button code 6" +end step + +step "Start button code 6" + If the label of the button is "Start" we send a message 'updateClock'. +action + interlude + highlight line "updateClock" of script editor for button "start" + go to step "Start button code 7" +end step + +step "Start button code 7" + We then set the label of the button to "Stop". +action + interlude + highlight line "set the label of me to" of script editor for button "start" + go to step "Start button code 8" +end step + +step "Start button code 8" + If the button label is not already "Start", then we must be stopping the clock, so we cancel the timer. +action + interlude + highlight line "cancel sTimerID" of script editor for button "start" + go to step "Start button code 9" +end step + +step "Start button code 9" + Then we change the label of the button back to "Start". +action + interlude + highlight line "end if" of script editor for button "start" + go to step "Start button code 10" +end step + +skip point + +step "Start button code 10" + Next we need to implement the updateClock message. This handler will + + - Get the seconds part of the current time + + - Calculate the angle to set the hands to + + - Set the angle of the second hand + + - Tell the clock to update again in 1 second +action + interlude + go to step "Start button code 11" +end step + +step "Start button code 11" + Add this handler to the button script. We'll go through the code one line at a time next. + + Don't forget to click the 'Apply' button when you have finished. +script + local sTimerID + + on mouseUp + if the label of me is "Start" then + updateClock + set the label of me to "Stop" + else + cancel sTimerID + set the label of me to "Start" + end if + end mouseUp + + on updateClock + set the itemDel to ":" + put word 1 of item 3 of the long time into tSeconds + put 360 - (tSeconds - 15) * 6 into tAngle + set the startAngle of graphic "seconds" to tAngle + + send "updateClock" to me in 1 second + put the result into sTimerID + end updateClock +action + highlight script editor for button "start" + wait until button "start" is scripted + go to step "Start button code 12" +end step + +step "Start button code 12" + First, we set the item delimiter - the character used to separate items in our string - to colon. This is because time is formatted separated by a colon e.g. +action + interlude + highlight line "set the itemDel to" of script editor for button "start" + go to step "Start button code 13" +end step + +step "Start button code 13" + Then we put word 1 of item 3 of the long time (fetched from the system) into a variable, 'tSeconds'. The long time is formatted as + + 12:50:15 PM + + Item 3 is "15 PM", so word 1 of item 3 gives us the seconds part. +action + interlude + highlight line "put word 1 of item 3" of script editor for button "start" + go to step "Start button code 14" +end step + +step "Start button code 14" + Next we calculate the angle to set the hand to, based on the seconds variable. We put this into 'tAngle' variable. +action + interlude + highlight line "put 360 - (tSeconds - 15)" of script editor for button "start" + go to step "Start button code 15" +end step + +step "Start button code 15" + Then we set the start angle - which exact slice of our graphic we are showing - to 'tAngle'. +action + interlude + highlight line "set the startAngle of graphic" of script editor for button "start" + go to step "Start button code 16" +end step + +step "Start button code 16" + We want to update the timer every second so we send the 'updateClock' message again in 1 second, creating a loop. +action + interlude + highlight line "send" of script editor for button "start" + go to step "Start button code 17" +end step + +step "Start button code 17" + Finally, we put the result of all this work into a local variable, 'sTimerID', which we declared at the top of the script. This means we can use it again in the first mouseUp handler, to stop the timer as well as start it. +action + interlude + highlight line "put the result into sTimerID" of script editor for button "start" + go to step "Run mode" +end step + +step "Run mode" + Try is out by switching into 'Run' mode on the Tools palette. + + Select 'Run mode' in the Tools Palette. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Test 1" +end step + +step "Test 1" + Click on the 'Start' button. You will see the seconds hand start to tick around the clock. Click it again to stop the clock. +action + highlight button "start" + wait until the label of button "start" is "Stop" +end step + +epilogue + Congratulations. You have learned how to + + - Use a timer to move the seconds hand on a clock + + - Cancel timers +end epilogue diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/resources/clockBackground.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/resources/clockBackground.png new file mode 100644 index 0000000000..ddcc7cfd65 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/Timers/resources/clockBackground.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2.png new file mode 100644 index 0000000000..e2ca0d5df8 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2_small.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2_small.png new file mode 100644 index 0000000000..2b2cfdbbe7 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenShot2_small.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot.png new file mode 100644 index 0000000000..04efb43ecf Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot_small.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot_small.png new file mode 100644 index 0000000000..54f46d8bba Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/linux/ToDoListScreenshot_small.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot.png new file mode 100644 index 0000000000..6d1fda905f Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2.png new file mode 100644 index 0000000000..6bf9690830 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2_small.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2_small.png new file mode 100644 index 0000000000..045955d3f1 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot2_small.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot_small.png b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot_small.png new file mode 100644 index 0000000000..ab724bc7ce Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/mac/ToDoListScreenshot_small.png differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot.PNG b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot.PNG new file mode 100755 index 0000000000..98a3f53ed8 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot.PNG differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2.PNG b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2.PNG new file mode 100755 index 0000000000..ed95879edc Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2.PNG differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2_small.PNG b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2_small.PNG new file mode 100755 index 0000000000..bdce56d882 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot2_small.PNG differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot_small.PNG b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot_small.PNG new file mode 100755 index 0000000000..18441a9e40 Binary files /dev/null and b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/_resources/windows/ToDoListScreenshot_small.PNG differ diff --git a/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/lessons/App Lesson.txt b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/lessons/App Lesson.txt new file mode 100755 index 0000000000..dcf65fbe31 --- /dev/null +++ b/Toolset/palettes/tutorial/courses/First Run/tutorials/To Do List/lessons/App Lesson.txt @@ -0,0 +1,721 @@ +tutorial "To Do List" + +prologue + In this tutorial we will create a simple To Do List. + + The finished app can be built into a self-contained app that can be shared + with anyone, even if they don't have LiveCode. +image + ToDoListScreenshot.png +end prologue + +step "Tutorial Intro I" + In creating this app you will learn: + + - How to build the User Interface(UI) of an app by dragging and dropping objects + + - The basics of coding in LiveCode to add user interactivity to your app + + - How to use the features of the LiveCode Integrated Development Environment (IDE) + + - How to build your app as a self contained application. In LiveCode we call this a standalone. +action + interlude + go to step "Tutorials Intro" +end step + +step "Tutorials Intro" + You can keep track of how much of the tutorial you have completed + with this progress bar, and exit the tutorial at any time by + clicking on the stop button. + + Clicking the fast-forward button will skip to the next important + concept being introduced in the tutorial. Use this if you've got the + idea about something and don't want to have to create every last + part of the user interface, for example. + + The tutorial will also help you out by disabling the parts of the IDE you + don't need for the current step. +action + interlude + highlight toolbar "tutorial" + go to step "Stack Interlude" +end step + +skip point + +step "Stack Interlude" + In this first section of the tutorial, we will create the User + Interface (UI) for the To Do List app. + + The first step in creating a LiveCode application is creating a + stack. A stack is the canvas for your app. Every window you see in LiveCode + is a stack. + + In this tutorial we will create our stack at iPhone 5 size. +action + interlude + go to step "Create Mainstack" +end step + +step "Create Mainstack" + Click on the File menu, and select 'New Stack' → 'iPhone 5 (320x568)'. +action + highlight menu item "iPhone 5 (320x568)" of menu item "New Stack" of menu "File" + capture the next new stack as "Mainstack" + capture the next new card of stack "Mainstack" as "ToDoList" + wait until there is a stack "Mainstack" + go to step "Set Stack Rect" +end step + +step "Set Stack Rect" + Resize the stack so that it has width 320 and height 568. +action + add guide "Stack" with rect "0,0,320,568" to stack "Mainstack" + highlight guide "Stack" + wait until stack "Mainstack" fits guide "Stack" with tolerance 5 + go to step "Properties interlude" +end step + +step "Properties interlude" + Every object in LiveCode has a set of properties associated with it. These + properties control the appearance, location and behavior of the objects + in your app. + + The Property Inspector is a window that allows you to control these properties. +action + interlude + go to step "Select Stack For Inspector" +end step + +step "Select Stack For Inspector" + Ensure this is the active stack, by clicking on it. +action + highlight stack "Mainstack" + wait until stack "Mainstack" is selected + go to step "Set Stack Properties" +end step + +step "Set Stack Properties" + Click on the Inspector icon on the Toolbar to open the Property + Inspector. +action + highlight toolbar "Inspector" + wait until there is an inspector for stack "Mainstack" + go to step "Property Inspector Interlude" +end step + +step "Property Inspector Interlude" + Properties of objects are grouped into sections. You can hover over + the icons at the top of the Property Inspector to see what each section is + called. +action + interlude + highlight inspector for stack "Mainstack" + go to step "Set Stack Title" +end step + +skip point + +step "Set Stack Title" + The first property we will set is the 'Title' of the stack. You will see the + title of the stack change after you set the property. + + Set the 'Title' of the stack to "To Do List" and press the + <Return> key. +action + highlight property "title" of section "basic" + wait until the title of stack "Mainstack" is "To Do List" + go to step "Tools Palette Interlude" +end step + +skip point + +step "Tools Palette Interlude" + The next step is to add some objects to your stack. + + This is the Tools Palette. It contains all the built-in objects that + you can drag out onto your stack, such as buttons, text fields and + scrollbars. It also contains more complex controls including a header bar, + navigation bar, browser and line graph. +action + interlude + highlight tools + go to step "Create Add Icon" +end step + +step "Create Add Icon" + The first object we will add is an 'add' icon. The user will click on this to + add a new item to the list. + + Drag an SVG Icon from the Tools Palette onto your stack. +action + highlight tool "Create com.livecode.widget.svgpath" + capture the next new widget of stack "Mainstack" as "add" + wait until there is a widget "add" + go to step "Select SVG Icon 1" +end step + +step "Select SVG Icon 1" + Select the SVG Icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "add" + wait until widget "add" is selected + go to step "Set Add Location" +end step + +step "Set Add Location" + Resize and position the icon, as shown. +action + add guide "addLoc" with rect "280,10,310,40" to stack "Mainstack" + highlight guide "addLoc" + wait until widget "add" fits guide "addLoc" with tolerance 5 + go to step "Select SVG Icon For Inspector" +end step + +step "Select SVG Icon For Inspector" + Select the SVG Icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "add" + wait until widget "add" is selected + go to step "Open Property Inspector" +end step + +step "Open Property Inspector" + Next we need to set some properties of the icon. + + Click on the Inspector icon in the Toolbar to open the Property Inspector for the + icon. +action + highlight toolbar "Inspector" + wait until there is an inspector for widget "add" + go to step "Set add name" +end step + +step "Set add name" + The 'Name' property is used when we refer to an object in the code. We want to + use short, unique, descriptive names to make it easier when we start writing + code. + + Set the name property of the SVG Icon to "Add" and press the + <Return> key. +action + highlight property "name" of section "Basic" + wait until the name of widget "add" is "Add" + go to step "Set add icon" +end step + +step "Set add icon" + The 'Preset' property of SVG icon lets you choose the icon you want to show, + in this case we want a '+' symbol. + + Click on the 'Preset' property where it shows a star. This will pop up a + set of icons for you to choose from. Choose the plus icon, its name in the + list is 'plus'. You might need to scroll the list of icons to find the one you want. +action + highlight property "iconPresetName" of section "Basic" + wait until the iconPresetName of widget "add" is "plus" + go to step "Create task list" +end step + +skip point + +step "Create task list" + Next we want to add a list field. This will be used to display the list of tasks. + + Drag a list field from the Tools Palette onto your stack. +action + highlight tool "Create list field" + capture the next new field of stack "Mainstack" as "TaskList" + wait until there is a field "TaskList" + go to step "Select Field 1" +end step + +step "Select Field 1" + Select the field by clicking on it. + + The selection handles will show around the field. +action + highlight field "TaskList" + wait until field "TaskList" is selected + go to step "Set task list Location" +end step + +step "Set task list Location" + Resize and position the field, as shown. +action + add guide "taskListLoc" with rect "0,60,320,568" to stack "Mainstack" + highlight guide "taskListLoc" + wait until field "taskList" fits guide "taskListLoc" with tolerance 5 + go to step "Select Field For Inspector" +end step + +step "Select Field For Inspector" + Select the field by clicking on it. + + The selection handles will show around the field. +action + highlight field "TaskList" + wait until field "TaskList" is selected + go to step "Task List PI" +end step + +step "Task List PI" + As before we need to set some properties of the field. + + Click on the Inspector icon in the Toolbar to open the Property Inspector for the + field. +action + highlight toolbar "Inspector" + wait until there is an inspector for field "taskList" + go to step "Set task list name" +end step + +step "Set task list name" + Again, we want to give the field a short descriptive name to make things + easier when we write code. + + Set the name of the field to "TaskList" and press the <Return> key. +action + highlight property "name" of section "Basic" + wait until the name of field "taskList" is "TaskList" + go to step "Set task list contents" +end step + +skip point + +step "Set task list contents" + We want the task list to start off empty. Delete the default contents from + the field and click away to allow the change to take effect. +action + highlight property "styledText" of section "contents" + wait until the text of field "taskList" is "" + go to step "Events and messages interlude" +end step + +skip point + +step "Events and messages interlude" + Now that the first part of the UI is complete the next stage is to add code to the app + to allow the user to interact with it. + + LiveCode apps work by responding to 'messages', which are usually triggered by + some kind of user action. A message might tell the app that the user has + clicked on a button or typed in a field. You add code to tell the app what + to do when a message is received. + + Each object has its own individual code, so different buttons can respond to + messages in different ways. +action + interlude + go to step "Select SVG Icon For Editor" +end step + +step "Select SVG Icon For Editor" + Select the SVG Icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "add" + wait until widget "add" is selected + go to step "Open Add Script" +end step + +step "Open Add Script" + Select the Add icon then click the Code button in the Toolbar. +action + highlight toolbar "Code" + wait until there is a script editor for widget "add" + go to step "Script Editor Interlude" +end step + +step "Script Editor Interlude" + The Script Editor is a window that allows you to add code to the + objects on your stack. + + The code you have added in the Script Editor does not become live + until you click on the 'Apply' button. When this is clicked, you will + get feedback about whether the code you have written has any + errors in it or not. +action + interlude + highlight "Apply" of script editor for widget "header" + go to step "mouseUp message" +end step + +skip point + +step "mouseUp message" + The message we will respond to is 'mouseUp'. This message is sent when the + user clicks on the Add icon. + + We will add code to add a new task to the list. When the user clicks + the 'add' icon the app asks the user to enter a task and adds it to the + bottom of the list. + + Add this handler to the script of 'add' icon. + + Don't forget to click the 'Apply' button when you have finished. +script + on mouseUp + ask "Please enter a task" + + if field "TaskList" is empty then + put it into field "TaskList" + else + put return & it after field "TaskList" + end if + end mouseUp +action + highlight script editor for widget "add" + wait until widget "add" is scripted + go to step "Explain ask" +end step + +step "Explain ask" + The ask command displays a dialog box with a prompt, a text box for the user + to enter a response, and OK and Cancel buttons. + + You use the ask command when you need to get information from the user before + continuing. +action + interlude + highlight line "ask" of script editor for widget "add" + go to step "Edit Tool Interlude"" +end step + +skip point + +step "Edit Tool Interlude" + LiveCode has two modes: Edit mode and Run mode. + + Up until now you have been in Edit mode all the time. In Edit mode + you can add, edit and move objects on your stack. You can also select objects + to change their properties or add code to them. +action + interlude + highlight tool "Edit Mode" + go to step "Run Tool Interlude" +end step + +step "Run Tool Interlude" + In Run mode your app is live - objects will behave as they would for + the app user. For example, clicking on the 'Add' button will allow you to add + a task to the list. + + To test the code you have just added, we are going to enter Run mode and try + adding a task to the list. +action + interlude + highlight tool "Run Mode" + go to step "Test Task List" +end step + +step "Test Task List" + Select 'Run mode' in the Tools Palette. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Add task" +end step + +skip point + +step "Add task" + Click the 'Add' icon and enter a task, it will appear at the bottom of the list. +action + highlight widget "add" + wait until the text of field "taskList" is changed with default "Buy milk" + go to step "Return to Edit Mode" +end step + +skip point + +step "Return to Edit Mode" + Change back to Edit mode to continue working on the app. +action + highlight tool "Edit Mode" + wait until the tool is edit + go to step "Delete action interlude" +end step + +step "Delete action interlude" + As well as adding tasks to the list the user will also want to delete tasks + when they are complete. + + We will add a 'Delete' option next to 'Add' to allow the user to delete a task + from the list. +action + interlude + go to step "Create delete icon" +end step + +step "Create delete Icon" + To create the 'Delete' icon drag another SVG Icon from the Tools Palette onto your stack. +action + highlight tool "Create com.livecode.widget.svgpath" + capture the next new widget of stack "Mainstack" as "delete" + wait until there is a widget "delete" + go to step "Select SVG Icon 2" +end step + +step "Select SVG Icon 2" + Select the icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "delete" + wait until widget "delete" is selected + go to step "Set Delete Location" +end step + +step "Set Delete Location" + Resize and position the icon, as shown. +action + add guide "deleteLoc" with rect "240,10,270,40" to stack "Mainstack" + highlight guide "deleteLoc" + wait until widget "delete" fits guide "deleteLoc" with tolerance 5 + go to step "Select Delete For Inspector" +end step + +step "Select Delete For Inspector" + Select the icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "delete" + wait until widget "delete" is selected + go to step "Open Delete Property Inspector" +end step + +step "Open Delete Property Inspector" + Next we need to set the properties of the 'Delete' icon. + + Click on the Inspector icon on the Toolbar to open the Property Inspector for the + SVG icon. +action + highlight toolbar "Inspector" + wait until there is an inspector for widget "delete" + go to step "Set delete name" +end step + +step "Set delete name" + Set the name property of the SVG Icon to "Delete" and press the + <Return> key. +action + highlight property "name" of section "Basic" + wait until the name of widget "delete" is "Delete" + go to step "Set delete icon" +end step + +step "Set delete icon" + Next we will set the image to be shown for the 'Delete' icon. + + Click on the 'Preset' property and choose the trash bin icon, its name in the + list is 'trash'. +action + highlight property "iconPresetName" of section "Basic" + wait until the iconPresetName of widget "delete" is "trash" + go to step "Select Delete For Editor" +end step + +step "Select Delete For Editor" + Select the icon by clicking on it. + + The selection handles will show around the icon. +action + highlight widget "delete" + wait until widget "delete" is selected + go to step "Open Delete script" +end step + +step "Open Delete Script" + Select the 'Delete' icon then click the Code icon in the Toolbar to open the Script Editor for the icon. +action + highlight toolbar "Code" + wait until there is a script editor for widget "delete" + go to step "Delete mouseUp" +end step + +step "Delete mouseUp" + Just like for the 'Add' icon the 'Delete' icon will respond to the + 'mouseUp' message. + + When the user clicks on the 'Delete' icon the task that is selected + in the list will be deleted. We will confirm the deletion with the + user before deleting the task. + + Add this handler to the script of the 'Delete' icon. + + Don't forget to click the 'Apply' button when you have added the code. +script + on mouseUp + + answer "Do you want to delete this task?" with "Yes" and "No" + + if it is "Yes" then + delete line (the hilitedLine of field "TaskList") of field "TaskList" + end if + end mouseUp +action + highlight script editor for widget "delete" + wait until widget "delete" is scripted + go to step "Run mode 2" +end step + +step "Run mode 2" + To test the code you have just added enter Run mode and delete the first + task by selecting the line in the list and clicking on the 'Delete' icon. + + Start by entering Run mode. +action + highlight tool "Run Mode" + wait until the tool is run + go to step "Test Delete Task" +end step + +step "Test Delete Task" + Select the first task and click the 'Delete' icon. Answer 'Yes' when + presented with the delete options. + + The task will be deleted from the list. +action + highlight widget "delete" + wait until the text of field "taskList" is changed with default "" + go to step "Return to Edit Mode 2" +end step + +step "Return to Edit Mode 2" + Change back to 'Edit' mode to continue working on the app. +action + highlight tool "Edit Mode" + wait until the tool is edit + go to step "Saving Data Interlude" +end step + +step "Saving Data Interlude" + Once you have built your app into a standalone it can't be changed, + so any data that should persist between uses of the app has to be + saved outside the app itself. + + We want the tasks we add to be saved when we close the app so we + need to save the task list when the app is closed and read it in + when the app is opened. +action + interlude + go to step "closeStack handler" +end step + +step "closeStack handler" + When a stack is closed it receives a 'CloseStack' message. Any + clean-up can be done in this handler. + + In this app we will save the list of tasks before the app is closed. + The contents of the 'TaskList' field are saved to a text file in the + 'Documents' folder, ready to be loaded in the next time the app is + opened. There is a 'Documents' folder on all platforms so this code + will work on desktop and mobile. +action + interlude + go to step "Select Stack For Editor" +end step + +step "Select Stack For Editor" + Ensure this is the active stack, by clicking on it. +action + highlight stack "Mainstack" + wait until stack "Mainstack" is selected + go to step "Open Stack Script" +end step + +step "Open Stack Script" + Just like the SVG icons and other objects a Stack can have code + associated with it and receive messages. + + The CloseStack message is sent to the stack so will be handled on + the Stack Script. + + Click on the Object menu, and select 'Stack Script' to open the + Script Editor for the stack. +action + highlight menu item "Stack Script" of menu "Object" + wait until there is a script editor for stack "Mainstack" + go to step "closeStack code" +end step + +step "closeStack code" + In the closeStack handler we work out the full path to the text + file that will be used to store the To Do list and save the + contents of the field to the text file. + + Add this handler to the Stack Script and press 'Apply'. +script + on closeStack + local tFile + put specialFolderPath("documents") & "/ToDoList.txt" into tFile + put field "TaskList" into url ("file:" & tFile) + end closeStack +action + highlight script editor for stack "Mainstack" + wait until stack "Mainstack" is scripted + go to step "preOpenStack code" +end step + +step "preOpenStack code" + When a stack is opened it receives a 'PreOpenStack' message. Any + set-up can be done in this handler, before the stack becomes visible + to the user. + + When the stack is opened we will load in the saved tasks form the + text file in the 'Documents' folder. + + Add this handler to the Stack Script and press 'Apply'. +script + on preOpenStack + local tFile + put specialFolderPath("documents") & "/ToDoList.txt" into tFile + put url ("file:" & tFile) into field "TaskList" + end preOpenStack + + on closeStack + local tFile + put specialFolderPath("documents") & "/ToDoList.txt" into tFile + put field "TaskList" into url ("file:" & tFile) + end closeStack +action + highlight script editor for stack "Mainstack" + wait until stack "Mainstack" is scripted + go to step "Save Standalone" +end step + +step "Save Standalone" + Before you can prepare your app for sharing you need to set is up to + build as a self contained, or 'standalone' app. + + You set up this up by selecting the platforms you want to build for + and setting some properties for the app. You then choose "Save As + Standalone Application..." from the File menu. This will build the + executable files for the selected platforms. + + For more details see this lesson +url + http://lessons.livecode.com/m/4603/l/44282-building-standalone-applications +action + interlude + go to step "epilogue" +end step + +skip point + +epilogue + That's it, you have finished your app. Switch back to 'Run' mode and try it out. + + Why don't you try customizing it by changing some properties such as the + icon colors or task list font and text size. +image + ToDoListScreenshot2.png +end epilogue diff --git a/Toolset/palettes/tutorial/revtutorial.livecodescript b/Toolset/palettes/tutorial/revtutorial.livecodescript index 786a00b2ea..7e51f63fc4 100644 --- a/Toolset/palettes/tutorial/revtutorial.livecodescript +++ b/Toolset/palettes/tutorial/revtutorial.livecodescript @@ -432,18 +432,26 @@ end revTutorialParseInterlude on revTutorialParseLoad pTokens, @rData local tData revTutorialParseLine "load lesson <token>", pTokens, tData - if the result is not empty then - return the result + if the result is empty then + put "load" into rData["type"] + put tData[1] into rData["lesson"] + return empty end if - put "load" into rData["type"] - put tData[1] into rData["lesson"] - return empty + + revTutorialParseLine "load stack <token>", pTokens, tData + if the result is empty then + put "load" into rData["type"] + put tData[1] into rData["stack"] + return empty + end if + + return the result end revTutorialParseLoad on revTutorialParseCapture pTokens, @rData local tData revTutorialParseLine "capture set <objlist> as <token>", pTokens, tData - if the result is empty then + if the result is empty then put "set" into rData["type"] put tData[1] into rData["objects"] put tData[2] into rData["tag"] @@ -674,6 +682,17 @@ on revTutorialParseWait pTokens, @rData return empty end if + revTutorialParseSubexpression "the <token> of <object> is changed with default <value>", pTokens, tToken, tCondition + + if the result is empty then + put "property" into rData["wait condition"] + put tCondition[1] into rData["property"] + put tCondition[2] into rData["object"] + put tCondition[3] into rData["default"] + put true into rData["is not"] + return empty + end if + revTutorialParseSubexpression "the <token> of <object> is <value>", pTokens, tToken, tCondition if the result is empty then @@ -681,6 +700,8 @@ on revTutorialParseWait pTokens, @rData put tCondition[1] into rData["property"] put tCondition[2] into rData["object"] put tCondition[3] into rData["value"] + put false into rData["is not"] + return empty end if return the result @@ -811,19 +832,21 @@ constant kMargin = 20 constant kMessageWidth = 200 constant kProgressHeight = 5 -constant kPointerHeight = 30 -constant kPointerWidth = 40 -constant kPointerOffset = 5 - constant kMaxScriptHeight = 200 local sDontShow local sLastShape -on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical - local tGotItButtonID, tCopyButtonID +on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical, pTopLeftOverride + if pTopLeftOverride is not empty then + revTutorialSetTopLeftOverride true + end if + + local tGotItButtonID, tCopyButtonID, tDoItButtonID local tMsgFieldID, tScriptFieldID, tImageID + local tActionButton put the long id of button "Got It" of stack "revTutorial" into tGotItButtonID + put the long id of button "Do It For Me" of stack "revTutorial" into tDoItButtonID put the long id of button "Copy Script" of stack "revTutorial" into tCopyButtonID put the long id of field "Message" of stack "revTutorial" into tMsgFieldID put the long id of field "Script" of stack "revTutorial" into tScriptFieldID @@ -844,9 +867,7 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical put the defaultStack into tDefaultStack set the defaultstack to "revTutorial" if sIsInterlude then - show tGotItButtonID - set the height of tGotItButtonID to the formattedHeight of tGotItButtonID - set the width of tGotItButtonID to the formattedWidth of tGotItButtonID + put tGotItButtonID into tActionButton put max(pWidthOverride, 460) into pWidthOverride else hide tGotItButtonID @@ -856,12 +877,19 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical if the text of tScriptFieldID is empty then put false into tHasScript hide tScriptFieldID + hide tCopyButtonID else put true into tHasScript show tScriptFieldID - set the height of tCopyButtonID to the formattedHeight of tCopyButtonID - set the width of tCopyButtonID to the formattedWidth of tCopyButtonID - show tCopyButtonID + put tCopyButtonID into tActionButton + end if + + # If this is a non-script action step, show the 'Do It For Me' button + if sIsInterlude or tHasScript or \ + revTutorialCanSkipStep() is not true then + hide tDoItButtonID + else + put tDoItButtonID into tActionButton end if local tHasImage @@ -904,7 +932,7 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical put true into tHasPointer end if - local tWidth, tHeight + local tContentWidth, tContentHeight local tMessageHeight, tMessageWidth if pWidthOverride is not empty then put max(kMessageWidth, pWidthOverride) into tMessageWidth @@ -916,8 +944,8 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical set the height of tMsgFieldID to tMessageHeight - put tMessageHeight + kMargin * 2 into tHeight - put the formattedWidth of tMsgFieldID + kMargin * 2 into tWidth + put tMessageHeight + kMargin * 2 into tContentHeight + put the formattedWidth of tMsgFieldID + kMargin * 2 into tContentWidth if tHasScript then local tScriptHeight @@ -935,25 +963,26 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical end if set the height of tScriptFieldID to tScriptHeight - add tScriptHeight + kMargin * 2 to tHeight + add tScriptHeight + kMargin * 2 to tContentHeight - put max(tWidth, the width of tScriptFieldID + kMargin * 2) into tWidth + put max(tContentWidth, the width of tScriptFieldID + kMargin * 2) into tContentWidth end if if tHasUrl then - add the height of tUrlControlID + kMargin * 2 to tHeight - put max(tWidth, the width of tUrlControlID + kMargin * 2) into tWidth + add the height of tUrlControlID + kMargin * 2 to tContentHeight + put max(tContentWidth, the width of tUrlControlID + kMargin * 2) into tContentWidth end if - if sIsInterlude then - add the height of tGotItButtonID + kMargin to tHeight - else if tHasScript then - add the height of tCopyButtonID + kMargin to tHeight + if tActionButton is not empty then + set the height of tActionButton to the formattedHeight of tActionButton + set the width of tActionButton to the formattedWidth of tActionButton + show tActionButton + add the height of tActionButton + kMargin to tContentHeight end if if tHasImage then - add the formattedheight of tImageID + kMargin * 2 to tHeight - put max(tWidth, the formattedwidth of tImageID + kMargin * 2) into tWidth + add the formattedheight of tImageID + kMargin * 2 to tContentHeight + put max(tContentWidth, the formattedwidth of tImageID + kMargin * 2) into tContentWidth end if # Work out what screen the tutorial stack should be on @@ -966,60 +995,63 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical put the working screenrect into tScreenRect end if + local tPointer if tHasPointer then - local tPointerLeft, tPointerTop, tCanFit - revTutorialEnsureOnscreen tWidth, tHeight, tScreenRect, tRect, tPointVertical, tPointerLeft, tPointerTop, tCanFit - - if not tCanFit then - put false into tHasPointer + if not revTutorialIsDraggingWindow() then + if pTopLeftOverride is empty then + put revTutorialPointerCompute(tContentWidth, tContentHeight, tScreenRect, tRect, tPointVertical) \ + into tPointer + else + put revTutorialPointerComputeForTopLeft(tContentWidth, tContentHeight, tRect, pTopLeftOverride) \ + into tPointer + end if + else + put revTutorialGetPointer() into tPointer + revTutorialSetPointer empty end if end if - local tNewShape - put revTutorialWindowShape(tWidth, tHeight, tHasPointer, tPointVertical, tPointerLeft, tPointerTop) into tNewShape - - if revTutorialWindowShapeDifferent(sLastShape, tNewShape) then - put tNewShape into sLastShape - if tHasPointer then - if the platform is "win32" then - set the windowshape of stack "revTutorial" to empty - end if - - revTutorialSetWindowShape tWidth, tHeight, tPointVertical, tPointerLeft, tPointerTop - else + if revTutorialPointerDifferent(tPointer) then + if tPointer is not empty then + // Create the windowshape for the stack and pointer + revTutorialCreateStack tContentWidth, tContentHeight, tPointer + else set the windowshape of stack "revTutorial" to empty set the decorations of stack "revTutorial" to empty end if end if + revTutorialSetPointer tPointer + local tMessageLeft, tMessageTop put kMargin into tMessageLeft put kMargin into tMessageTop - if tHasPointer then - local tStackLeft, tStackTop - revTutorialStackPosition tWidth, tHeight, tRect, tPointVertical, tPointerLeft, tPointerTop, tStackLeft, tStackTop - - if tPointVertical then - add kPointerWidth / 2 to tHeight - if tPointerTop then - add kPointerWidth / 2 to tMessageTop - end if - else - add kPointerWidth / 2 to tWidth - if tPointerLeft then - add kPointerWidth / 2 to tMessageLeft - end if - end if - set the rect of stack "revTutorial" to 0, 0, tWidth, tHeight - set the topleft of stack "revTutorial" to tStackLeft, tStackTop + + local tWidth, tHeight + if tPointer is not empty then + revTutorialPositionStackAndPointer tContentWidth, tContentHeight, tRect, tPointer, tWidth, tHeight + add revTutorialPointerLeftOverhang(tPointer) to tMessageLeft + add revTutorialPointerTopOverhang(tPointer) to tMessageTop else - if sIsInterlude then - set the bottomright of tGotItButtonID to tWidth - kMargin, tHeight - kMargin - else if tHasScript then - set the bottomright of tCopyButtonID to tWidth - kMargin, tHeight - kMargin + put tContentWidth into tWidth + put tContentHeight into tHeight + set the rect of stack "revTutorial" to 0, 0, tContentWidth, tContentHeight + if pTopLeftOverride is empty then + set the loc of stack "revTutorial" to item 3 of tScreenRect / 2, item 4 of tScreenRect / 2 + else + set the topleft of stack "revTutorial" to pTopLeftOverride end if - set the rect of stack "revTutorial" to 0, 0, tWidth, tHeight - set the loc of stack "revTutorial" to item 3 of tScreenRect / 2, item 4 of tScreenRect / 2 + revTutorialSetEffectiveTopLeft the topleft of stack "revTutorial" + end if + + if tActionButton is not empty then + local tButtonBottom, tButtonRight + put tWidth - kMargin into tButtonRight + put tHeight - kMargin into tButtonBottom + + subtract revTutorialPointerRightOverhang(tPointer, tContentWidth) from tButtonRight + subtract revTutorialPointerBottomOverhang(tPointer, tContentHeight) from tButtonBottom + set the bottomright of tActionButton to tButtonRight,tButtonBottom end if if sIsInterlude then @@ -1045,72 +1077,40 @@ on revTutorialPositionStack pStack, pObject, pWidthOverride, pForceVertical unlock screen end revTutorialPositionStack -function revTutorialWindowShape pWidth, pHeight, pHasPointer, pPointVertical, pPointerLeft, pPointerTop - local tShapeA - put pWidth into tShapeA["width"] - put pHeight into tShapeA["height"] - if not pHasPointer then - put false into tShapeA["pointer"] - return tShapeA - end if - - put true into tShapeA["pointer"] - put pPointVertical into tShapeA["pointer-vertical"] - put pPointerLeft into tShapeA["pointer-left"] - put pPointerTop into tShapeA["pointer-top"] - return tShapeA -end revTutorialWindowShape - -function revTutorialWindowShapeDifferent pOldShape, pNewShape - repeat for each key tKey in pNewShape - if pOldShape[tKey] is not pNewShape[tKey] then - return true - end if - end repeat - return false -end revTutorialWindowShapeDifferent +local sEffectiveTopLeft +private command revTutorialSetEffectiveTopLeft pStackTopLeft + put pStackTopLeft into sEffectiveTopLeft +end revTutorialSetEffectiveTopLeft -command revTutorialStackPosition pContentWidth, pContentHeight, pHighlightRect, pPointVertical, pPointerLeft, pPointerTop, @rStackLeft, @rStackTop - local tLeft, tTop, tRight, tBottom - put item 1 of pHighlightRect into tLeft - put item 2 of pHighlightRect into tTop - put item 3 of pHighlightRect into tRight - put item 4 of pHighlightRect into tBottom - - local tStackTop, tStackLeft, tMiddle - if not pPointVertical then - put (tBottom + tTop) / 2 into tMiddle - if pPointerTop then - put tMiddle - kPointerWidth into tStackTop - else - put tMiddle - pContentHeight + kPointerWidth into tStackTop - end if - - if pPointerLeft then - put tRight + kPointerOffset into tStackLeft - else - put tLeft - pContentWidth - kPointerHeight + kPointerOffset into tStackLeft - end if - else - put (tRight + tLeft) / 2 into tMiddle - if pPointerTop then - put tBottom + 5 into tStackTop - else - put tTop - pContentHeight - kPointerHeight + kPointerOffset into tStackTop - end if - - if pPointerLeft then - put tMiddle - kPointerWidth into tStackLeft - else - put tMiddle - pContentWidth + kPointerWidth into tStackLeft - end if +private function revTutorialGetEffectiveTopLeft + return sEffectiveTopLeft +end revTutorialGetEffectiveTopLeft + +local sTopLeftOverride +private function revTutorialTopLeftOverride + if sTopLeftOverride then + return revTutorialGetEffectiveTopLeft() end if - put tStackLeft into rStackLeft - put tStackTop into rStackTop -end revTutorialStackPosition + return empty +end revTutorialTopLeftOverride + +private command revTutorialSetTopLeftOverride pValue + put pValue into sTopLeftOverride +end revTutorialSetTopLeftOverride -command revTutorialSetWindowShape pContentWidth, pContentHeight, pPointVertical, pPointerLeft, pPointerTop +command revTutorialPositionStackAndPointer pContentWidth, pContentHeight, pHighlightRect, pPointer, @rWidth, @rHeight + local tStackLeft, tStackTop, tWidth, tHeight + revTutorialPointerStackPosition pContentWidth, pContentHeight, pHighlightRect, pPointer, tStackLeft, tStackTop + revTutorialPointerStackSize pContentWidth, pContentHeight, pPointer, tWidth, tHeight + set the rect of stack "revTutorial" to 0, 0, tWidth, tHeight + set the topleft of stack "revTutorial" to tStackLeft, tStackTop + + put tWidth into rWidth + put tHeight into rHeight +end revTutorialPositionStackAndPointer + +command revTutorialCreateStack pContentWidth, pContentHeight, pPointer # Store templategraphic props (in case we have a graphic tool selected) local tProps put the properties of the templategraphic into tProps @@ -1122,6 +1122,10 @@ command revTutorialSetWindowShape pContentWidth, pContentHeight, pPointVertical, set the lineSize of the templateGraphic to 0 set the backColor of the templateGraphic to "black" set the opaque of the templateGraphic to true + + # Ensure the window does not have a 1-bit mask + set the blendlevel of the templateGraphic to 1 + create group "Group" put it into tGroup set the margins of it to 0 @@ -1129,60 +1133,259 @@ command revTutorialSetWindowShape pContentWidth, pContentHeight, pPointVertical, create graphic "Shape" in tGroup put it into tGraphic set the style of it to "rectangle" - set the width of it to pContentWidth * the screenpixelscale - set the height of it to pContentHeight * the screenpixelscale + set the width of it to pContentWidth + set the height of it to pContentHeight + set the topleft of it to 0,0 create graphic "Pointer" in tGroup put it into tPointer - set the style of tPointer to "regular" - set the polysides of tPointer to 4 - local tX, tY - if not pPointVertical then - set the width of tPointer to kPointerWidth - set the height of tPointer to kPointerHeight - - if pPointerTop then - put the top of tGraphic + kPointerWidth into tY - else - put the bottom of tGraphic - kPointerWidth into tY - end if - - if pPointerLeft then - put the left of tGraphic into tX - else - put the right of tGraphic into tX - end if - else - set the width of tPointer to kPointerHeight - set the height of tPointer to kPointerWidth - - if pPointerTop then - put the top of tGraphic into tY - else - put the bottom of tGraphic into tY - end if - - if pPointerLeft then - put the left of tGraphic + kPointerWidth into tX - else - put the right of tGraphic - kPointerWidth into tX - end if + revTutorialPointerSetGraphicProps tPointer, tGraphic, pPointer, pContentWidth, pContentHeight + + set the rect of stack "revTutorial" to the formattedRect of tGroup + if revTutorialIsDraggingWindow() then + set the visible of tPointer to false end if - set the loc of tPointer to tX,tY + set the topleft of tGroup to 0,0 reset the templateGraphic set the properties of the templategraphic to tProps import snapshot from rect (the rect of tGroup) of tGroup + set the id of the last image to the id of stack "revIcons" put the long id of the last image into tWindowShape + set the topleft of tWindowShape to 0,0 delete tGroup set the windowshape of stack "revTutorial" to the id of tWindowShape delete tWindowShape -end revTutorialSetWindowShape + +end revTutorialCreateStack + +############################################################################## +# +# POINTER MANAGEMENT +# +############################################################################## + +constant kPointerHeight = 30 +constant kPointerWidth = 40 +constant kPointerOffset = 40 +constant kPointerPadding = 5 +private command revTutorialPointerSetGraphicProps pPointerObj, pContentGraphic, pPointer, pContentWidth, pContentHeight + local tSide, tPos, tSource + put revTutorialPointerSide(pPointer) into tSide + put revTutorialPointerPositionOnSide(pPointer) into tPos + put revTutorialPointerSource(pPointer, pContentWidth, pContentHeight) into tSource + + if pPointer["style"] is "original" then + set the style of pPointerObj to "regular" + set the polysides of pPointerObj to 4 + + if revTutorialPointerVertical(pPointer) then + set the width of pPointerObj to kPointerHeight + set the height of pPointerObj to kPointerWidth + else + set the width of pPointerObj to kPointerWidth + set the height of pPointerObj to kPointerHeight + end if + + set the loc of pPointerObj to \ + the left of pContentGraphic + item 1 of tSource, \ + the top of pContentGraphic + item 2 of tSource + else + set the style of pPointerObj to "line" + set the lineSize of pPointerObj to 3 + + local tTarget + put pPointer["end"]["x"], pPointer["end"]["y"] into tTarget + set the points of pPointerObj to tTarget & return & tSource + end if +end revTutorialPointerSetGraphicProps + +private function revTutorialPointerSide pPointer + set the itemdelimiter to "-" + return item 1 of pPointer["position"] +end revTutorialPointerSide + +private function revTutorialPointerPositionOnSide pPointer + set the itemdelimiter to "-" + return item 2 of pPointer["position"] +end revTutorialPointerPositionOnSide + +private function revTutorialPointerVertical pPointer + local tSide + put revTutorialPointerSide(pPointer) into tSide + return tSide is "top" or tSide is "bottom" +end revTutorialPointerVertical + +private function revTutorialPointerLeft pPointer + return revTutorialPointerSide(pPointer) is "left" or \ + revTutorialPointerPositionOnSide(pPointer) is "left" +end revTutorialPointerLeft + +private function revTutorialPointerSource pPointer, pStackWidth, pStackHeight + switch pPointer["position"] + case "top-left" + return kPointerOffset, 0 + case "top-right" + return pStackWidth - kPointerOffset, 0 + case "right-top" + return pStackWidth, kPointerOffset + case "right-bottom" + return pStackWidth, pStackHeight - kPointerOffset + case "bottom-right" + return pStackWidth - kPointerOffset, pStackHeight + case "bottom-left" + return kPointerOffset, pStackHeight + case "left-bottom" + return 0, pStackHeight - kPointerOffset + case "left-top" + return 0, kPointerOffset + end switch +end revTutorialPointerSource + +private command revTutorialPointerComputeTarget pContentWidth, pContentHeight, pHighlightRect, pStackTopLeft, @xPointer + local tLeft, tTop, tRight, tBottom + put item 1 of pHighlightRect into tLeft + put item 2 of pHighlightRect into tTop + put item 3 of pHighlightRect into tRight + put item 4 of pHighlightRect into tBottom + + local tSide + put revTutorialPointerSide(xPointer) into tSide + + local tSource + put revTutorialPointerSource(xPointer, pContentWidth, pContentHeight) into tSource + + local tAbsoluteX, tAbsoluteY + switch tSide + case "top" + put tBottom + kPointerPadding into tAbsoluteY + put (tRight + tLeft) / 2 into tAbsoluteX + break + case "bottom" + put tTop - kPointerPadding into tAbsoluteY + put (tRight + tLeft) / 2 into tAbsoluteX + break + case "left" + put tRight + kPointerPadding into tAbsoluteX + put (tTop + tBottom) / 2 into tAbsoluteY + break + case "right" + put tLeft - kPointerPadding into tAbsoluteX + put (tTop + tBottom) / 2 into tAbsoluteY + break + end switch + + put tAbsoluteX - item 1 of pStackTopLeft into xPointer["end"]["x"] + put tAbsoluteY - item 2 of pStackTopLeft into xPointer["end"]["y"] + put pStackTopLeft into xPointer["stacktopleft"] +end revTutorialPointerComputeTarget + +local sPointer +function revTutorialStackHasPointer + return sPointer is not empty +end revTutorialStackHasPointer + +private command revTutorialSetPointer pPointer + put pPointer into sPointer +end revTutorialSetPointer + +private function revTutorialGetPointer pPointer + return sPointer +end revTutorialGetPointer + +function revTutorialPointerDifferent pPointer + return pPointer is not sPointer +end revTutorialPointerDifferent + +function revTutorialPointerLeftOverhang pPointer + if revTutorialIsDraggingWindow() then + return 0 + end if + + if pPointer["style"] is "original" then + if revTutorialPointerSide(pPointer) is "left" then + return kPointerWidth / 2 + end if + else if pPointer["end"]["x"] < 0 then + return -(pPointer["end"]["x"]) + end if + + return 0 +end revTutorialPointerLeftOverhang + +function revTutorialPointerTopOverhang pPointer + if revTutorialIsDraggingWindow() then + return 0 + end if + + if pPointer["style"] is "original" then + if revTutorialPointerSide(pPointer) is "top" then + return kPointerWidth / 2 + end if + else if pPointer["end"]["y"] < 0 then + return -(pPointer["end"]["y"]) + end if + + return 0 +end revTutorialPointerTopOverhang + +function revTutorialPointerRightOverhang pPointer, pWidth + if revTutorialIsDraggingWindow() then + return 0 + end if + + if pPointer["style"] is "original" then + if revTutorialPointerSide(pPointer) is "right" then + return kPointerWidth / 2 + end if + else if pPointer["end"]["x"] > pWidth then + return pPointer["end"]["x"] - pWidth + end if + + return 0 +end revTutorialPointerRightOverhang + +function revTutorialPointerBottomOverhang pPointer, pHeight + if revTutorialIsDraggingWindow() then + return 0 + end if + + if pPointer["style"] is "original" then + if revTutorialPointerSide(pPointer) is "bottom" then + return kPointerWidth / 2 + end if + else if pPointer["end"]["y"] > pHeight then + return pPointer["end"]["y"] - pHeight + end if + + return 0 +end revTutorialPointerBottomOverhang + +private function revTutorialPointerPositionCompute pPointerVertical, pPointerLeft, pPointerTop + local tTopBottom, tLeftRight + if pPointerTop then + put "top" into tTopBottom + else + put "bottom" into tTopBottom + end if + + if pPointerLeft then + put "left" into tLeftRight + else + put "right" into tLeftRight + end if + + if pPointerVertical then + return tTopBottom & "-" & tLeftRight + else + return tLeftRight & "-" & tTopBottom + end if +end revTutorialPointerPositionCompute private command revTutorialDecideSide pNear, pFar, @rNear, @rCanFit # If they are both zero then we can't fit @@ -1239,9 +1442,38 @@ private command revTutorialTryToFitWithPointer pContentWidth, pContentHeight, pS put true into rCanFit end revTutorialTryToFitWithPointer -private command revTutorialEnsureOnscreen pContentWidth, pContentHeight, pScreenRect, pHighlightRect, @xPointerVertical, @rPointerLeft, @rPointerTop, @rCanFit +private function revTutorialPointerComputeForTopLeft pWidth, pHeight, pTargetRect, pStackTopLeft + # Determine where the target rect is wrt the new stack position + local tStackLoc, tTargetLoc + put item 1 of pStackTopLeft + pWidth / 2, \ + item 2 of pStackTopLeft + pHeight / 2 into tStackLoc + put (item 1 of pTargetRect + item 3 of pTargetRect) / 2, \ + (item 2 of pTargetRect + item 4 of pTargetRect) / 2 into tTargetLoc + + local tLeftOffset, tTopOffset + put item 1 of tTargetLoc - item 1 of tStackLoc into tLeftOffset + put item 2 of tTargetLoc - item 2 of tStackLoc into tTopOffset + + local tPointerVertical, tPointerLeft, tPointerTop + if tLeftOffset <= 0 then + put true into tPointerLeft + end if + if tTopOffset <= 0 then + put true into tPointerTop + end if + put abs(tTopOffset) >= abs(tLeftOffset) into tPointerVertical + + local tPointer + put revTutorialPointerPositionCompute(tPointerVertical, tPointerLeft, tPointerTop) \ + into tPointer["position"] + revTutorialPointerComputeTarget pWidth, pHeight, pTargetRect, pStackTopLeft, tPointer + put "override" into tPointer["style"] + return tPointer +end revTutorialPointerComputeForTopLeft + +private function revTutorialPointerCompute pContentWidth, pContentHeight, pScreenRect, pHighlightRect, pPointerVertical local tPointerVertical, tPointerLeft, tPointerTop, tCanFit - put xPointerVertical into tPointerVertical + put pPointerVertical into tPointerVertical # Try with the pre-existing preference of pointer vertical / horizontal revTutorialTryToFitWithPointer pContentWidth, pContentHeight, pScreenRect, pHighlightRect, tPointerVertical, tPointerLeft, tPointerTop, tCanFit @@ -1252,11 +1484,89 @@ private command revTutorialEnsureOnscreen pContentWidth, pContentHeight, pScreen revTutorialTryToFitWithPointer pContentWidth, pContentHeight, pScreenRect, pHighlightRect, tPointerVertical, tPointerLeft, tPointerTop, tCanFit end if - put tPointerVertical into xPointerVertical - put tPointerLeft into rPointerLeft - put tPointerTop into rPointerTop - put tCanFit into rCanFit -end revTutorialEnsureOnscreen + if not tCanFit then + return empty + end if + local tPointer + put revTutorialPointerPositionCompute(tPointerVertical, tPointerLeft, tPointerTop) \ + into tPointer["position"] + put "original" into tPointer["style"] + return tPointer +end revTutorialPointerCompute + +private command revTutorialPointerStackPositionOriginal pContentWidth, pContentHeight, pHighlightRect, pPointer, @rStackLeft, @rStackTop + local tLeft, tTop, tRight, tBottom + put item 1 of pHighlightRect into tLeft + put item 2 of pHighlightRect into tTop + put item 3 of pHighlightRect into tRight + put item 4 of pHighlightRect into tBottom + + local tSide + put revTutorialPointerSide(pPointer) into tSide + + local tSource + put revTutorialPointerSource(pPointer, pContentWidth, pContentHeight) into tSource + + local tStackTop, tStackLeft, tEffectiveTop, tEffectiveLeft + switch tSide + case "top" + put tBottom + kPointerPadding into tStackTop + put (tRight + tLeft) / 2 - item 1 of tSource into tStackLeft + break + case "bottom" + put tTop - pContentHeight - kPointerPadding into tStackTop + put (tRight + tLeft) / 2 - item 1 of tSource into tStackLeft + break + case "left" + put tRight + kPointerPadding into tStackLeft + put (tTop + tBottom) / 2 - item 2 of tSource into tStackTop + break + case "right" + put tLeft - pContentWidth - kPointerPadding into tStackLeft + put (tTop + tBottom) / 2 - item 2 of tSource into tStackTop + break + end switch + + put tStackLeft - revTutorialPointerLeftOverhang(pPointer) into tEffectiveLeft + put tStackTop - revTutorialPointerTopOverhang(pPointer) into tEffectiveTop + + revTutorialSetEffectiveTopLeft (tEffectiveLeft, tEffectiveTop) + put tStackTop into rStackTop + put tStackLeft into rStackLeft +end revTutorialPointerStackPositionOriginal + +private command revTutorialPointerStackPositionOverride pContentWidth, pContentHeight, pHighlightRect, pPointer, @rStackLeft, @rStackTop + local tTopLeftOverride + put pPointer["stacktopleft"] into tTopLeftOverride + + put item 1 of tTopLeftOverride - revTutorialPointerLeftOverhang(pPointer) into rStackLeft + put item 2 of tTopLeftOverride - revTutorialPointerTopOverhang(pPointer) into rStackTop + + revTutorialSetEffectiveTopLeft tTopLeftOverride +end revTutorialPointerStackPositionOverride + +private command revTutorialPointerStackPosition pContentWidth, pContentHeight, pHighlightRect, pPointer, @rStackLeft, @rStackTop + if pPointer["style"] is "original" then + revTutorialPointerStackPositionOriginal pContentWidth, pContentHeight, pHighlightRect, pPointer, rStackLeft, rStackTop + else + revTutorialPointerStackPositionOverride pContentWidth, pContentHeight, pHighlightRect, pPointer, rStackLeft, rStackTop + end if +end revTutorialPointerStackPosition + +command revTutorialPointerStackSize pContentWidth, pContentHeight, pPointer, @rWidth, @rHeight + local tWidth, tHeight + put pContentWidth into tWidth + put pContentHeight into tHeight + + add revTutorialPointerLeftOverhang(pPointer) to tWidth + add revTutorialPointerRightOverhang(pPointer, pContentWidth) to tWidth + add revTutorialPointerTopOverhang(pPointer) to tHeight + add revTutorialPointerBottomOverhang(pPointer, pContentHeight) to tHeight + + put tWidth into rWidth + put tHeight into rHeight +end revTutorialPointerStackSize + ############################################################################## # # MAIN FUNCTIONALITY @@ -1313,6 +1623,10 @@ on revInitialiseTutorial delete button "Got It" of stack "revTutorial" end if + if there is a button "Do It For Me" of stack "revTutorial" then + delete button "Do It For Me" of stack "revTutorial" + end if + if there is a button "Copy Script" of stack "revTutorial" then delete button "Copy Script" of stack "revTutorial" end if @@ -1330,10 +1644,15 @@ on revInitialiseTutorial end if set the windowShape of stack "revTutorial" to empty + set the decorations of stack "revTutorial" to empty set the textStyle of stack "revTutorial" to "bold" set the textColor of stack "revTutorial" to "white" - set the textsize of stack "revTutorial" to 15 + if the platform is "win32" then + set the textsize of stack "revTutorial" to 18 + else + set the textsize of stack "revTutorial" to 16 + end if -- Create fields set the lockText of the templateField to true @@ -1352,6 +1671,8 @@ on revInitialiseTutorial create field "Script" set the dontWrap of it to true + set the opaque of it to true + set the backcolor of it to "white" if revIDEBrowserWidgetUnavailable() then create field "Url" @@ -1383,6 +1704,10 @@ on revInitialiseTutorial set the backColor of it to revTutorialMessageAltColor() set the label of it to "Copy Script To Editor" + create button "Do It For Me" + set the backColor of it to revTutorialMessageAltColor() + set the label of it to "Do It For Me" + reset the templateButton create image "Image" @@ -1403,13 +1728,24 @@ on revInitialiseTutorial revIDESetPreference "cToolbarIcons", true revIDESetPreference "idePropertyInspector_labels", false + -- Ensure we know when stack names change + revIDESubscribe "ideNameChanged" + unlock screen end revInitialiseTutorial +on ideNameChanged pOldName, pNewName, pTarget + if word 1 of pTarget is "stack" then + -- Update all our long IDs if we're tracking this stack + revTutorialStackNameChanged pOldName, pNewName + end if +end ideNameChanged + on revTutorialInitialiseStep put false into sWaiting put false into sIsInterlude put 0 into sActionNumber + revTutorialSetTopLeftOverride false end revTutorialInitialiseStep on revFinaliseTutorial @@ -1533,14 +1869,22 @@ on revTutorialStartAtStep pCourse, pTutorial, pLesson, pLocation, pStepName revTutorialStartWithState pStepName, sTaggedObjects end revTutorialStartAtStep -on revTutorialSkip - local tTutorialInfo - put revIDETutorialInProgress() into tTutorialInfo - - if tTutorialInfo is empty then - exit revTutorialSkip +command revTutorialGoBackToSelectStep + // At the moment it should be a safe assumption that the relevant + // 'select' step is the previous one + local tPreviousStep + put revTutorialPreviousStep() into tPreviousStep + if sSteps[tPreviousStep]["actions"]["wait"]["wait condition"] is "state" and \ + sSteps[tPreviousStep]["actions"]["wait"]["state"] is "selected" then + revTutorialGoBackToPreviousStep end if - +end revTutorialGoBackToSelectStep + +command revTutorialSkipCurrentStep + revTutorialSkipStep sStepName +end revTutorialSkipCurrentStep + +on revTutorialSkip # Calculate the skip point local tSkipPoint put sStepName into tSkipPoint @@ -1548,18 +1892,27 @@ on revTutorialSkip put sSteps[tSkipPoint]["actions"]["go"]["step"] into tSkipPoint end repeat - local tRunUntil - put sSteps[tSkipPoint]["actions"]["go"]["step"] into tRunUntil + revTutorialSkipStep tSkipPoint +end revTutorialSkip + +command revTutorialSkipStep pStep + local tTutorialInfo + put revIDETutorialInProgress() into tTutorialInfo + + if tTutorialInfo is empty then + exit revTutorialSkipStep + end if # Run from the current step to the next skip point revTutorialRunTutorial tTutorialInfo["course"], tTutorialInfo["tutorial"], \ - tTutorialInfo["lesson"], tTutorialInfo["location"], sStepName, tRunUntil + tTutorialInfo["lesson"], tTutorialInfo["location"], sStepName, pStep + revTutorialInitialiseStep # Due to how the run loop works, we need to continue from the step # *prior* to the next executed step - revTutorialContinueFromStep tSkipPoint -end revTutorialSkip + revTutorialContinueFromStep pStep +end revTutorialSkipStep on revTutorialStop revTutorialClearHighlights @@ -1600,11 +1953,15 @@ function revTutorialDonePercentage return 100 * (sStepNum - 1) / sNumSteps end revTutorialDonePercentage +private command revTutorialShow + show stack "revTutorial" +end revTutorialShow + on revTutorialPrologue if sSteps["prologue"] is not empty then revTutorialDoInterlude false revTutorialSetText "prologue" - show stack "revTutorial" + revTutorialShow else send "revTutorialContinue" to stack "revTutorial" in 0 millisecs end if @@ -1612,9 +1969,10 @@ end revTutorialPrologue on revTutorialEpilogue if sSteps["epilogue"] is not empty then + revTutorialClearHighlights revTutorialDoInterlude true revTutorialSetText "epilogue" - show stack "revTutorial" + revTutorialShow else revIDEStopTutorial end if @@ -1642,7 +2000,7 @@ on revTutorialClearAllPalettes end repeat end revTutorialClearAllPalettes -on revTutorialContinue +on revTutorialContinue pBack repeat forever if sWaiting then exit repeat @@ -1654,7 +2012,7 @@ on revTutorialContinue else if sSteps[sStepName]["actions"]["go"] is empty then revTutorialFinish exit repeat - else + else if not pBack then // Otherwise we're here after a wait, so go to the next step revTutorialExecuteAction sSteps[sStepName]["actions"]["go"] end if @@ -1670,7 +2028,7 @@ on revTutorialContinue if sSteps[sStepName]["actions"]["wait"] is not empty then # Add guide in case wait is 'fits guide' revTutorialExecuteAction sSteps[sStepName]["actions"]["add guide"] - if revTutorialCheckWaitCondition(sSteps[sStepName]["actions"]["wait"]) then + if revTutorialCheckWaitCondition(sSteps[sStepName]["actions"]["wait"], true) then put false into sDontShow next repeat end if @@ -1695,7 +2053,7 @@ on revTutorialContinue revTutorialExecuteAction sSteps[sStepName]["actions"]["highlight"] unlock screen - show stack "revTutorial" + revTutorialShow -- Work around windowShape issue on Windows set the backcolor of this card of stack "revTutorial" to the backcolor of this card of stack "revTutorial" @@ -1747,25 +2105,46 @@ on revTutorialExecuteAction pActionData revTutorialDoCreateSet pActionData["objects"], pActionData["tag"] break case "load" - revTutorialDoLoad pActionData["lesson"] + revTutorialDoLoad pActionData break end switch end revTutorialExecuteAction -on revTutorialDoLoad pLesson +command revTutorialDoLoadLesson pLesson # Check to see if the stack from the specified lesson is complete local tTutorialInfo put revIDETutorialInProgress() into tTutorialInfo # Simply run the lesson that is to be loaded revTutorialRunTutorial tTutorialInfo["course"], tTutorialInfo["tutorial"], pLesson, tTutorialInfo["location"] +end revTutorialDoLoadLesson + +command revTutorialDoLoadStackResource pFile + local tFileName, tStackName + put revIDETutorialInternalResource(pFile) into tFileName + lock screen + lock messages + go stack tFileName + put the name of stack tFileName into tStackName + set the filename of stack tStackName to empty + revIDETutorialUpdateAndRemoveTags tStackName, sTaggedObjects + unlock messages + unlock screen +end revTutorialDoLoadStackResource + +on revTutorialDoLoad pActionData + if pActionData["lesson"] is not empty then + revTutorialDoLoadLesson pActionData["lesson"] + else if pActionData["stack"] is not empty then + revTutorialDoLoadStackResource pActionData["stack"] + end if end revTutorialDoLoad -on revTutorialSetText pStep - revTutorialConfigureMessage sSteps[pStep] +on revTutorialSetText pStep, pTopLeft + revTutorialConfigureMessage sSteps[pStep], pTopLeft end revTutorialSetText -on revTutorialConfigureMessage pData +on revTutorialConfigureMessage pData, pTopLeft local tWidthOverride put kMessageWidth into tWidthOverride set the width of field "Message" of stack "revTutorial" to kMessageWidth @@ -1785,7 +2164,7 @@ on revTutorialConfigureMessage pData local tImageFile if pData["image"] is not empty then local tImageWidth - put revIDETutorialInternalResource(pData["image"]) into tImageFile + put revTutorialImageForScreenSize(pData["image"]) into tImageFile set the filename of image "Image" of stack "revTutorial" to tImageFile put the formattedWidth of image "Image" of stack "revTutorial" + 2 * kMargin into tImageWidth put max(tWidthOverride, tImageWidth) into tWidthOverride @@ -1820,9 +2199,26 @@ on revTutorialConfigureMessage pData end if end if - revTutorialPositionStack "", "", tWidthOverride, false + revTutorialPositionStackForHighlight pTopLeft, tWidthOverride end revTutorialConfigureMessage +function revTutorialImageForScreenSize pImage + local tScreen, tScreenRect + put the screen of stack "revTutorial" into tScreen + put line tScreen of the the screenrects into tScreenRect + if item 4 of tScreenRect - item 2 of tScreenRect <= 1080 then + local tSmallImage, tFile + put pImage into tSmallImage + set the itemdelimiter to "." + put "_small" after item -2 of tSmallImage + put revIDETutorialInternalResource(tSmallImage) into tFile + if there is a file tFile then + return tFile + end if + end if + return revIDETutorialInternalResource(pImage) +end revTutorialImageForScreenSize + function revTutorialScriptRetry pCurrent local tText put "Your script is not quite right. You have:" & return & return after tText @@ -1880,6 +2276,9 @@ on revTutorialEnsureState pStep case "palette for object" revTutorialEnsurePaletteForObject tHighlightDataA["palette"], tHighlightDataA["object"] break + case "script line" + revTutorialEnsurePaletteForObject "script editor", tHighlightDataA["object"] + break case "item of palette" case "palette" revTutorialEnsurePalette tHighlightDataA["palette"] @@ -1892,15 +2291,40 @@ on revTutorialSetContextualStepData pStepDataA put pStepDataA["file"] into sStepContextA["file"] put pStepDataA["value"] into sStepContextA["value"] put pStepDataA["image"] into sStepContextA["image"] + if pStepDataA["actions"]["wait"]["wait condition"] is "pops up" then + put false into sStepContextA["can skip"] + else + put true into sStepContextA["can skip"] + end if end revTutorialSetContextualStepData +function revTutorialCanSkipStep + return sStepContextA["can skip"] +end revTutorialCanSkipStep + ############################################################################## # # ACTION IMPLEMENTATIONS # ############################################################################## -on revTutorialDoGoToStep pStep +local sPreviousStep +private function revTutorialPreviousStep + return sPreviousStep +end revTutorialPreviousStep + +command revTutorialGoBackToPreviousStep + if sPreviousStep is empty then + exit revTutorialGoBackToPreviousStep + end if + revTutorialDoGoToStep sPreviousStep, true + send "revTutorialContinue true" to stack "revTutorial" in 0 millisecs +end revTutorialGoBackToPreviousStep + +on revTutorialDoGoToStep pStep, pBack + if not pBack then + put sStepName into sPreviousStep + end if revTutorialInitialiseStep revTutorialClearHighlights revTutorialClearGuides @@ -1946,7 +2370,7 @@ end revTutorialReturnFromInterlude on revTutorialDoWait pActionData put empty into sWait // Check to see if wait condition is immediately satisfied - if revTutorialCheckWaitCondition(pActionData) then + if revTutorialCheckWaitCondition(pActionData, true) then exit revTutorialDoWait end if @@ -2000,7 +2424,7 @@ on revTutorialDoWait pActionData end switch end revTutorialDoWait -function revTutorialCheckWaitCondition pActionData +function revTutorialCheckWaitCondition pActionData, pBeforeDisplay # Deal with non-object wait conditions switch pActionData["wait condition"] case "there is a palette" @@ -2017,6 +2441,12 @@ function revTutorialCheckWaitCondition pActionData switch pActionData["wait condition"] case "property" + # If we are waiting for the property to be 'changed' then don't try and + # shortcut the step + if pBeforeDisplay and pActionData["is not"] then + break + end if + local tValue # If the step specified a value then we want to compare with this instead # of the string "value" @@ -2026,7 +2456,7 @@ function revTutorialCheckWaitCondition pActionData put pActionData["value"] into tValue end if - if revTutorialObjectPropertyIsValue(tObject, pActionData["property"], tValue) then + if revTutorialObjectPropertyIsValue(tObject, pActionData["property"], tValue, pActionData["is not"]) then return true end if break @@ -2049,21 +2479,32 @@ function revTutorialCheckWaitCondition pActionData end if break case "scripted" - # If the script hasn't changed then don't do anything. - if revTutorialScriptIs(the script of tObject, sWait["current script"]) then + # Don't try and shortcut this step + if pBeforeDisplay then break end if - if revTutorialObjectPropertyIsValue(tObject, "script", pActionData["script"]) then + + # This code path is triggered by any propertyChanged message, + # so if the script hasn't changed then don't do anything. + local tScript + put the script of tObject into tScript + revTutorialCompareScript tScript, sWait["current script"] + if the result is empty then + break + end if + local tMistake + revTutorialCompareScript tScript, pActionData["script"] + put the result into tMistake + if tMistake is empty then return true - else if sWait["current script"] is not empty then - add 1 to sWait["incorrect attempts"] - put the script of tObject into sWait["current script"] - # Show the current script and the target script in the tip stack - local tData - put revTutorialScriptRetry(sWait["current script"]) into tData["text"] - put pActionData["script"] into tData["script"] - revTutorialConfigureMessage tData end if + put tScript into sWait["current script"] + add 1 to sWait["incorrect attempts"] + # Show the current script and the target script in the tip stack + local tData + put revTutorialScriptRetry(tMistake) into tData["text"] + put pActionData["script"] into tData["script"] + revTutorialConfigureMessage tData, revTutorialGetEffectiveTopLeft() break end switch break @@ -2085,6 +2526,7 @@ on revTutorialWaitUntilObjectIsScripted pTaggedObject revTutorialSetSEPreference "explicitVariables", false revIDESubscribe "idePropertyChanged", tObjID + revIDESubscribe "ideScriptEdited" end revTutorialWaitUntilObjectIsScripted on revTutorialWaitUntilObjectIsClicked @@ -2131,6 +2573,7 @@ on revTutorialWaitUntilThereIsAPaletteForObject pPalette revIDEHighlightPaletteObject "menubar", "standard" revIDESubscribe "ideEditScript" end if + revIDESubscribe "ideSelectedObjectChanged" end revTutorialWaitUntilThereIsAPaletteForObject on revTutorialWaitUntilTheToolIs @@ -2140,6 +2583,9 @@ end revTutorialWaitUntilTheToolIs on revTutorialWaitUntilObjectPropertyHasValue pTaggedObject local tObjID put revTutorialResolveObjectToLongID(pTaggedObject) into tObjID + if sWait["is not"] then + put the sWait["property"] of tObjID into sWait["value"] + end if revIDESubscribe "idePropertyChanged", tObjID end revTutorialWaitUntilObjectPropertyHasValue @@ -2244,7 +2690,7 @@ on revTutorialHighlightPalette pPaletteName put pPaletteName into sHighlight["stack"] revIDESubscribe "ideStackMoved", the long id of stack revIDEPaletteToStackName(pPaletteName) - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightPalette function revTutorialPaletteForObject pPaletteName, pObject @@ -2284,7 +2730,7 @@ on revTutorialHighlightObjectByID pObjID end if revIDESubscribe "ideStackMoved", revIDEStackOfObject(pObjID) revIDESubscribe "idePropertyChanged", pObjID - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightObjectByID on revTutorialHighlightItemOfPaletteForObject pPalette, pItem, pObject @@ -2309,7 +2755,7 @@ on revTutorialHighlightItemOfStack pStackID, pItem put pItem into sHighlight["object"] put "object" into sHighlight["type"] revIDESubscribe "ideStackMoved", pStackID - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightItemOfStack @@ -2330,7 +2776,7 @@ on revTutorialHighlightTool pTool revIDESubscribe "ideStackMoved", the long id of stack revIDEPaletteToStackName("tools") put "tool" into sHighlight["type"] put pTool into sHighlight["tool"] - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightTool function revTutorialHighlightedPalette pPalette @@ -2370,7 +2816,7 @@ on revTutorialHighlightInspector pSection, pGroup put "property" into sHighlight["type"] put pGroup into sHighlight["group"] put sLastObjects["inspector"] into sHighlight["object"] - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() put false into sDismissA["inspector"] end revTutorialHighlightInspector @@ -2382,7 +2828,7 @@ on revTutorialHighlightMenuItem pMenu, pItem revIDESubscribe "ideStackMoved", the long id of stack revIDEPaletteToStackName("menubar") put "menu" into sHighlight["type"] put pMenu into sHighlight["menu"] - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightMenuItem on revTutorialHighlightToolbarItem pItem @@ -2390,7 +2836,7 @@ on revTutorialHighlightToolbarItem pItem revIDESubscribe "ideStackMoved", the long id of stack revIDEPaletteToStackName("menubar") put "toolbar" into sHighlight["type"] put pItem into sHighlight["item"] - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightToolbarItem on disableToolsPalette @@ -2453,7 +2899,7 @@ on revTutorialHighlightGuide pGuide revIDESubscribe "ideStackMoved", revIDEStackOfObject(sGuides[pGuide]) put "guide" into sHighlight["type"] put pGuide into sHighlight["guide"] - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end revTutorialHighlightGuide on revTutorialClearGuides @@ -2493,6 +2939,20 @@ end revTutorialReShow on ideActiveStacksChanged revTutorialReShow + + local tObject + put revIDESelectedObjects() into tObject + if sWait["wait condition"] is "there is a palette for object" then + -- If the object became deselected, go back a step + if not revTutorialObjectIsTaggedObject(tObject, sWait["object"]) then + revTutorialGoBackToSelectStep + end if + else if sWait["wait condition"] is "state" and sWait["state"] is "selected" then + if revTutorialObjectIsTaggedObject(tObject, sWait["object"]) then + revIDEUnsubscribe "ideSelectedObjectChanged" + revTutorialWaitConditionSatisfied + end if + end if end ideActiveStacksChanged on ideCloseStackRequest pStack @@ -2625,7 +3085,7 @@ end ideNewCard on idePropertyChanged pObject # If a highlighted object moved then reposition the tutorial step pointer if not pObject begins with "stack" and revTutorialObjectIsHighlighted(pObject) then - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end if if revTutorialObjectIsTaggedObject(pObject, sWait["object"]) then @@ -2642,12 +3102,58 @@ on idePropertyChanged pObject end if end idePropertyChanged +local sScriptCheck +on revTutorialCheckScript pScript, pObject + if revTutorialObjectIsTaggedObject(pObject, sWait["object"]) then + if sWait["wait condition"] is "state" and \ + sWait["state"] is "scripted" then + revTutorialCompareScript pScript, sWait["script"] + lock screen + if the result is empty and sWait["correct script"] is not true then + -- If the currently typed script is correct, then + -- remind about clicking Apply + -- Remember the chosen location + put revTutorialGetEffectiveTopLeft() into sScriptCheck["topleft"] + put true into sScriptCheck["correct script"] + put "Apply" into sHighlight["object"] + put "object" into sHighlight["type"] + local tData + put "Click 'Apply' to apply the script" into tData["text"] + revTutorialConfigureMessage tData + else if sScriptCheck["correct script"] is true then + -- Otherwise, the script has been changed from the correct one + put false into sScriptCheck["correct script"] + -- Reset the highlight + put "stack" into sHighlight["type"] + -- Reset the text + revTutorialSetText sStepName, sScriptCheck["topleft"] + end if + unlock screen + end if + end if +end revTutorialCheckScript + +local sCheckScriptMsg +constant kCheckBufferMS = 800 +on ideScriptEdited pScript, pObject + -- In order to mitigate against forgetting to press the + -- apply button, we subscribe to ideScriptEdited and check + -- to see if the script entered is correct. However, we + -- don't want to interrupt the flow of typing, so add a + -- buffer + if sCheckScriptMsg is not empty then + cancel sCheckScriptMsg + end if + send "revTutorialCheckScript pScript, pObject" to me in kCheckBufferMS millisecs + put the result into sCheckScriptMsg +end ideScriptEdited + on ideStackMoved pStack local tStack put revIDEStackOfObject(pStack) into tStack # If the highlighted stack is moved, then reposition the tutorial step pointer if revTutorialObjectIsHighlighted(tStack) then - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end if end ideStackMoved @@ -2657,7 +3163,7 @@ on ideResumeStack pStack if not revTutorialObjectIsHighlighted(tStack) then # If the target stack is not highlighted then react accordingly else - revTutorialPositionStackForHighlight + revTutorialPositionStackForHighlight revTutorialTopLeftOverride() end if end ideResumeStack @@ -2681,6 +3187,8 @@ on mouseDown put the long id of the target into tObject if word 1 of tObject is "button" then revTutorialSetPressedState tObject + else + revTutorialDragWindow end if end mouseDown @@ -2690,6 +3198,8 @@ on mouseRelease if word 1 of tObject is "button" then revTutorialSetUnpressedState tObject end if + + revTutorialDragStop end mouseRelease on mouseUp pWhich @@ -2706,11 +3216,75 @@ on mouseUp pWhich revTutorialCopyScriptToEditor end if + if tObject is the long id of button "Do It For Me" of stack "revTutorial" then + revTutorialSkipCurrentStep + end if + if word 1 of tObject is "button" then revTutorialSetUnpressedState tObject end if + + revTutorialDragStop end mouseUp +on mouseMove + if revTutorialIsDraggingWindow() then + revTutorialTrackToMouse + end if +end mouseMove + +local sMouseLoc, sMoved +command revTutorialDragWindow + if sMouseLoc is not empty or the mouse is not "down" then + exit revTutorialDragWindow + end if + put the screenmouseloc into sMouseLoc +end revTutorialDragWindow + +command revTutorialDragStart + lock screen + lock messages + local tTopLeft + put revTutorialGetEffectiveTopLeft() into tTopLeft + revTutorialOverrideLocation tTopLeft + unlock messages + unlock screen + + put true into sMoved +end revTutorialDragStart + +command revTutorialDragStop + lock screen + lock messages + put empty into sMouseLoc + if sMoved then + revTutorialOverrideLocation the topleft of stack "revTutorial" + end if + put false into sMoved + unlock messages + unlock screen +end revTutorialDragStop + +private function revTutorialIsDraggingWindow + return sMouseLoc is not empty +end revTutorialIsDraggingWindow + +private command revTutorialTrackToMouse + if not sMoved then + revTutorialDragStart + end if + local tNewLoc, tNewTopLeft + put the screenmouseloc into tNewLoc + + local tTopLeft + put revTutorialGetEffectiveTopLeft() into tTopLeft + repeat with x = 1 to 2 + put item x of tTopLeft + (item x of tNewLoc - item x of sMouseLoc) \ + into item x of tNewTopLeft + end repeat + set the topleft of stack "revTutorial" to tNewTopLeft +end revTutorialTrackToMouse + on ideMouseDoubleUp pWhich, pTarget if sWait["wait condition"] is "state" and sWait["state"] is "double clicked" then if revTutorialObjectIsTaggedObject(pTarget, sWait["object"]) then @@ -2720,12 +3294,18 @@ on ideMouseDoubleUp pWhich, pTarget end ideMouseDoubleUp on ideSelectedObjectChanged + local tObject + put revIDESelectedObjects() into tObject if sWait["wait condition"] is "state" and sWait["state"] is "selected" then - local tObject - put revIDESelectedObjects() into tObject if revTutorialObjectIsTaggedObject(tObject, sWait["object"]) then + revIDEUnsubscribe "ideSelectedObjectChanged" revTutorialWaitConditionSatisfied end if + else if sWait["wait condition"] is "there is a palette for object" then + -- If the object became deselected, go back a step + if not revTutorialObjectIsTaggedObject(tObject, sWait["object"]) then + revTutorialGoBackToSelectStep + end if end if end ideSelectedObjectChanged @@ -2733,6 +3313,7 @@ on ideInspectObjects pObjects if sWait["wait condition"] is "there is a palette for object" and sWait["palette"] is "inspector" then if revTutorialObjectIsTaggedObject(pObjects, sWait["object"]) then revIDEUnsubscribe "ideInspectObjects" + revIDEUnsubscribe "ideSelectedObjectChanged" put pObjects into sLastObjects[sWait["palette"]] revTutorialWaitConditionSatisfied end if @@ -2743,6 +3324,7 @@ on ideEditScript pObject if sWait["wait condition"] is "there is a palette for object" and sWait["palette"] is "script editor" then if revTutorialObjectIsTaggedObject(the long id of pObject, sWait["object"]) then revIDEUnsubscribe "ideEditScript" + revIDEUnsubscribe "ideSelectedObjectChanged" put pObject into sLastObjects[sWait["palette"]] revTutorialWaitConditionSatisfied end if @@ -2853,34 +3435,41 @@ function revTutorialObjectIsHighlighted pObject return false end revTutorialObjectIsHighlighted -on revTutorialPositionStackForHighlight +on revTutorialPositionStackForHighlight pTopLeft, pWidthOverride lock screen switch sHighlight["type"] case "guide" - revTutorialPositionStack "", sGuides[sHighlight["guide"]] + revTutorialPositionStack "", sGuides[sHighlight["guide"]], pWidthOverride, "", pTopLeft break case "property" - revTutorialPositionStack "inspector", sHighlight + revTutorialPositionStack "inspector", sHighlight, pWidthOverride, "", pTopLeft break case "menu" - revTutorialPositionStack "menubar", sHighlight["menu"] + revTutorialPositionStack "menubar", sHighlight["menu"], pWidthOverride, "", pTopLeft break case "toolbar" - revTutorialPositionStack "menubar", sHighlight["item"] + revTutorialPositionStack "menubar", sHighlight["item"], pWidthOverride, "", pTopLeft break case "tool" - revTutorialPositionStack "tools", sHighlight["tool"] + revTutorialPositionStack "tools", sHighlight["tool"], pWidthOverride, "", pTopLeft break case "object" - revTutorialPositionStack sHighlight["stack"], sHighlight["object"], "", sHighlight["line"] is not empty + revTutorialPositionStack sHighlight["stack"], sHighlight["object"], pWidthOverride, sHighlight["line"] is not empty, pTopLeft break case "stack" - revTutorialPositionStack sHighlight["stack"], "" + revTutorialPositionStack sHighlight["stack"], "", pWidthOverride, "", pTopLeft + break + default + revTutorialPositionStack "", "", pWidthOverride, "", pTopLeft break end switch unlock screen end revTutorialPositionStackForHighlight +on revTutorialOverrideLocation pTopLeft + revTutorialPositionStackForHighlight pTopLeft +end revTutorialOverrideLocation + on revTutorialClearHighlights switch sHighlight["type"] case "tool" @@ -2936,6 +3525,30 @@ function revTutorialReparentChild pObject return the long id of pObject end revTutorialReparentChild +command revTutorialStackNameChanged pOldName, pNewName + -- Update the tagged objects + repeat for each key tType in sTaggedObjects + repeat for each key tTag in sTaggedObjects[tType] + replace "stack" && quote & pOldName & quote \ + with "stack" && quote & pNewName & quote \ + in sTaggedObjects[tType][tTag] + end repeat + end repeat + + -- Update any wait state if we are waiting. Now that the tagged objects + -- are updated just call DoWait again with the current wait state.The + -- type/tag in the sWait array will resolve to the updated long ID + if sWait is not empty then + -- if new condition is immediately satisified (i.e. if we are waiting for a + -- stack name change) then sWaiting will still be false after revTutorialDoWait + put false into sWaiting + revTutorialDoWait sWait + if not sWaiting then + revTutorialWaitConditionSatisfied + end if + end if +end revTutorialStackNameChanged + # Take a tutorial tagged object (an array with 'type' and 'tag' keys) # and return the corresponding long ID (or list of long IDs for 'set' types) function revTutorialResolveObjectToLongID pTaggedObject, pUpdate @@ -3004,22 +3617,23 @@ function revTutorialThereIsAPalette pPalette return false end revTutorialThereIsAPalette -function revTutorialObjectPropertyIsValue pObjectIDs, pProperty, pValue +function revTutorialObjectPropertyIsValue pObjectIDs, pProperty, pValue, pIsNot repeat for each line tObject in pObjectIDs if pProperty ends with "color" then - if revTutorialColorIs(the pProperty of tObject, pValue) is false then + if revTutorialColorIs(the pProperty of tObject, pValue) is pIsNot then return false end if else if pProperty is "script" then - if revTutorialScriptIs(the script of tObject, pValue) is false then + revTutorialCompareScript the script of tObject, pValue + if (the result is empty) is pIsNot then return false end if else if pProperty is "name" then - if the short name of tObject is not pValue then + if (the short name of tObject is pValue) is pIsNot then return false end if else - if the pProperty of tObject is not pValue then + if (the pProperty of tObject is pValue) is pIsNot then return false end if end if @@ -3072,19 +3686,61 @@ on revTutorialSnapObjectToGuide pObject, pGuide unlock screen end revTutorialSnapObjectToGuide +private function revTutorialGetMistake pObjScript, pTokenNum, pReadToken, pTargetToken + lock messages + local tDefaultStack + put the defaultStack into tDefaultStack + set the defaultStack to "revTutorial" + create invisible field "script_tester" + put pObjScript into field "script_tester" + + local tCharIndex, tLineIndex, tLineChars + put the lineIndex of token pTokenNum of field "script_tester" into tLineIndex + put the charIndex of token pTokenNum of field "script_tester" into tCharIndex + put the number of chars in line 0 to tLineIndex - 1 \ + of field "script_tester" into tLineChars + subtract tLineChars from tCharIndex + + local tMistake + if pTargetToken is not empty then + put merge(quote & "[[pReadToken]]" & quote && \ + "instead of" && quote & "[[pTargetToken]]" & quote && \ + "at char [[tCharIndex]] of line [[tLineIndex]]") into tMistake + else + put merge("Unexpected additional script" && \ + quote & "[[pReadToken]]" & quote && \ + "at char [[tCharIndex]] of line [[tLineIndex]]") into tMistake + end if + delete field "script_tester" + set the defaultStack to tDefaultStack + unlock messages + return tMistake +end revTutorialGetMistake + // In the future we might want to add a bit more "approximity" to this. -function revTutorialScriptIs pObjScript, pTargetScript - local tObjTokens, tTargetTokens - repeat for each token tToken in pObjScript - put tToken & " " after tObjTokens +command revTutorialCompareScript pObjScript, pTargetScript + local tTokenNum, tMistake, tToken + repeat for each token tTargetToken in pTargetScript + add 1 to tTokenNum + put token tTokenNum of pObjScript into tToken + if tTargetToken is not tToken then + put revTutorialGetMistake(pObjScript, tTokenNum, tToken, tTargetToken) \ + into tMistake + exit repeat + end if end repeat - repeat for each token tToken in pTargetScript - put tToken & " " after tTargetTokens - end repeat + if tMistake is empty then + add 1 to tTokenNum + put token tTokenNum of pObjScript into tToken + if tToken is not empty then + put revTutorialGetMistake(pObjScript, tTokenNum, tToken, empty) \ + into tMistake + end if + end if - return tObjTokens is tTargetTokens -end revTutorialScriptIs + return tMistake +end revTutorialCompareScript constant kColorTolerance = 10 function revTutorialColorIs pColor, pTarget @@ -3141,6 +3797,7 @@ on revTutorialRunTutorial pCourse, pTutorial, pLesson, pLocation, pFromStep, pUn put pCourse into sRunningInfo["course"] put pTutorial into sRunningInfo["tutorial"] put pLesson into sRunningInfo["lesson"] + put pLocation into sRunningInfo["location"] if pFromStep is empty then put tData["first step"] into pFromStep @@ -3154,12 +3811,11 @@ on revTutorialRunSteps pSteps, pFromStep, pUntilStep local tStep, tStepNum put pFromStep into tStep repeat until tStep is empty + revTutorialSetContextualStepData pSteps[tStep] + revTutorialRunStep pSteps[tStep]["actions"] if tStep is pUntilStep then exit repeat end if - - revTutorialSetContextualStepData pSteps[tStep] - revTutorialRunStep pSteps[tStep]["actions"] put pSteps[tStep]["actions"]["go"]["step"] into tStep end repeat unlock screen @@ -3201,7 +3857,7 @@ on revTutorialRunAction pActionData break case "property" # Set the property of the objects - revTutorialSetPropertyOfObjects revTutorialResolveObjectToLongID(tWaitData["object"]), tWaitData["property"], tWaitData["value"] + revTutorialSetPropertyOfObjects revTutorialResolveObjectToLongID(tWaitData["object"]), tWaitData["property"], tWaitData["value"], tWaitData["is not"], tWaitData["default"] break case "fits" # Set the rect of the objects @@ -3216,11 +3872,22 @@ on revTutorialRunAction pActionData case "state" switch tWaitData["state"] case "scripted" - # Everything becomes extremely sad if we already have a tab open for this script - # and try to run a scripting step. So close the palette first. - revTutorialClearPalette "script editor" - # Set the script of the objects - revTutorialSetPropertyOfObjects revTutorialResolveObjectToLongID(tWaitData["object"]), "script", tWaitData["script"] + # See if the object has a script editor open + local tPalette, tObject + put revTutorialResolveObjectToLongID(tWaitData["object"]) into tObject + put revScriptEditor(tObject) into tPalette + if tPalette is not empty then + # If so, check the script. If correct, apply the script + if sScriptCheck["correct script"] then + dispatch "revSEApply" to stack tPalette with true + else + # Otherwise set the script + dispatch "revSESetScript" to stack tPalette with tWaitData["script"] + end if + else + # If there is no SE, just set the script of the objects directly + revTutorialSetPropertyOfObjects tObject, "script", tWaitData["script"] + end if break case "selected" put revTutorialResolveObjectToLongID(tWaitData["object"]) into sSelected @@ -3292,7 +3959,7 @@ on revTutorialCreateAndCaptureObjects pWaitData, pCaptureData, pHighlightData else if pHighlightData["tool"] is not empty then dispatch function "toolObjectName" to stack "revTools" with pHighlightData["tool"] - revIDECreateObject the result, sTaggedObjects["stack"][tCapture["target stack"]["tag"]], "0,0" + revIDECreateObject the result, sTaggedObjects["stack"][tCapture["target stack"]["tag"]] put the result into sTaggedObjects[tType][tCapture["tag"]] else if pHighlightData["item"][1] contains "Import" then # Deal with 'import' @@ -3340,12 +4007,16 @@ on revTutorialCreateAndCaptureObjects pWaitData, pCaptureData, pHighlightData end if end revTutorialCreateAndCaptureObjects -on revTutorialSetPropertyOfObjects pObjects, pProp, pValue +on revTutorialSetPropertyOfObjects pObjects, pProp, pValue, pIsNot, pDefault # If the step specified a value then we set this instead of the string "value" if pValue is "value" and sStepContextA["value"] is not empty then put sStepContextA["value"] into pValue end if + if pIsNot then + put pDefault into pValue + end if + if the environment begins with "development" then revIDESetPropertyOfObject pObjects, pProp, pValue else diff --git a/Toolset/palettes/welcome/revwelcome.livecodescript b/Toolset/palettes/welcome/revwelcome.livecodescript index e8a45e0eb6..bdd6b5f0d7 100644 --- a/Toolset/palettes/welcome/revwelcome.livecodescript +++ b/Toolset/palettes/welcome/revwelcome.livecodescript @@ -283,7 +283,7 @@ end mouseMove on mouseUp if the mouseloc is within the rect of button "close" then stackClose - if revIDEPrefGet("StartPageShow") is not "false" then + if revIDEGetPreference("cStartPageShow") is not "false" then revIDEOpenPalette "Start Center" end if else if the mouseloc is within the rect of graphic "nonprogrammer-hover" then diff --git a/Toolset/resources/communityplus/ideSkin/about-background.png b/Toolset/resources/communityplus/ideSkin/about-background.png new file mode 100644 index 0000000000..d5ef18095b Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/about-background.png differ diff --git a/Toolset/resources/communityplus/ideSkin/about-background@extra-high.png b/Toolset/resources/communityplus/ideSkin/about-background@extra-high.png new file mode 100644 index 0000000000..4e6691f95c Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/about-background@extra-high.png differ diff --git a/Toolset/resources/communityplus/ideSkin/activation-background.png b/Toolset/resources/communityplus/ideSkin/activation-background.png new file mode 100644 index 0000000000..1b347c0a3c Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/activation-background.png differ diff --git a/Toolset/resources/communityplus/ideSkin/activation-background@extra-high.png b/Toolset/resources/communityplus/ideSkin/activation-background@extra-high.png new file mode 100644 index 0000000000..30e51096c3 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/activation-background@extra-high.png differ diff --git a/Toolset/resources/communityplus/ideSkin/bubble.png b/Toolset/resources/communityplus/ideSkin/bubble.png new file mode 100644 index 0000000000..99d58b1bdb Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/bubble.png differ diff --git a/Toolset/resources/communityplus/ideSkin/logo.png b/Toolset/resources/communityplus/ideSkin/logo.png new file mode 100644 index 0000000000..22aa593633 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/logo.png differ diff --git a/Toolset/resources/communityplus/ideSkin/logo@extra-high.png b/Toolset/resources/communityplus/ideSkin/logo@extra-high.png new file mode 100644 index 0000000000..0b7130a766 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/logo@extra-high.png differ diff --git a/Toolset/resources/communityplus/ideSkin/resource-center-bottom.png b/Toolset/resources/communityplus/ideSkin/resource-center-bottom.png new file mode 100644 index 0000000000..0e1888220b Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/resource-center-bottom.png differ diff --git a/Toolset/resources/communityplus/ideSkin/resource-center-top.png b/Toolset/resources/communityplus/ideSkin/resource-center-top.png new file mode 100644 index 0000000000..647d6b018d Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/resource-center-top.png differ diff --git a/Toolset/resources/communityplus/ideSkin/resource-center-top@extra-high.png b/Toolset/resources/communityplus/ideSkin/resource-center-top@extra-high.png new file mode 100644 index 0000000000..3002d0e44e Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/resource-center-top@extra-high.png differ diff --git a/Toolset/resources/communityplus/ideSkin/revOnline-top.png b/Toolset/resources/communityplus/ideSkin/revOnline-top.png new file mode 100644 index 0000000000..a6ba28b561 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/revOnline-top.png differ diff --git a/Toolset/resources/communityplus/ideSkin/revOnline-top@extra-high.png b/Toolset/resources/communityplus/ideSkin/revOnline-top@extra-high.png new file mode 100644 index 0000000000..128108453c Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/revOnline-top@extra-high.png differ diff --git a/Toolset/resources/communityplus/ideSkin/splash.png b/Toolset/resources/communityplus/ideSkin/splash.png new file mode 100644 index 0000000000..7a58e72d10 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/splash.png differ diff --git a/Toolset/resources/communityplus/ideSkin/splash@extra-high.png b/Toolset/resources/communityplus/ideSkin/splash@extra-high.png new file mode 100644 index 0000000000..aa8a622848 Binary files /dev/null and b/Toolset/resources/communityplus/ideSkin/splash@extra-high.png differ diff --git a/Toolset/resources/supporting_files/colors/colorsToNames.txt b/Toolset/resources/supporting_files/colors/colorsToNames.txt deleted file mode 100644 index 6b3612ac52..0000000000 --- a/Toolset/resources/supporting_files/colors/colorsToNames.txt +++ /dev/null @@ -1,511 +0,0 @@ -/* This mapping comes from engine/src/rgb.cpp and should not be changed */ - -0,0,0,Black -0,0,128,Navy -0,0,139,DarkBlue -0,0,205,MediumBlue -0,0,255,Blue -0,100,0,DarkGreen -0,104,139,DeepSkyBlue4 -0,134,139,Turquoise4 -0,139,0,Green4 -0,139,69,SpringGreen4 -0,139,139,DarkCyan -0,154,205,DeepSkyBlue3 -0,178,238,DeepSkyBlue2 -0,191,255,DeepSkyBlue -0,197,205,Turquoise3 -0,205,0,Green3 -0,205,102,SpringGreen3 -0,229,238,Turquoise2 -0,238,0,Green2 -0,238,118,SpringGreen2 -0,245,255,Turquoise1 -0,250,154,MediumSpringGreen -0,255,0,Green -0,255,127,SpringGreen -0,255,255,Cyan -10,10,10,Gray4 -13,13,13,Gray5 -15,15,15,Gray6 -16,78,139,DodgerBlue4 -18,18,18,Gray7 -20,20,20,Gray8 -21,5,23,Transparent -21,27,84,MidnightBlue -21,27,126,Blue4 -21,40,199,Blue3 -21,49,126,RoyalBlue4 -21,49,236,Blue2 -21,53,255,Blue1 -21,137,255,DodgerBlue -24,116,205,DodgerBlue3 -28,134,238,DodgerBlue2 -30,144,255,DodgerBlue1 -32,178,170,LightSeaGreen -34,139,34,ForestGreen -37,5,23,Gray18 -37,56,60,DarkSlateGray -37,84,199,RoyalBlue3 -43,27,23,Gray21 -43,56,86,DarkSlateBlue -43,84,126,SteelBlue4 -43,96,222,RoyalBlue -43,101,236,RoyalBlue2 -46,139,87,SeaGreen -48,34,23,Gray23 -48,34,38,Gray24 -48,103,84,MediumSeaGreen -48,110,255,RoyalBlue1 -48,125,126,Cyan4 -50,205,50,LimeGreen -52,40,38,Gray25 -52,40,44,Gray26 -52,45,126,SlateBlue4 -52,114,53,MediumForestGreen -56,45,44,Gray27 -59,49,49,Gray28 -59,156,156,DarkTurquoise -59,185,255,DeepSkyBlue1 -62,53,53,Gray29 -64,224,208,Turquoise -65,56,57,Gray30 -65,56,60,Gray31 -65,98,126,SkyBlue4 -65,124,100,Aquamarine4 -67,124,23,Chartreuse4 -67,183,186,Aquamarine -67,205,128,SeaGreen3 -70,27,126,Purple4 -70,62,63,Gray32 -70,62,65,DimGray -70,130,180,SteelBlue -70,199,199,Cyan3 -72,138,199,SteelBlue3 -72,204,205,MediumTurquoise -74,65,23,DarkOliveGreen -74,67,68,Gray34 -76,70,70,Gray35 -76,120,126,CadetBlue4 -76,125,126,DarkSlateGray4 -78,72,72,Gray36 -78,124,65,PaleGreen4 -80,74,75,Gray37 -80,235,236,Cyan2 -84,78,79,Gray38 -86,80,81,Gray39 -86,109,126,LightSkyBlue4 -86,165,236,SteelBlue2 -87,134,147,CadetBlue -87,254,255,Cyan1 -92,179,255,SteelBlue1 -93,71,139,MediumPurple4 -94,251,110,SpringGreen1 -95,251,23,Green1 -100,96,96,Gray44 -100,109,126,LightSteelBlue4 -100,149,237,CornflowerBlue -100,233,134,SeaGreen2 -101,115,131,SlateGray -101,128,23,OliveDrab -101,158,199,SkyBlue3 -102,99,98,Gray45 -102,102,102,Gray40 -102,124,38,DarkOliveGreen4 -102,139,139,PaleTurquoise4 -102,152,255,SkyBlue -102,205,0,Chartreuse3 -102,205,170,MediumAquamarine -104,34,139,DarkOrchid4 -104,131,139,LightBlue4 -105,89,205,SlateBlue3 -105,96,236,SlateBlue2 -105,101,101,Gray46 -105,105,105,Gray41 -105,139,34,OliveDrab4 -105,139,105,DarkSeaGreen4 -106,40,126,MediumOrchid4 -106,90,205,SlateBlue -106,251,146,SeaGreen1 -107,107,107,Gray42 -108,45,199,Purple3 -108,123,139,SlateGray4 -109,105,104,Gray47 -109,123,141,LightSlateGray -110,106,107,Gray48 -110,110,110,Gray43 -113,125,125,LightCyan4 -114,110,109,Gray49 -114,143,206,LightSteelBlue -115,105,255,SlateBlue1 -115,106,255,LightSlateBlue -116,113,112,Gray50 -118,238,0,Chartreuse2 -118,238,198,Aquamarine2 -119,191,199,CadetBlue3 -120,116,115,Gray51 -120,199,199,DarkSlateGray3 -121,186,236,SkyBlue2 -121,216,103,PaleGreen -122,119,119,Gray52 -122,125,116,Honeydew4 -122,125,125,Azure4 -123,104,238,MediumSlateBlue -124,121,121,Gray53 -124,205,124,PaleGreen3 -124,252,0,LawnGreen -125,5,63,DeepPink4 -125,5,65,VioletRed4 -125,5,82,Maroon4 -125,27,126,DarkOrchid -125,34,82,HotPink4 -125,56,124,Orchid4 -126,5,23,Brown4 -126,34,23,Tomato4 -126,40,23,Coral4 -126,49,23,SaddleBrown -126,53,23,Sienna4 -126,53,77,PaleVioletRed4 -126,56,23,Salmon4 -126,88,126,Plum4 -127,56,236,Purple2 -127,70,44,LightSalmon4 -127,72,23,Orange4 -127,78,82,LightPink4 -127,82,23,DarkGoldenrod4 -127,82,93,Pink4 -127,90,88,RosyBrown4 -127,255,0,Chartreuse -127,255,212,Aquamarine1 -128,5,23,Firebrick -128,88,23,Goldenrod4 -128,99,65,Burlywood4 -128,101,23,Gold4 -128,103,82,PeachPuff4 -128,106,75,NavajoWhite4 -128,109,126,Thistle4 -128,111,108,MistyRose4 -128,125,124,Gray54 -129,5,65,Maroon -129,110,89,Bisque4 -129,111,84,Wheat4 -129,115,57,LightGoldenrod4 -129,118,121,LavenderBlush4 -129,122,104,CornSilk4 -129,124,123,Snow4 -129,125,116,Ivory4 -130,120,57,Khaki4 -130,124,23,Yellow4 -130,125,107,LightYellow4 -130,128,126,Gray55 -130,202,250,LightSkyBlue -130,202,255,SkyBlue1 -132,45,206,DarkViolet -132,103,215,MediumPurple -133,131,129,Gray56 -135,133,131,Gray57 -135,175,199,LightSkyBlue3 -137,59,255,Purple1 -137,104,205,MediumPurple3 -138,43,226,BlueViolet -139,0,0,DarkRed -139,0,139,DarkMagenta -139,49,199,DarkOrchid3 -139,131,120,AntiqueWhite4 -139,131,120,AntiqueWhite4 -139,134,130,Seashell4 -139,137,112,LemonChiffon4 -139,137,135,Gray58 -139,179,129,DarkSeaGreen -141,56,201,Violet -141,139,137,Gray59 -141,238,238,DarkSlateGray2 -142,53,239,Purple -142,226,236,CadetBlue2 -143,142,141,Gray60 -144,238,144,LightGreen -146,199,199,PaleTurquoise3 -147,145,144,Gray61 -149,148,146,Gray62 -149,185,199,LightBlue3 -151,255,255,DarkSlateGray1 -152,5,23,Brown -152,175,199,SlateGray3 -152,245,255,CadetBlue1 -153,151,149,Gray63 -153,197,23,OliveDrab3 -153,198,142,DarkSeaGreen3 -154,153,152,Gray64 -154,173,199,LightSteelBlue3 -154,205,50,YellowGreen -154,255,154,PaleGreen1 -158,156,155,Gray65 -159,121,238,MediumPurple2 -160,82,45,Sienna -160,159,157,LightGray -160,197,68,DarkOliveGreen3 -160,207,236,LightSkyBlue2 -162,59,236,DarkOrchid2 -163,162,160,Gray67 -165,164,163,Gray68 -167,74,199,MediumOrchid3 -169,168,166,Gray69 -169,169,169,DarkGray -171,130,255,MediumPurple1 -172,171,169,Gray70 -173,169,110,Khaki -173,216,230,LightBlue -173,220,227,PowderBlue -173,223,255,LightSkyBlue1 -173,235,236,PaleTurquoise2 -173,255,47,GreenYellow -174,173,172,Gray71 -174,235,236,PaleTurquoise -175,120,23,DarkGoldenrod -175,199,199,LightCyan3 -175,220,236,LightBlue2 -176,65,255,DarkOrchid1 -176,72,181,MediumOrchid -177,177,175,Gray72 -179,132,129,RosyBrown -179,179,177,Gray73 -179,238,58,OliveDrab2 -180,207,236,SlateGray2 -180,238,180,DarkSeaGreen2 -183,173,89,DarkKhaki -183,182,180,Gray74 -183,206,236,LightSteelBlue2 -185,59,143,Plum -185,184,182,Gray75 -187,255,255,PaleTurquoise1 -188,187,186,Gray76 -188,199,185,Honeydew3 -188,199,199,Azure3 -188,233,84,DarkOliveGreen2 -189,237,255,LightBlue1 -190,190,188,Gray77 -190,190,190,Gray -192,49,199,Magenta3 -192,255,62,OliveDrab1 -193,27,23,Red3 -193,34,103,DeepPink3 -193,34,131,Maroon3 -193,40,105,VioletRed3 -193,96,195,Orchid3 -193,193,191,Gray78 -193,255,193,DarkSeaGreen1 -194,34,23,Brown3 -194,40,23,OrangeRed3 -194,62,23,Tomato3 -194,70,65,IndianRed3 -194,82,131,HotPink3 -194,90,124,PaleVioletRed3 -194,223,255,SlateGray1 -195,74,44,Coral3 -195,86,23,Chocolate3 -195,88,23,Sienna3 -195,98,65,Salmon3 -195,142,199,Plum3 -195,196,194,Gray79 -196,90,236,MediumOrchid2 -196,116,81,LightSalmon3 -196,129,137,LightPink3 -196,135,147,Pink3 -197,119,23,Orange3 -197,119,38,Peru -197,137,23,DarkGoldenrod3 -197,144,142,RosyBrown3 -198,142,23,Goldenrod3 -198,160,109,Burlywood3 -198,166,136,PeachPuff3 -198,174,199,Thistle3 -198,175,172,MistyRose3 -198,222,255,LightSteelBlue1 -199,21,133,MediumVioletRed -199,163,23,Gold3 -199,170,125,NavajoWhite3 -199,175,146,Bisque3 -199,199,197,Gray80 -200,90,23,Chocolate -200,177,137,Wheat3 -200,181,96,LightGoldenrod3 -200,185,166,AntiqueWhite3 -200,187,190,LavenderBlush3 -200,194,167,CornSilk3 -200,196,194,Snow3 -201,190,98,Khaki3 -201,199,170,LightYellow3 -201,199,185,Ivory3 -202,197,23,Yellow3 -202,202,201,Gray81 -202,255,112,DarkOliveGreen1 -204,185,84,MediumGoldenrod -204,204,203,Gray82 -205,92,92,IndianRed -205,197,191,Seashell3 -205,201,165,LemonChiffon3 -207,236,236,LightCyan2 -208,32,144,VioletRed -208,207,207,Gray83 -209,101,135,PaleVioletRed -210,180,140,Tan -210,185,211,Thistle -210,210,209,Gray84 -212,98,255,MediumOrchid1 -212,160,23,Gold -213,213,212,Gray85 -215,215,215,Gray86 -216,175,121,Burlywood -216,217,215,Gainsboro -218,112,214,Orchid -218,165,32,Goldenrod -219,219,217,Gray87 -221,221,220,Gray88 -222,235,220,Honeydew2 -222,236,236,Azure2 -224,224,224,Gray89 -224,255,255,LightCyan -225,139,107,Salmon -226,56,236,Magenta2 -226,227,225,Gray90 -227,49,157,Maroon2 -227,228,250,Lavender -228,27,23,Red2 -228,34,23,Firebrick2 -228,40,124,DeepPink2 -228,45,23,Brown2 -228,49,23,OrangeRed2 -228,49,127,VioletRed2 -228,94,157,HotPink2 -228,115,231,Orchid2 -229,76,44,Tomato2 -229,84,81,IndianRed2 -229,91,60,Coral2 -229,103,23,Chocolate2 -229,110,148,PaleVioletRed2 -229,230,228,Gray91 -230,108,44,Sienna2 -230,116,81,Salmon2 -230,169,236,Plum2 -231,116,113,LightCoral -231,138,97,LightSalmon2 -231,142,23,Orange2 -231,142,53,Tan2 -231,153,163,LightPink2 -231,161,176,Pink2 -232,163,23,DarkGoldenrod2 -232,173,170,RosyBrown2 -232,233,232,Gray92 -233,171,23,Goldenrod2 -233,207,236,Thistle2 -234,190,131,Burlywood2 -234,193,23,Gold2 -234,197,163,PeachPuff2 -234,201,149,NavajoWhite2 -234,208,174,Bisque2 -234,208,204,MistyRose2 -235,211,163,Wheat2 -235,219,197,AntiqueWhite2 -235,221,226,LavenderBlush2 -235,235,234,Gray93 -236,214,114,LightGoldenrod2 -236,216,114,LightGoldenrod -236,229,198,CornSilk2 -236,231,230,Snow2 -236,236,220,Ivory2 -237,226,117,Khaki2 -237,228,158,PaleGoldenrod -237,235,203,LightYellow2 -238,154,77,SandyBrown -238,229,222,Seashell2 -238,233,23,Yellow2 -238,233,191,LemonChiffon2 -238,238,238,Gray94 -239,247,255,AliceBlue -239,255,255,Azure -240,241,240,Gray95 -240,254,238,Honeydew -240,255,240,Honeydew1 -243,218,169,Wheat -244,62,255,Magenta -244,244,243,WhiteSmoke -245,40,135,DeepPink -245,53,170,Maroon1 -245,243,215,Beige -245,243,215,Beige -245,255,249,MintCream -246,34,23,Red1 -246,40,23,Firebrick1 -246,53,38,Brown1 -246,53,138,VioletRed1 -246,56,23,OrangeRed -246,96,171,HotPink - -246,125,250,Orchid1 -246,246,245,Gray97 -247,84,49,Tomato -247,93,89,IndianRed1 -247,101,65,Coral -247,120,161,PaleVioletRed1 -247,247,255,GhostWhite -248,114,23,Chocolate1 -248,116,49,Sienna1 -248,122,23,Orange -248,128,23,DarkOrange -248,129,88,Salmon1 -249,150,107,LightSalmon -249,167,176,LightPink1 -249,183,255,Plum1 -249,232,210,AntiqueWhite -249,238,226,Linen -249,249,250,Gray98 -250,155,23,Orange1 -250,155,60,Tan1 -250,175,186,LightPink -250,175,190,Pink -250,248,204,LightGoldenrodYellow -251,177,23,DarkGoldenrod1 -251,185,23,Goldenrod1 -251,187,185,RosyBrown1 -251,251,251,Gray99 -252,206,142,Burlywood1 -252,213,176,PeachPuff -252,223,255,Thistle1 -252,243,226,OldLace -253,208,23,Gold1 -253,218,163,NavajoWhite -253,224,172,Moccasin -253,224,188,Bisque1 -253,225,221,MistyRose -253,238,244,LavenderBlush -254,228,177,Wheat1 -254,232,198,BlanchedAlmond -254,236,207,PapayaWhip -254,237,214,AntiqueWhite1 -254,243,235,Seashell -255,0,0,Red -255,0,255,Magenta1 -255,20,147,DeepPink1 -255,69,0,OrangeRed1 -255,99,71,Tomato1 -255,160,122,LightSalmon1 -255,181,197,Pink1 -255,218,185,PeachPuff1 -255,222,173,NavajoWhite1 -255,228,196,Bisque -255,228,225,MistyRose1 -255,232,124,LightGoldenrod1 -255,240,245,LavenderBlush1 -255,243,128,Khaki1 -255,245,238,Seashell1 -255,247,215,CornSilk -255,248,198,LemonChiffon -255,249,238,FloralWhite -255,249,250,Snow -255,250,205,LemonChiffon1 -255,250,250,Snow1 -255,254,220,LightYellow -255,255,0,Yellow -255,255,224,LightYellow1 -255,255,238,Ivory -255,255,255,White diff --git a/Toolset/resources/supporting_files/colors/namesToColors.txt b/Toolset/resources/supporting_files/colors/namesToColors.txt deleted file mode 100644 index 88a9cd59bc..0000000000 --- a/Toolset/resources/supporting_files/colors/namesToColors.txt +++ /dev/null @@ -1,557 +0,0 @@ -/* This mapping comes from engine/src/rgb.cpp and should not be changed */ - -AliceBlue,239,247,255 -AntiqueWhite,249,232,210 -AntiqueWhite1,254,237,214 -AntiqueWhite2,235,219,197 -AntiqueWhite3,200,185,166 -AntiqueWhite4,139,131,120 -AntiqueWhite4,139,131,120 -Aquamarine,67,183,186 -Aquamarine1,127,255,212 -Aquamarine2,118,238,198 -Aquamarine3,102,205,170 -Aquamarine4,65,124,100 -Azure,239,255,255 -Azure1,239,255,255 -Azure2,222,236,236 -Azure3,188,199,199 -Azure4,122,125,125 -Beige,245,243,215 -Beige,245,243,215 -Bisque,255,228,196 -Bisque1,253,224,188 -Bisque2,234,208,174 -Bisque3,199,175,146 -Bisque4,129,110,89 -Black,0,0,0 -BlanchedAlmond,254,232,198 -Blue,0,0,255 -Blue1,21,53,255 -Blue2,21,49,236 -Blue3,21,40,199 -Blue4,21,27,126 -BlueViolet,138,43,226 -Brown,152,5,23 -Brown1,246,53,38 -Brown2,228,45,23 -Brown3,194,34,23 -Brown4,126,5,23 -Burlywood,216,175,121 -Burlywood1,252,206,142 -Burlywood2,234,190,131 -Burlywood3,198,160,109 -Burlywood4,128,99,65 -CadetBlue,87,134,147 -CadetBlue1,152,245,255 -CadetBlue2,142,226,236 -CadetBlue3,119,191,199 -CadetBlue4,76,120,126 -Chartreuse,127,255,0 -Chartreuse1,127,255,0 -Chartreuse2,118,238,0 -Chartreuse3,102,205,0 -Chartreuse4,67,124,23 -Chocolate,200,90,23 -Chocolate1,248,114,23 -Chocolate2,229,103,23 -Chocolate3,195,86,23 -Chocolate4,126,49,23 -Coral,247,101,65 -Coral1,247,101,65 -Coral2,229,91,60 -Coral3,195,74,44 -Coral4,126,40,23 -CornflowerBlue,100,149,237 -CornSilk,255,247,215 -CornSilk1,255,247,215 -CornSilk2,236,229,198 -CornSilk3,200,194,167 -CornSilk4,129,122,104 -Cyan,0,255,255 -Cyan1,87,254,255 -Cyan2,80,235,236 -Cyan3,70,199,199 -Cyan4,48,125,126 -DarkBlue,0,0,139 -DarkCyan,0,139,139 -DarkGoldenrod,175,120,23 -DarkGoldenrod1,251,177,23 -DarkGoldenrod2,232,163,23 -DarkGoldenrod3,197,137,23 -DarkGoldenrod4,127,82,23 -DarkGray,169,169,169 -DarkGreen,0,100,0 -DarkKhaki,183,173,89 -DarkMagenta,139,0,139 -DarkOliveGreen,74,65,23 -DarkOliveGreen1,202,255,112 -DarkOliveGreen2,188,233,84 -DarkOliveGreen3,160,197,68 -DarkOliveGreen4,102,124,38 -DarkOrange,248,128,23 -DarkOrange1,248,114,23 -DarkOrange2,229,103,23 -DarkOrange3,195,86,23 -DarkOrange4,126,49,23 -DarkOrchid,125,27,126 -DarkOrchid1,176,65,255 -DarkOrchid2,162,59,236 -DarkOrchid3,139,49,199 -DarkOrchid4,104,34,139 -DarkRed,139,0,0 -DarkSalmon,225,139,107 -DarkSeaGreen,139,179,129 -DarkSeaGreen1,193,255,193 -DarkSeaGreen2,180,238,180 -DarkSeaGreen3,153,198,142 -DarkSeaGreen4,105,139,105 -DarkSlateBlue,43,56,86 -DarkSlateGray,37,56,60 -DarkSlateGray1,151,255,255 -DarkSlateGray2,141,238,238 -DarkSlateGray3,120,199,199 -DarkSlateGray4,76,125,126 -DarkTurquoise,59,156,156 -DarkViolet,132,45,206 -DeepPink,245,40,135 -DeepPink1,255,20,147 -DeepPink2,228,40,124 -DeepPink3,193,34,103 -DeepPink4,125,5,63 -DeepSkyBlue,0,191,255 -DeepSkyBlue1,59,185,255 -DeepSkyBlue2,0,178,238 -DeepSkyBlue3,0,154,205 -DeepSkyBlue4,0,104,139 -DimGray,70,62,65 -DodgerBlue,21,137,255 -DodgerBlue1,30,144,255 -DodgerBlue2,28,134,238 -DodgerBlue3,24,116,205 -DodgerBlue4,16,78,139 -Firebrick,128,5,23 -Firebrick1,246,40,23 -Firebrick2,228,34,23 -Firebrick3,193,27,23 -Firebrick4,126,5,23 -FloralWhite,255,249,238 -ForestGreen,34,139,34 -Gainsboro,216,217,215 -GhostWhite,247,247,255 -Gold,212,160,23 -Gold1,253,208,23 -Gold2,234,193,23 -Gold3,199,163,23 -Gold4,128,101,23 -Goldenrod,218,165,32 -Goldenrod1,251,185,23 -Goldenrod2,233,171,23 -Goldenrod3,198,142,23 -Goldenrod4,128,88,23 -Gray,190,190,190 -Gray0,0,0,0 -Gray0,0,0,0 -Gray1,21,5,23 -Gray10,21,5,23 -Gray100,255,255,255 -Gray11,21,5,23 -Gray12,21,5,23 -Gray13,21,5,23 -Gray14,21,5,23 -Gray15,21,5,23 -Gray16,21,5,23 -Gray17,21,5,23 -Gray18,37,5,23 -Gray19,37,5,23 -Gray2,21,5,23 -Gray20,37,5,23 -Gray21,43,27,23 -Gray22,43,27,23 -Gray23,48,34,23 -Gray24,48,34,38 -Gray25,52,40,38 -Gray26,52,40,44 -Gray27,56,45,44 -Gray28,59,49,49 -Gray29,62,53,53 -Gray3,21,5,23 -Gray30,65,56,57 -Gray31,65,56,60 -Gray32,70,62,63 -Gray33,70,62,65 -Gray34,74,67,68 -Gray35,76,70,70 -Gray36,78,72,72 -Gray37,80,74,75 -Gray38,84,78,79 -Gray39,86,80,81 -Gray4,10,10,10 -Gray40,102,102,102 -Gray41,105,105,105 -Gray42,107,107,107 -Gray43,110,110,110 -Gray44,100,96,96 -Gray45,102,99,98 -Gray46,105,101,101 -Gray47,109,105,104 -Gray48,110,106,107 -Gray49,114,110,109 -Gray5,13,13,13 -Gray50,116,113,112 -Gray51,120,116,115 -Gray52,122,119,119 -Gray53,124,121,121 -Gray54,128,125,124 -Gray55,130,128,126 -Gray56,133,131,129 -Gray57,135,133,131 -Gray58,139,137,135 -Gray59,141,139,137 -Gray6,15,15,15 -Gray60,143,142,141 -Gray61,147,145,144 -Gray62,149,148,146 -Gray63,153,151,149 -Gray64,154,153,152 -Gray65,158,156,155 -Gray66,160,159,157 -Gray67,163,162,160 -Gray68,165,164,163 -Gray69,169,168,166 -Gray7,18,18,18 -Gray70,172,171,169 -Gray71,174,173,172 -Gray72,177,177,175 -Gray73,179,179,177 -Gray74,183,182,180 -Gray75,185,184,182 -Gray76,188,187,186 -Gray77,190,190,188 -Gray78,193,193,191 -Gray79,195,196,194 -Gray8,20,20,20 -Gray80,199,199,197 -Gray81,202,202,201 -Gray82,204,204,203 -Gray83,208,207,207 -Gray84,210,210,209 -Gray85,213,213,212 -Gray86,215,215,215 -Gray87,219,219,217 -Gray88,221,221,220 -Gray89,224,224,224 -Gray9,21,5,23 -Gray90,226,227,225 -Gray91,229,230,228 -Gray92,232,233,232 -Gray93,235,235,234 -Gray94,238,238,238 -Gray95,240,241,240 -Gray96,244,244,243 -Gray97,246,246,245 -Gray98,249,249,250 -Gray99,251,251,251 -Green,0,255,0 -Green1,95,251,23 -Green2,0,238,0 -Green3,0,205,0 -Green4,0,139,0 -GreenYellow,173,255,47 -Honeydew,240,254,238 -Honeydew1,240,255,240 -Honeydew2,222,235,220 -Honeydew3,188,199,185 -Honeydew4,122,125,116 -HotPink,246,96,171 -HotPink1,246,101,171 -HotPink2,228,94,157 -HotPink3,194,82,131 -HotPink4,125,34,82 -IndianRed,205,92,92 -IndianRed1,247,93,89 -IndianRed2,229,84,81 -IndianRed3,194,70,65 -IndianRed4,126,34,23 -Ivory,255,255,238 -Ivory1,255,255,238 -Ivory2,236,236,220 -Ivory3,201,199,185 -Ivory4,129,125,116 -Khaki,173,169,110 -Khaki1,255,243,128 -Khaki2,237,226,117 -Khaki3,201,190,98 -Khaki4,130,120,57 -Lavender,227,228,250 -LavenderBlush,253,238,244 -LavenderBlush1,255,240,245 -LavenderBlush2,235,221,226 -LavenderBlush3,200,187,190 -LavenderBlush4,129,118,121 -LawnGreen,124,252,0 -LemonChiffon,255,248,198 -LemonChiffon1,255,250,205 -LemonChiffon2,238,233,191 -LemonChiffon3,205,201,165 -LemonChiffon4,139,137,112 -LightBlue,173,216,230 -LightBlue1,189,237,255 -LightBlue2,175,220,236 -LightBlue3,149,185,199 -LightBlue4,104,131,139 -LightCoral,231,116,113 -LightCyan,224,255,255 -LightCyan1,224,255,255 -LightCyan2,207,236,236 -LightCyan3,175,199,199 -LightCyan4,113,125,125 -LightGoldenrod,236,216,114 -LightGoldenrod1,255,232,124 -LightGoldenrod2,236,214,114 -LightGoldenrod3,200,181,96 -LightGoldenrod4,129,115,57 -LightGoldenrodYellow,250,248,204 -LightGray,160,159,157 -LightGreen,144,238,144 -LightPink,250,175,186 -LightPink1,249,167,176 -LightPink2,231,153,163 -LightPink3,196,129,137 -LightPink4,127,78,82 -LightSalmon,249,150,107 -LightSalmon1,255,160,122 -LightSalmon2,231,138,97 -LightSalmon3,196,116,81 -LightSalmon4,127,70,44 -LightSeaGreen,32,178,170 -LightSkyBlue,130,202,250 -LightSkyBlue1,173,223,255 -LightSkyBlue2,160,207,236 -LightSkyBlue3,135,175,199 -LightSkyBlue4,86,109,126 -LightSlateBlue,115,106,255 -LightSlateGray,109,123,141 -LightSteelBlue,114,143,206 -LightSteelBlue1,198,222,255 -LightSteelBlue2,183,206,236 -LightSteelBlue3,154,173,199 -LightSteelBlue4,100,109,126 -LightYellow,255,254,220 -LightYellow1,255,255,224 -LightYellow2,237,235,203 -LightYellow3,201,199,170 -LightYellow4,130,125,107 -LimeGreen,50,205,50 -Linen,249,238,226 -Magenta,244,62,255 -Magenta1,255,0,255 -Magenta2,226,56,236 -Magenta3,192,49,199 -Magenta4,125,27,126 -Maroon,129,5,65 -Maroon1,245,53,170 -Maroon2,227,49,157 -Maroon3,193,34,131 -Maroon4,125,5,82 -MediumAquamarine,102,205,170 -MediumBlue,0,0,205 -MediumForestGreen,52,114,53 -MediumGoldenrod,204,185,84 -MediumOrchid,176,72,181 -MediumOrchid1,212,98,255 -MediumOrchid2,196,90,236 -MediumOrchid3,167,74,199 -MediumOrchid4,106,40,126 -MediumPurple,132,103,215 -MediumPurple1,171,130,255 -MediumPurple2,159,121,238 -MediumPurple3,137,104,205 -MediumPurple4,93,71,139 -MediumSeaGreen,48,103,84 -MediumSlateBlue,123,104,238 -MediumSpringGreen,0,250,154 -MediumTurquoise,72,204,205 -MediumVioletRed,199,21,133 -MidnightBlue,21,27,84 -MintCream,245,255,249 -MistyRose,253,225,221 -MistyRose1,255,228,225 -MistyRose2,234,208,204 -MistyRose3,198,175,172 -MistyRose4,128,111,108 -Moccasin,253,224,172 -NavajoWhite,253,218,163 -NavajoWhite1,255,222,173 -NavajoWhite2,234,201,149 -NavajoWhite3,199,170,125 -NavajoWhite4,128,106,75 -Navy,0,0,128 -NavyBlue,0,0,128 -OldLace,252,243,226 -OliveDrab,101,128,23 -OliveDrab1,192,255,62 -OliveDrab2,179,238,58 -OliveDrab3,153,197,23 -OliveDrab4,105,139,34 -Orange,248,122,23 -Orange1,250,155,23 -Orange2,231,142,23 -Orange3,197,119,23 -Orange4,127,72,23 -OrangeRed,246,56,23 -OrangeRed1,255,69,0 -OrangeRed2,228,49,23 -OrangeRed3,194,40,23 -OrangeRed4,126,5,23 -Orchid,218,112,214 -Orchid1,246,125,250 -Orchid2,228,115,231 -Orchid3,193,96,195 -Orchid4,125,56,124 -PaleGoldenrod,237,228,158 -PaleGreen,121,216,103 -PaleGreen1,154,255,154 -PaleGreen2,144,238,144 -PaleGreen3,124,205,124 -PaleGreen4,78,124,65 -PaleTurquoise,174,235,236 -PaleTurquoise1,187,255,255 -PaleTurquoise2,173,235,236 -PaleTurquoise3,146,199,199 -PaleTurquoise4,102,139,139 -PaleVioletRed,209,101,135 -PaleVioletRed1,247,120,161 -PaleVioletRed2,229,110,148 -PaleVioletRed3,194,90,124 -PaleVioletRed4,126,53,77 -PapayaWhip,254,236,207 -PeachPuff,252,213,176 -PeachPuff1,255,218,185 -PeachPuff2,234,197,163 -PeachPuff3,198,166,136 -PeachPuff4,128,103,82 -Peru,197,119,38 -Pink,250,175,190 -Pink1,255,181,197 -Pink2,231,161,176 -Pink3,196,135,147 -Pink4,127,82,93 -Plum,185,59,143 -Plum1,249,183,255 -Plum2,230,169,236 -Plum3,195,142,199 -Plum4,126,88,126 -PowderBlue,173,220,227 -Purple,142,53,239 -Purple1,137,59,255 -Purple2,127,56,236 -Purple3,108,45,199 -Purple4,70,27,126 -Red,255,0,0 -Red1,246,34,23 -Red2,228,27,23 -Red3,193,27,23 -Red4,126,5,23 -RosyBrown,179,132,129 -RosyBrown1,251,187,185 -RosyBrown2,232,173,170 -RosyBrown3,197,144,142 -RosyBrown4,127,90,88 -RoyalBlue,43,96,222 -RoyalBlue1,48,110,255 -RoyalBlue2,43,101,236 -RoyalBlue3,37,84,199 -RoyalBlue4,21,49,126 -SaddleBrown,126,49,23 -Salmon,225,139,107 -Salmon1,248,129,88 -Salmon2,230,116,81 -Salmon3,195,98,65 -Salmon4,126,56,23 -SandyBrown,238,154,77 -SeaGreen,46,139,87 -SeaGreen1,106,251,146 -SeaGreen2,100,233,134 -SeaGreen3,67,205,128 -SeaGreen4,46,139,87 -Seashell,254,243,235 -Seashell1,255,245,238 -Seashell2,238,229,222 -Seashell3,205,197,191 -Seashell4,139,134,130 -Sienna,160,82,45 -Sienna1,248,116,49 -Sienna2,230,108,44 -Sienna3,195,88,23 -Sienna4,126,53,23 -SkyBlue,102,152,255 -SkyBlue1,130,202,255 -SkyBlue2,121,186,236 -SkyBlue3,101,158,199 -SkyBlue4,65,98,126 -SlateBlue,106,90,205 -SlateBlue1,115,105,255 -SlateBlue2,105,96,236 -SlateBlue3,105,89,205 -SlateBlue4,52,45,126 -SlateGray,101,115,131 -SlateGray1,194,223,255 -SlateGray2,180,207,236 -SlateGray3,152,175,199 -SlateGray4,108,123,139 -Snow,255,249,250 -Snow1,255,250,250 -Snow2,236,231,230 -Snow3,200,196,194 -Snow4,129,124,123 -SpringGreen,0,255,127 -SpringGreen1,94,251,110 -SpringGreen2,0,238,118 -SpringGreen3,0,205,102 -SpringGreen4,0,139,69 -SteelBlue,70,130,180 -SteelBlue1,92,179,255 -SteelBlue2,86,165,236 -SteelBlue3,72,138,199 -SteelBlue4,43,84,126 -Tan,210,180,140 -Tan1,250,155,60 -Tan2,231,142,53 -Tan3,197,119,38 -Tan4,127,72,23 -Thistle,210,185,211 -Thistle1,252,223,255 -Thistle2,233,207,236 -Thistle3,198,174,199 -Thistle4,128,109,126 -Tomato,247,84,49 -Tomato1,255,99,71 -Tomato2,229,76,44 -Tomato3,194,62,23 -Tomato4,126,34,23 -Transparent,21,5,23 -Turquoise,64,224,208 -Turquoise1,0,245,255 -Turquoise2,0,229,238 -Turquoise3,0,197,205 -Turquoise4,0,134,139 -Violet,141,56,201 -VioletRed,208,32,144 -VioletRed1,246,53,138 -VioletRed2,228,49,127 -VioletRed3,193,40,105 -VioletRed4,125,5,65 -Wheat,243,218,169 -Wheat1,254,228,177 -Wheat2,235,211,163 -Wheat3,200,177,137 -Wheat4,129,111,84 -White,255,255,255 -WhiteSmoke,244,244,243 -Yellow,255,255,0 -Yellow1,255,255,0 -Yellow2,238,233,23 -Yellow3,202,197,23 -Yellow4,130,124,23 -YellowGreen,154,205,50 \ No newline at end of file diff --git a/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Button.livecodescript b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Button.livecodescript new file mode 100644 index 0000000000..181f93b9c9 --- /dev/null +++ b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Button.livecodescript @@ -0,0 +1,6 @@ +script "com.livecode.interface.classic.Button" +-- Sent when the mouse is released after clicking +-- pMouseButton specifies which mouse button was pressed +on mouseUp pMouseButton + +end mouseUp diff --git a/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.OptionMenu.livecodescript b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.OptionMenu.livecodescript new file mode 100644 index 0000000000..af8117b101 --- /dev/null +++ b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.OptionMenu.livecodescript @@ -0,0 +1,7 @@ +script "com.livecode.interface.classic.OptionMenu" +-- Sent when a menu item is picked from the option menu +on menuPick pItemName + switch pItemName + + end switch +end menuPick \ No newline at end of file diff --git a/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Scrollbar.livecodescript b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Scrollbar.livecodescript new file mode 100644 index 0000000000..be70d149b9 --- /dev/null +++ b/Toolset/resources/supporting_files/default_scripts/com.livecode.interface.classic.Scrollbar.livecodescript @@ -0,0 +1,11 @@ +script "com.livecode.interface.classic.Scrollbar" +local sStartValue +on mouseDown + --save the initial value + put the thumbPos of me into sStartValue +end mouseDown + +on scrollbarDrag newValue +-- newValue contains the current thumbpos value + +end scrollbarDrag \ No newline at end of file diff --git a/Toolset/resources/supporting_files/fonts/LICENSE.txt b/Toolset/resources/supporting_files/fonts/LICENSE.txt new file mode 100755 index 0000000000..df187637e1 --- /dev/null +++ b/Toolset/resources/supporting_files/fonts/LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Black.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Black.ttf new file mode 100644 index 0000000000..7ca3628014 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Black.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-BlackIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-BlackIt.ttf new file mode 100644 index 0000000000..97cf90204b Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-BlackIt.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Bold.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Bold.ttf new file mode 100644 index 0000000000..64a7fad726 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Bold.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-BoldIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-BoldIt.ttf new file mode 100644 index 0000000000..13952e33d3 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-BoldIt.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLight.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLight.ttf new file mode 100644 index 0000000000..4ee6382b13 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLight.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLightIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLightIt.ttf new file mode 100644 index 0000000000..6fcd060a09 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-ExtraLightIt.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-It.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-It.ttf new file mode 100644 index 0000000000..34fc30ae48 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-It.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Light.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Light.ttf new file mode 100644 index 0000000000..9bd5f5581a Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Light.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-LightIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-LightIt.ttf new file mode 100644 index 0000000000..77e8ab6b9a Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-LightIt.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Medium.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Medium.ttf new file mode 100644 index 0000000000..902ded026c Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Medium.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-MediumIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-MediumIt.ttf new file mode 100644 index 0000000000..6c9c216973 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-MediumIt.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Regular.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Regular.ttf new file mode 100644 index 0000000000..2790fd23ba Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Regular.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-Semibold.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-Semibold.ttf new file mode 100644 index 0000000000..37111b6dd6 Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-Semibold.ttf differ diff --git a/Toolset/resources/supporting_files/fonts/SourceCodePro-SemiboldIt.ttf b/Toolset/resources/supporting_files/fonts/SourceCodePro-SemiboldIt.ttf new file mode 100644 index 0000000000..63d4f3e40b Binary files /dev/null and b/Toolset/resources/supporting_files/fonts/SourceCodePro-SemiboldIt.ttf differ diff --git a/Toolset/resources/supporting_files/property_definitions/classicToolsOrder.txt b/Toolset/resources/supporting_files/property_definitions/classicToolsOrder.tsv similarity index 100% rename from Toolset/resources/supporting_files/property_definitions/classicToolsOrder.txt rename to Toolset/resources/supporting_files/property_definitions/classicToolsOrder.tsv diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.tsv b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.tsv new file mode 100644 index 0000000000..4413fd3300 --- /dev/null +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.tsv @@ -0,0 +1,14 @@ +Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step +type control +title Control Properties + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +geometry:revIDEGetGeometry:revIDESetGeometry Geometry Geometry Manager com.livecode.pi.geometry true false +location +resize:revIDEGetRectProperty:revIDESetRectProperty Resize when setting rect property Position com.livecode.pi.boolean true false +left +top +right +bottom +layer +number \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.txt deleted file mode 100644 index 7069e05565..0000000000 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.Control.txt +++ /dev/null @@ -1,6 +0,0 @@ -type control -title Control Properties - -Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- -geometry:revIDEGetGeometry:revIDESetGeometry Geometry Geometry Manager com.livecode.pi.geometry true false \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.tsv similarity index 58% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.tsv index 09b5225063..e56c51fbda 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.MultipleObjects.tsv @@ -1,11 +1,11 @@ -type multiple -title Multiple Objects - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- -equalize::revIDEAlignControlsFromPI Equalize Align Controls com.livecode.pi.equalize true false -align::revIDEAlignControlsFromPI Align Align Controls com.livecode.pi.align true false Align -alignCenter::revIDEAlignControlsFromPI Align center Align Controls com.livecode.pi.aligncenter true false Align -distribute::revIDEAlignControlsFromPI Distribute Align Controls com.livecode.pi.distribute true false -nudge::revIDEAlignControlsFromPI Nudge Align Controls com.livecode.pi.nudge true false -relayer::revIDEAlignControlsFromPI Relayer Align Controls com.livecode.pi.relayer true false \ No newline at end of file +type multiple +title Multiple Objects + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +equalize::revIDEAlignControlsFromPI Equalize Align Controls com.livecode.pi.equalize true false +align::revIDEAlignControlsFromPI Align Align Controls com.livecode.pi.align true false Align +alignCenter::revIDEAlignControlsFromPI Align center Align Controls com.livecode.pi.aligncenter true false Align +distribute::revIDEAlignControlsFromPI Distribute Align Controls com.livecode.pi.distribute true false +nudge::revIDEAlignControlsFromPI Nudge Align Controls com.livecode.pi.nudge true false +relayer::revIDEAlignControlsFromPI Relayer Align Controls com.livecode.pi.relayer true false \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.tsv similarity index 85% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.tsv index 825e5324b1..c7f626d99b 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Button.tsv @@ -1,8 +1,8 @@ -type button -title Standard Button - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Standard Button + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Button label tooltip @@ -28,6 +28,7 @@ disabledIcon visitedIcon armedIcon hoverIcon +iconGravity threeD true showBorder true hiliteBorder true @@ -62,12 +63,5 @@ textStyle textAlign center margins 4 lockLoc false -width 82 -height 23 -location -left -top -right -bottom -layer -number \ No newline at end of file +width::revIDESetRectProperty com.livecode.pi.dimension 82 +height::revIDESetRectProperty com.livecode.pi.dimension 23 \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.tsv similarity index 85% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.tsv index 7845e20210..a17ca69f09 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Card.tsv @@ -1,8 +1,8 @@ -type card -title Card - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type card +title Card + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name number mark false @@ -12,7 +12,7 @@ showBorder true opaque true threeD true borderWidth 2 -behavior +behavior foregroundColor foregroundPattern backgroundColor @@ -43,5 +43,5 @@ left true top true right true bottom true -layer -number false \ No newline at end of file +layer +number false \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.tsv similarity index 85% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.tsv index d5060ba229..de0d0fdb90 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Checkbox.tsv @@ -1,8 +1,8 @@ -type button -title Check Box - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Check Box + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Check label tooltip @@ -19,7 +19,7 @@ traversalOn true showFocusBorder true default false disabled -hilited +hilited layerMode behavior icon @@ -62,12 +62,5 @@ textStyle textAlign margins 4 lockLoc false -width 82 -height 23 -location -left -top -right -bottom -layer -number \ No newline at end of file +width::revIDESetRectProperty com.livecode.pi.dimension 82 +height::revIDESetRectProperty com.livecode.pi.dimension 23 \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.tsv similarity index 76% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.tsv index 9b153b0680..be5adb35c3 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ComboBox.tsv @@ -1,8 +1,8 @@ -type button -title Combo Box Menu - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Combo Box Menu + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name ComboBox Menu label Choice 1 tooltip @@ -12,9 +12,9 @@ menuMouseButton visible true opaque true showName true -traversalOn true +traversalOn true disabled false -text Menu Items true Choice 1\nChoice 2\nChoice 3 +text Menu Items true Choice 1\nChoice 2\nChoice 3 menuLines 5 menuName layerMode @@ -29,8 +29,8 @@ threeD true showBorder true hiliteBorder true borderWidth 2 -armBorder false false -autoHilite false false +armBorder false false +autoHilite false false foregroundColor Text fill foregroundPattern Text fill backgroundColor @@ -56,17 +56,10 @@ textStyle textAlign center margins 4 lockLoc no_default -width 102 -height 22 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 102 +height::revIDESetRectProperty com.livecode.pi.dimension 22 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.tsv similarity index 74% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.tsv index d384a79a65..df8e98c0ad 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.CurveGraphic.tsv @@ -1,9 +1,10 @@ -type graphic tool -title Curve Graphic - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- -name Curve +type graphic tool +title Curve Graphic + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +name Curve +label tooltip style curve rectangle,roundrect,line,oval,regular,line,curve,polygon opaque false @@ -16,12 +17,12 @@ dashes startArrow false endArrow false points -layerMode Static Static,Dynamic,Scrolling +layerMode behavior empty long id foregroundColor Border fill foregroundPattern Border fill fillGradient -strokeGradient +strokeGradient topColor topPattern bottomColor @@ -37,15 +38,8 @@ margins 8 lockLoc false width height -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.tsv similarity index 62% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.tsv index 3365d6a2bb..74128ac66e 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGrid.tsv @@ -1,67 +1,80 @@ -type data grid -title Data Grid - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type data grid +title Data Grid + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name -style:revIDEGetDataGridProperty:revIDESetDataGridProperty Style Data Grid com.livecode.pi.enum true false no_default table,form -show hscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show hScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto -show vscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show vScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto -allow editing:revIDEGetDataGridProperty:revIDESetDataGridProperty Allow text editing Data Grid com.livecode.pi.boolean true false no_default -alternate row colors:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row colors Data Grid com.livecode.pi.boolean true false no_default -auto hilite:revIDEGetDataGridProperty:revIDESetDataGridProperty Auto-hilite rows Data Grid com.livecode.pi.boolean true false no_default -multiple lines:revIDEGetDataGridProperty:revIDESetDataGridProperty Multi-row hilites Data Grid com.livecode.pi.boolean true false no_default -allow column resizing:revIDEGetDataGridProperty:revIDESetDataGridProperty Drag resizing Data Grid com.livecode.pi.boolean true false no_default -persistent data:revIDEGetDataGridProperty:revIDESetDataGridProperty Persistent data Data Grid com.livecode.pi.boolean true false no_default -fixed control height:revIDEGetDataGridProperty:revIDESetDataGridProperty Empty row height Data Grid com.livecode.pi.boolean false false true +style:revIDEGetDataGridProperty:revIDESetDataGridProperty Style Data Grid com.livecode.pi.enum true false no_default table,form +show hscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show hScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto +show vscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show vScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto +allow editing:revIDEGetDataGridProperty:revIDESetDataGridProperty Allow text editing Data Grid com.livecode.pi.boolean true false no_default +alternate row colors:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row colors Data Grid com.livecode.pi.boolean true false no_default +auto hilite:revIDEGetDataGridProperty:revIDESetDataGridProperty Auto-hilite rows Data Grid com.livecode.pi.boolean true false no_default +multiple lines:revIDEGetDataGridProperty:revIDESetDataGridProperty Multi-row hilites Data Grid com.livecode.pi.boolean true false no_default +allow column resizing:revIDEGetDataGridProperty:revIDESetDataGridProperty Drag resizing Data Grid com.livecode.pi.boolean true false no_default +persistent data:revIDEGetDataGridProperty:revIDESetDataGridProperty Persistent data Data Grid com.livecode.pi.boolean true false no_default +animate actions:revIDEGetDataGridProperty:revIDESetDataGridProperty Animate actions Data Grid com.livecode.pi.boolean false false true +enable swipe:revIDEGetDataGridProperty:revIDESetDataGridProperty Enable swipes Data Grid com.livecode.pi.boolean false false false +fixed control height:revIDEGetDataGridProperty:revIDESetDataGridProperty Empty row height Data Grid com.livecode.pi.boolean false false true row height:revIDEGetDataGridProperty:revIDESetDataGridProperty Row height Data Grid com.livecode.pi.number true false 21 1 - -row template::revIDEDataGridAction Row Template... Data Grid com.livecode.pi.action true false -refresh::revIDEDataGridAction Refresh Data Grid Data Grid com.livecode.pi.action true false - -text:revIDEGetDataGridProperty:revIDESetDataGridProperty Contents Contents com.livecode.pi.textcontents true false no_default - -text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Text color Colors com.livecode.pi.color true false -hilited text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Hilited text color Colors com.livecode.pi.color true false -background color:revIDEGetDataGridProperty:revIDESetDataGridProperty Background color Colors com.livecode.pi.color true false -row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Row color Colors com.livecode.pi.color true false -alternate row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row color Colors com.livecode.pi.color true false -hilite color:revIDEGetDataGridProperty:revIDESetDataGridProperty Selection hilite color Colors com.livecode.pi.color true false -column divider color:revIDEGetDataGridProperty:revIDESetDataGridProperty Column divider color Colors com.livecode.pi.color true false -corner color:revIDEGetDataGridProperty:revIDESetDataGridProperty Corner color Colors com.livecode.pi.color true false -header text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text color Colors com.livecode.pi.color true false - -show header:revIDEGetDataGridProperty:revIDESetDataGridProperty Show column headers Columns com.livecode.pi.boolean true false true -columnData:revIDEGetDataGridColumns:revIDESetDataGridColumns Columns Columns com.livecode.pi.datagridcolumns true false no_default -column name:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column name Columns com.livecode.pi.string true false no_default -column label:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column label Columns com.livecode.pi.string true false no_default -column visible:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Visible Columns com.livecode.pi.boolean true false no_default + +row template::revIDEDataGridAction Row Template... Data Grid com.livecode.pi.action true false +refresh::revIDEDataGridAction Refresh Data Grid Data Grid com.livecode.pi.action true false + +text:revIDEGetDataGridProperty:revIDESetDataGridProperty Contents Contents com.livecode.pi.textcontents true false no_default + +text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Text color Colors com.livecode.pi.color true false +hilited text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Hilited text color Colors com.livecode.pi.color true false +background color:revIDEGetDataGridProperty:revIDESetDataGridProperty Background color Colors com.livecode.pi.color true false +row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Row color Colors com.livecode.pi.color true false +alternate row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row color Colors com.livecode.pi.color true false +hilite color:revIDEGetDataGridProperty:revIDESetDataGridProperty Selection hilite color Colors com.livecode.pi.color true false +column divider color:revIDEGetDataGridProperty:revIDESetDataGridProperty Column divider color Colors com.livecode.pi.color true false +corner color:revIDEGetDataGridProperty:revIDESetDataGridProperty Corner color Colors com.livecode.pi.color true false +header background color:revIDEGetDataGridProperty:revIDESetDataGridProperty Header color Colors com.livecode.pi.color true false +header text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text color Colors com.livecode.pi.color true false +header background hilite color:revIDEGetDataGridProperty:revIDESetDataGridProperty Header hilite color Colors com.livecode.pi.color true false + + + +show header:revIDEGetDataGridProperty:revIDESetDataGridProperty Show column headers Columns com.livecode.pi.boolean true false true +columnData:revIDEGetDataGridColumns:revIDESetDataGridColumns Columns Columns com.livecode.pi.datagridcolumns true false no_default +column name:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column name Columns com.livecode.pi.string true false no_default +column label:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column label Columns com.livecode.pi.string true false no_default +column visible:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Visible Columns com.livecode.pi.boolean true false no_default column width:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Width Columns com.livecode.pi.number true false no_default 1 -column drag to resize:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Drag to resize Columns com.livecode.pi.boolean true false no_default +column drag to resize:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Drag to resize Columns com.livecode.pi.boolean true false no_default column min width:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Min width Columns com.livecode.pi.number true false no_default 1 column max width:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Max width Columns com.livecode.pi.number true false no_default 1 -column align:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Align Columns com.livecode.pi.enum true false Left Left,Center,Right -sort by column:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort by column Columns com.livecode.pi.boolean true false no_default -column sort direction:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort direction Columns com.livecode.pi.enum true false Sort Options Ascending Ascending,Descending -column sort type:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort type Columns com.livecode.pi.enum true false Sort Options Text Text,Numeric,DateTime,System DateTime,International -column case sensitive:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Case sensitive Columns com.livecode.pi.boolean true false no_default -column behavior:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column behavior Columns com.livecode.pi.dgcolumnbehavior true false no_default - +column align:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Align Columns com.livecode.pi.enum true false Left Left,Center,Right +sort by column:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort by column Columns com.livecode.pi.boolean true false no_default +column sort direction:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort direction Columns com.livecode.pi.enum true false Sort Options Ascending Ascending,Descending +column sort type:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Sort type Columns com.livecode.pi.enum true false Sort Options Text Text,Numeric,DateTime,System DateTime,International +column case sensitive:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Case sensitive Columns com.livecode.pi.boolean true false no_default +column behavior:revIDEGetDataGridColumnProperty:revIDESetDataGridColumnProperty Column behavior Columns com.livecode.pi.dgcolumnbehavior true false no_default + +text font:revIDEGetDataGridProperty:revIDESetDataGridProperty Text font Text com.livecode.pi.font true false +text size:revIDEGetDataGridProperty:revIDESetDataGridProperty Text size Text com.livecode.pi.integer true false empty +text style:revIDEGetDataGridProperty:revIDESetDataGridProperty Text style Text com.livecode.pi.textstyle true false +header text font:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text font Text com.livecode.pi.font true false +header text size:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text size Text com.livecode.pi.integer true false empty +header text style:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text style Text com.livecode.pi.textstyle true false + label tooltip disabled -showBorder true -borderWidth 1 +showBorder true +borderWidth 1 visible customProperties lockLoc false width 250 height 160 -location -left -top -right -bottom -layer -layerMode -number \ No newline at end of file +layerMode +blendLevel 0 0,100 +ink +dropShadow +innerShadow +outerGlow +innerGlow +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.tsv similarity index 60% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.tsv index c54c7fcef6..0db7821640 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DataGridForm.tsv @@ -1,50 +1,57 @@ Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name -style:revIDEGetDataGridProperty:revIDESetDataGridProperty Style Data Grid com.livecode.pi.enum true false no_default table,form -show hscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show hScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto -show vscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show vScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto -allow editing:revIDEGetDataGridProperty:revIDESetDataGridProperty Allow text editing Data Grid com.livecode.pi.boolean true false no_default -alternate row colors:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row colors Data Grid com.livecode.pi.boolean true false no_default -auto hilite:revIDEGetDataGridProperty:revIDESetDataGridProperty Auto-hilite rows Data Grid com.livecode.pi.boolean true false no_default -multiple lines:revIDEGetDataGridProperty:revIDESetDataGridProperty Multi-row hilites Data Grid com.livecode.pi.boolean true false no_default -allow column resizing:revIDEGetDataGridProperty:revIDESetDataGridProperty Drag resizing Data Grid com.livecode.pi.boolean true false no_default -cache controls:revIDEGetDataGridProperty:revIDESetDataGridProperty Cache controls Data Grid com.livecode.pi.boolean true false no_default -persistent data:revIDEGetDataGridProperty:revIDESetDataGridProperty Persistent data Data Grid com.livecode.pi.boolean true false no_default -fixed control height:revIDEGetDataGridProperty:revIDESetDataGridProperty Empty row height Data Grid com.livecode.pi.boolean true false no_default +style:revIDEGetDataGridProperty:revIDESetDataGridProperty Style Data Grid com.livecode.pi.enum true false no_default table,form +show hscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show hScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto +show vscrollbar:revIDEGetDataGridProperty:revIDESetDataGridProperty Show vScrollbar Data Grid com.livecode.pi.enum true false no_default true,false,auto +allow editing:revIDEGetDataGridProperty:revIDESetDataGridProperty Allow text editing Data Grid com.livecode.pi.boolean true false no_default +alternate row colors:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row colors Data Grid com.livecode.pi.boolean true false no_default +auto hilite:revIDEGetDataGridProperty:revIDESetDataGridProperty Auto-hilite rows Data Grid com.livecode.pi.boolean true false no_default +multiple lines:revIDEGetDataGridProperty:revIDESetDataGridProperty Multi-row hilites Data Grid com.livecode.pi.boolean true false no_default +allow column resizing:revIDEGetDataGridProperty:revIDESetDataGridProperty Drag resizing Data Grid com.livecode.pi.boolean true false no_default +cache controls:revIDEGetDataGridProperty:revIDESetDataGridProperty Cache controls Data Grid com.livecode.pi.boolean true false no_default +persistent data:revIDEGetDataGridProperty:revIDESetDataGridProperty Persistent data Data Grid com.livecode.pi.boolean true false no_default +animate actions:revIDEGetDataGridProperty:revIDESetDataGridProperty Animate actions Data Grid com.livecode.pi.boolean true false true +enable swipe:revIDEGetDataGridProperty:revIDESetDataGridProperty Enable swipes Data Grid com.livecode.pi.boolean true false false +minimal layout:revIDEGetDataGridProperty:revIDESetDataGridProperty Minimal layout Data Grid com.livecode.pi.boolean true false false +fixed control height:revIDEGetDataGridProperty:revIDESetDataGridProperty Fixed row height Data Grid com.livecode.pi.boolean true false no_default row height:revIDEGetDataGridProperty:revIDESetDataGridProperty Row height Data Grid com.livecode.pi.number true false 21 1 row behavior:revIDEGetDataGridProperty:revIDESetDataGridProperty Row behavior Data Grid com.livecode.pi.script true true no_default 1 - -row template::revIDEDataGridAction Row Template... Data Grid com.livecode.pi.action true false -refresh::revIDEDataGridAction Refresh Data Grid Data Grid com.livecode.pi.action true false - -text:revIDEGetDataGridProperty:revIDESetDataGridProperty Contents Contents com.livecode.pi.textcontents true false no_default -first row header:revIDEGetDataGridProperty:revIDESetDataGridProperty First row is header Contents com.livecode.pi.boolean true false no_default - -text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Text color Colors com.livecode.pi.color true false -hilited text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Hilited text color Colors com.livecode.pi.color true false -background color:revIDEGetDataGridProperty:revIDESetDataGridProperty Background color Colors com.livecode.pi.color true false -row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Row color Colors com.livecode.pi.color true false -alternate row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row color Colors com.livecode.pi.color true false -hilite color:revIDEGetDataGridProperty:revIDESetDataGridProperty Selection hilite color Colors com.livecode.pi.color true false -column divider color:revIDEGetDataGridProperty:revIDESetDataGridProperty Column divider color Colors com.livecode.pi.color true false -corner color:revIDEGetDataGridProperty:revIDESetDataGridProperty Corner color Colors com.livecode.pi.color true false -header text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Header text color Colors com.livecode.pi.color true false + +row template::revIDEDataGridAction Row Template... Data Grid com.livecode.pi.action true false +refresh::revIDEDataGridAction Refresh Data Grid Data Grid com.livecode.pi.action true false + +text:revIDEGetDataGridProperty:revIDESetDataGridProperty Contents Contents com.livecode.pi.textcontents true false no_default +first row header:revIDEGetDataGridProperty:revIDESetDataGridProperty First row is header Contents com.livecode.pi.boolean true false no_default + +text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Text color Colors com.livecode.pi.color true false +hilited text color:revIDEGetDataGridProperty:revIDESetDataGridProperty Hilited text color Colors com.livecode.pi.color true false +background color:revIDEGetDataGridProperty:revIDESetDataGridProperty Background color Colors com.livecode.pi.color true false +row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Row color Colors com.livecode.pi.color true false +alternate row color:revIDEGetDataGridProperty:revIDESetDataGridProperty Alternate row color Colors com.livecode.pi.color true false +hilite color:revIDEGetDataGridProperty:revIDESetDataGridProperty Selection hilite color Colors com.livecode.pi.color true false +column divider color:revIDEGetDataGridProperty:revIDESetDataGridProperty Column divider color Colors com.livecode.pi.color true false +corner color:revIDEGetDataGridProperty:revIDESetDataGridProperty Corner color Colors com.livecode.pi.color true false + +text font:revIDEGetDataGridProperty:revIDESetDataGridProperty Text font Text com.livecode.pi.font true false +text size:revIDEGetDataGridProperty:revIDESetDataGridProperty Text size Text com.livecode.pi.integer true false +text style:revIDEGetDataGridProperty:revIDESetDataGridProperty Text style Text com.livecode.pi.textstyle true false + label tooltip disabled -showBorder true -borderWidth 1 +showBorder true +borderWidth 1 visible customProperties lockLoc false width 250 height 160 -location -left -top -right -bottom -layer -layerMode -number \ No newline at end of file +layerMode +blendLevel 0 0,100 +ink +dropShadow +innerShadow +outerGlow +innerGlow +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.tsv similarity index 84% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.tsv index c86df192de..5b72d73489 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.DefaultButton.tsv @@ -1,8 +1,8 @@ -type button -title Default Button - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Default Button + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Button label tooltip @@ -29,6 +29,7 @@ disabledIcon 0 visitedIcon 0 armedIcon 0 hoverIcon 0 +iconGravity threeD true showBorder true hiliteBorder true @@ -60,17 +61,10 @@ textStyle textAlign center margins 4 lockLoc false -width 82 -height 22 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 82 +height::revIDESetRectProperty com.livecode.pi.dimension 22 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.tsv similarity index 83% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.tsv index 9daf1d8001..62286a863f 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Field.tsv @@ -1,8 +1,8 @@ -type field -title Field - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type field +title Field + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Field styledText tooltip @@ -20,7 +20,7 @@ showBorder true borderWidth 2 hScrollbar false vScrollbar false -scrollbarWidth 20 +scrollbarWidth 20 autoHilite true listBehavior false multipleHilites false @@ -31,7 +31,7 @@ dontSearch false layerMode behavior basicTableObject false -cellEdit false +cellEdit false maxColumnCount cellFormat false showLines false @@ -65,17 +65,10 @@ fixedLineHeight textHeight margins 8 lockLoc false -width 100 -height 21 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 100 +height::revIDESetRectProperty com.livecode.pi.dimension 21 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.tsv similarity index 81% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.tsv index 5d3cbbb2bd..65d8d1717c 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Group.tsv @@ -1,8 +1,8 @@ -type group -title Group - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type group +title Group + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name label disabled false @@ -25,7 +25,7 @@ cantDelete false sharedBehavior false backgroundBehavior false boundingRect -layerMode +layerMode Static,Dynamic,Scrolling,Container behavior foregroundColor foregroundPattern @@ -52,17 +52,11 @@ textStyle empty textAlign empty margins Basic 8 lockLoc false -width -height -location -left -top -right -bottom -layer +clipsToRect false +width::revIDESetRectProperty com.livecode.pi.dimension +height::revIDESetRectProperty com.livecode.pi.dimension dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.tsv similarity index 75% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.tsv index 933398d080..0db8391b48 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Image.tsv @@ -1,11 +1,12 @@ -type image -title Image - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type image +title Image + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name -filename +filename::revIDESetImageFilename id +size tooltip visible true dontDither false @@ -38,17 +39,10 @@ textStyle textAlign margins 8 lockLoc false -width 120 -height 120 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 120 +height::revIDESetRectProperty com.livecode.pi.dimension 120 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.tsv similarity index 84% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.tsv index 5bb885c7d8..b688989508 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LabelField.tsv @@ -1,8 +1,8 @@ -type field -title Label Field - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type field +title Label Field + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Label Field styledText text false Label: @@ -31,7 +31,7 @@ dontSearch false layerMode behavior basicTableObject false -cellEdit false +cellEdit false maxColumnCount cellFormat false showLines false @@ -65,12 +65,5 @@ fixedLineHeight textHeight margins 8 lockLoc false -width 100 -height 21 -location -left -top -right -bottom -layer -number \ No newline at end of file +width::revIDESetRectProperty com.livecode.pi.dimension 100 +height::revIDESetRectProperty com.livecode.pi.dimension 21 \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.tsv similarity index 80% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.tsv index ee2f64b93e..d526adfc11 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LineGraphic.tsv @@ -1,8 +1,9 @@ -type graphic tool - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type graphic tool + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Line +label tooltip style line rectangle,roundrect,line,oval,regular,line,curve,polygon opaque false @@ -22,7 +23,7 @@ foregroundPattern Border fill backgroundColor backgroundPattern fillGradient -strokeGradient +strokeGradient topColor topPattern bottomColor @@ -38,15 +39,8 @@ margins 8 lockLoc false width height -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.tsv similarity index 81% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.tsv index 81892f9927..ac8554ad7a 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.ListField.tsv @@ -1,11 +1,11 @@ -type field -title Scrolling List Field - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type field +title Scrolling List Field + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Scrolling List Field styledText -text false Choice 1\nChoice 2\nChoice 3 +text false Choice 1\nChoice 2\nChoice 3 tooltip disabled false visible true @@ -21,7 +21,7 @@ showBorder true borderWidth 2 hScrollbar false vScrollbar true -scrollbarWidth +scrollbarWidth autoHilite true listBehavior true multipleHilites false @@ -32,7 +32,7 @@ dontSearch false layerMode behavior basicTableObject false -cellEdit false +cellEdit false maxColumnCount cellFormat false showLines false @@ -66,17 +66,10 @@ fixedLineHeight textHeight margins 8 lockLoc false -width 250 -height 56 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 250 +height::revIDESetRectProperty com.livecode.pi.dimension 56 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.tsv similarity index 73% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.tsv index ba52d5d830..2f37232be9 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.LittleArrows.tsv @@ -1,8 +1,8 @@ -type scrollbar -title Little Arrows - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type scrollbar +title Little Arrows + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Scrollbar style scrollbar progress,scale,slider visible true @@ -10,10 +10,10 @@ disabled false traversalOn true focusBorder horizontal Horizontal,Vertical startValue empty -endValue empty -thumbPosition 0 -thumbSize 8192 -lineInc +endValue empty +thumbPosition 0 +thumbSize 8192 +lineInc pageInc false layerMode behavior @@ -38,15 +38,8 @@ margins 8 lockLoc false width 15 height 23 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.tsv similarity index 74% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.tsv index aaecd4aa19..a8e77896fb 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OptionMenu.tsv @@ -1,8 +1,8 @@ -type button -title Option Menu - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Option Menu + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Option Menu label Choice 1 tooltip @@ -13,7 +13,7 @@ visible true opaque true showName true disabled false -text Menu Items true Choice 1\nChoice 2\nChoice 3 +text Menu Items true Choice 1\nChoice 2\nChoice 3 menuLines 5 menuName layerMode @@ -26,11 +26,11 @@ armedIcon hoverIcon threeD true showBorder true -hiliteBorder true -borderWidth 2 -armBorder false false -traversalOn false false -autoHilite false false +hiliteBorder true +borderWidth 2 +armBorder false false +traversalOn false false +autoHilite false false shadow false shadowOffset 4 foregroundColor Text fill @@ -59,17 +59,10 @@ textStyle textAlign center margins 4 lockLoc false -width 102 -height 22 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 102 +height::revIDESetRectProperty com.livecode.pi.dimension 22 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.tsv similarity index 80% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.tsv index 7b8fc91c5d..84252f4c4a 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.OvalGraphic.tsv @@ -1,9 +1,10 @@ -type graphic -title Oval Graphic - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type graphic +title Oval Graphic + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Oval +label tooltip style oval rectangle,roundrect,line,oval,regular,line,curve,polygon opaque true @@ -38,15 +39,8 @@ margins 8 lockLoc false width 120 height 120 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.tsv similarity index 78% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.tsv index c49d098b15..17508f9d97 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Player.tsv @@ -1,10 +1,10 @@ -type player -title Player - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type player +title Player + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name -filename execute:get revIDESpecialFolderPath("IDE") & "/Resources/Sample.mpg" video,audio,media,all +filename execute:get revIDESpecialFolderPath("IDE") & "/Resources/Sample.mpg" video,audio,media,all tooltip alwaysBuffer false visible true @@ -16,7 +16,7 @@ startTime endTime showSelection false playSelection false -playRate +playRate looping false playLoudness 100 0,100 showBorder true @@ -51,17 +51,11 @@ textStyle textAlign margins 8 lockLoc false -width 310 -height 264 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 310 +height::revIDESetRectProperty com.livecode.pi.dimension 264 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay +mirrored diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.tsv similarity index 73% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.tsv index 2b416a7736..25350eb4a6 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PolygonGraphic.tsv @@ -1,9 +1,10 @@ -type graphic tool -title Polygon Graphic - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type graphic tool +title Polygon Graphic + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Polygon +label tooltip style polygon rectangle,roundrect,line,oval,regular,line,curve,polygon opaque false @@ -15,7 +16,7 @@ lineSize 1 dashes startArrow false endArrow false -points Basic +points Basic 0,0\n100,100 markerDrawn false markerLineSize 1 markerFilled false @@ -27,11 +28,11 @@ foregroundPattern Border fill backgroundColor backgroundPattern fillGradient -strokeGradient -hiliteColor Marker border fill -hilitePattern Marker border fill -borderColor Marker fill -borderPattern Marker fill +strokeGradient +hiliteColor Marker border fill +hilitePattern Marker border fill +borderColor Marker fill +borderPattern Marker fill topColor topPattern bottomColor @@ -47,15 +48,8 @@ margins 8 lockLoc false width 100 height 100 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.tsv similarity index 80% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.tsv index 4bc87a9524..8fb0bdb86d 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PopupMenu.tsv @@ -1,8 +1,8 @@ -type button -title Popup Menu - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Popup Menu + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name PopUp Menu label tooltip @@ -13,7 +13,7 @@ visible true opaque true showName true disabled false -text Menu Items true Choice 1\nChoice 2\nChoice 3 +text Menu Items true Choice 1\nChoice 2\nChoice 3 menuLines 5 menuName layerMode @@ -55,17 +55,10 @@ textStyle textAlign center margins 4 lockLoc false -width 102 -height 22 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 102 +height::revIDESetRectProperty com.livecode.pi.dimension 22 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.tsv similarity index 75% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.tsv index fa7f692d2a..b7dd71b5d7 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Progressbar.tsv @@ -1,16 +1,16 @@ -type scrollbar -title Progress Bar - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type scrollbar +title Progress Bar + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Progress Scrollbar style progress progress,scale,scrollbar visible true disabled false startValue -endValue +endValue thumbPosition -thumbsize 0 +thumbsize 0 layerMode behavior backgroundColor @@ -34,15 +34,8 @@ margins 4 lockLoc false width 200 height 16 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.tsv similarity index 76% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.tsv index 418411e47a..9687b9bfef 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.PulldownMenu.tsv @@ -1,8 +1,8 @@ -type button -title Pulldown Menu - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Pulldown Menu + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Pulldown Menu label tooltip @@ -13,7 +13,7 @@ visible true opaque true showName true disabled false -text Menu Items true Choice 1\nChoice 2\nChoice 3 +text Menu Items true Choice 1\nChoice 2\nChoice 3 menuLines 5 menuName layerMode @@ -28,9 +28,9 @@ threeD true showBorder true hiliteBorder true borderWidth 2 -armBorder false false -traversalOn false false -autoHilite false false +armBorder false false +traversalOn false false +autoHilite false false shadow false shadowOffset 4 foregroundColor Text fill @@ -58,17 +58,10 @@ textStyle textAlign left margins 4 lockLoc false -width 102 -height 22 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 102 +height::revIDESetRectProperty com.livecode.pi.dimension 22 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.tsv similarity index 83% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.tsv index 2400fd9f2f..7250a98c42 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RadioButton.tsv @@ -1,8 +1,8 @@ -type button -title Radio Button - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Radio Button + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Radio label tooltip @@ -20,7 +20,7 @@ showFocusBorder true mnemonic default false disabled -hilited +hilited layerMode behavior icon @@ -58,17 +58,10 @@ textStyle textAlign left margins 4 lockLoc false -width 82 -height 23 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 82 +height::revIDESetRectProperty com.livecode.pi.dimension 23 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.tsv similarity index 84% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.tsv index 642fbb2d8c..8711fc8cc7 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleButton.tsv @@ -1,8 +1,8 @@ -type button -title Rectangle Button - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Rectangle Button + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Button label tooltip @@ -28,6 +28,7 @@ disabledIcon visitedIcon armedIcon hoverIcon +iconGravity threeD true showBorder true hiliteBorder true @@ -59,17 +60,10 @@ textStyle textAlign center margins 4 lockLoc false -width 82 -height 23 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 82 +height::revIDESetRectProperty com.livecode.pi.dimension 23 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.tsv similarity index 80% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.tsv index ddef207737..47a8499952 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RectangleGraphic.tsv @@ -1,9 +1,10 @@ -type graphic +Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step +type graphic title Rectangle Graphic -Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Rectangle +label tooltip style rectangle rectangle,roundrect,line,oval,regular,line,curve,polygon opaque true @@ -20,7 +21,7 @@ foregroundPattern Border fill backgroundColor backgroundPattern fillGradient -strokeGradient +strokeGradient topColor topPattern bottomColor @@ -36,15 +37,8 @@ margins 8 lockLoc false width 120 height 120 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.tsv similarity index 78% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.tsv index a9f1c47c72..aeda873eaa 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RegularGraphic.tsv @@ -1,9 +1,10 @@ -type graphic -title Regular Polygon Graphic - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type graphic +title Regular Polygon Graphic + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Regular Polygon +label tooltip style regular rectangle,roundrect,line,oval,regular,line,curve,polygon opaque true @@ -22,7 +23,7 @@ foregroundPattern Border fill backgroundColor backgroundPattern fillGradient -strokeGradient +strokeGradient topColor topPattern bottomColor @@ -38,15 +39,8 @@ margins 8 lockLoc false width 100 height 100 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.tsv similarity index 79% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.tsv index 53e3e9340e..fc7837e7c5 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.RoundRectGraphic.tsv @@ -1,9 +1,10 @@ -type graphic -title Round Rectangle Graphic - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type graphic +title Round Rectangle Graphic + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Round Rectangle +label tooltip style roundrect rectangle,roundrect,line,oval,regular,line,curve,polygon opaque true @@ -21,7 +22,7 @@ foregroundPattern Border fill backgroundColor backgroundPattern fillGradient -strokeGradient +strokeGradient topColor topPattern bottomColor @@ -38,15 +39,8 @@ margins 8 lockLoc false width 120 height 120 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.tsv similarity index 79% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.tsv index bd48317322..2abbb51dc0 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Scrollbar.tsv @@ -1,8 +1,8 @@ -type Scrollbar -title Scrollbar - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type Scrollbar +title Scrollbar + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Scrollbar tooltip style scrollbar progress,scale,scrollbar @@ -14,7 +14,7 @@ orientation startValue 0 endValue 65535 thumbPosition 0 -thumbSize 8192 +thumbSize 8192 lineInc pageInc layerMode @@ -40,15 +40,8 @@ margins 4 lockLoc false width 200 height 20 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.tsv similarity index 72% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.tsv index fc4a0dd1b5..34dc55b89a 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Slider.tsv @@ -1,8 +1,8 @@ -type scrollbar -title Slider - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type scrollbar +title Slider + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Scrollbar style scale progress,scale,scrollbar visible @@ -11,17 +11,17 @@ traversalOn true focusBorder orientation startValue 1 -endValue +endValue thumbPosition 1 -thumbsize -showValue true +thumbsize +showValue true numberFormat pageInc 1 -lineInc false 0 +lineInc false 0 layerMode behavior -foregroundColor Text Color -foregroundPattern Text Pattern +foregroundColor Text Color +foregroundPattern Text Pattern backgroundColor backgroundPattern borderColor @@ -43,15 +43,8 @@ margins 4 lockLoc false width 100 height 38 -location -left -top -right -bottom -layer dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.tsv similarity index 81% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.tsv index 29192a289b..e783fb84d5 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Stack.tsv @@ -1,11 +1,11 @@ -type stack -title Stack - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type stack +title Stack + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name -title -mainStack execute:get revIDEMainstackPropertyOptions() +title +mainStack decorations style Toplevel,Modeless,Modal,Palette windowShape @@ -19,11 +19,10 @@ startupIconic false destroyStack false destroyWindow false cantDelete false -cantModify false cantAbort false stackFiles -externalReferences -behavior +externals +behavior foregroundColor foregroundPattern backgroundColor @@ -41,8 +40,8 @@ shadowPattern focusColor focusPattern linkColor -clickColor -visitedColor +linkHiliteColor +linkVisitedColor underlineLinks true customProperties blendLevel 0 0,100 @@ -59,4 +58,3 @@ minWidth 32 minHeight 32 maxWidth 65535 maxHeight 65535 -behavior diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Substack.tsv b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Substack.tsv new file mode 100644 index 0000000000..1dd332f375 --- /dev/null +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.Substack.tsv @@ -0,0 +1,61 @@ +Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step +type stack +title Substack + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +name +title +mainStack +makeMainstack::revIDEMakeSubstackMainstack Make mainstack Basic com.livecode.pi.action true true +decorations +windowShape +scaleFactor 1 +shadow Basic true +visible true +formatForPrinting false +systemWindow false +iconic false +startupIconic false +destroyStack false +destroyWindow false +cantDelete false +cantModify false +cantAbort false +stackFiles true +externals +behavior +foregroundColor +foregroundPattern +backgroundColor +backgroundPattern +hiliteColor +hilitePattern +borderColor +borderPattern +topColor +topPattern +bottomColor +bottomPattern +shadowColor +shadowPattern +focusColor +focusPattern +linkColor +clickColor +visitedColor +underlineLinks true +customProperties +blendLevel 0 0,100 +ink +textFont +textSize +textStyle +textAlign empty +resizable true +width 400 +height 400 +location +minWidth 32 +minHeight 32 +maxWidth 65535 +maxHeight 65535 \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.tsv similarity index 75% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.tsv index 37e313a621..0747d52c04 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TabPanel.tsv @@ -1,15 +1,15 @@ -type button -title Tab Panel - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type button +title Tab Panel + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Tab Menu label tooltip visible true disabled false showName false -text Tabs (one per line) true Tab 1\nTab 2\nTab 3 +text Tabs (one per line) true Tab 1\nTab 2\nTab 3 layerMode behavior foregroundColor Text fill @@ -37,19 +37,12 @@ textStyle textAlign center margins 4 lockLoc false -width 234 -height 144 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 234 +height::revIDESetRectProperty com.livecode.pi.dimension 144 style false menu menumode false tabbed dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.tsv similarity index 80% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.tsv index 8922c7006c..ec054d9931 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TableField.tsv @@ -1,8 +1,8 @@ -type field -title Table Field - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type field +title Table Field + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Table Field styledText text @@ -21,18 +21,18 @@ showBorder true borderWidth 2 hScrollbar false vScrollbar true -scrollbarWidth +scrollbarWidth autoHilite true listBehavior false multipleHilites false nonContiguousHilites false -toggleHilites false +toggleHilites false firstIndent 0 dontSearch false layerMode behavior basicTableObject true -cellEdit true +cellEdit true maxColumnCount cellFormat false showLines false @@ -62,21 +62,14 @@ textFont textSize textStyle textAlign left -fixedLineHeight +fixedLineHeight true textHeight margins 8 lockLoc false -width 250 -height 56 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 250 +height::revIDESetRectProperty com.livecode.pi.dimension 56 dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.tsv similarity index 84% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.tsv index 89342fde2e..ff1117d79e 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.TextArea.tsv @@ -1,8 +1,8 @@ -type field -title Scrolling Field - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type field +title Scrolling Field + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Field styledText tooltip @@ -20,7 +20,7 @@ showBorder true borderWidth 2 hScrollbar false vScrollbar true -scrollbarWidth +scrollbarWidth autoHilite true listBehavior false multipleHilites false @@ -31,7 +31,7 @@ dontSearch false layerMode behavior basicTableObject false -cellEdit false +cellEdit false maxColumnCount cellFormat false showLines false @@ -65,14 +65,8 @@ fixedLineHeight textHeight margins 8 lockLoc false -width 250 -height 56 -location -left -top -right -bottom -layer +width::revIDESetRectProperty com.livecode.pi.dimension 250 +height::revIDESetRectProperty com.livecode.pi.dimension 56 basicTableObject false maxEditableColumns cellFormatting false @@ -84,5 +78,4 @@ dropShadow innerShadow outerGlow innerGlow -colorOverlay -number \ No newline at end of file +colorOverlay \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.txt b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.tsv similarity index 61% rename from Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.txt rename to Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.tsv index 6d05ffdf53..f49d1f8b00 100644 --- a/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.txt +++ b/Toolset/resources/supporting_files/property_definitions/com.livecode.interface.classic.widget.tsv @@ -1,7 +1,7 @@ -type widget - Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ----------------------------------------------------------------------------------------------------- +type widget + +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- name Widget kind tooltip @@ -15,13 +15,6 @@ blendLevel 0 0,100 lockLoc false width no_default height no_default -location -left -top -right -bottom -layer -textFont +textFont textSize -traversalOn Advanced false -number \ No newline at end of file +traversalOn Advanced false \ No newline at end of file diff --git a/Toolset/resources/supporting_files/property_definitions/propertyInfo.txt b/Toolset/resources/supporting_files/property_definitions/propertyInfo.tsv similarity index 83% rename from Toolset/resources/supporting_files/property_definitions/propertyInfo.txt rename to Toolset/resources/supporting_files/property_definitions/propertyInfo.tsv index 3251e254bd..f27d8a4e61 100644 --- a/Toolset/resources/supporting_files/property_definitions/propertyInfo.txt +++ b/Toolset/resources/supporting_files/property_definitions/propertyInfo.tsv @@ -1,9 +1,9 @@ Property : optional getter : optional setter Label Section Editor User Visible Read Only Group Default Options Subsection min max step ---------------------------------------------------------------------------------------------------------------------- -alwaysBuffer Buffer Basic com.livecode.pi.boolean true false false +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +alwaysBuffer Buffer Basic com.livecode.pi.boolean true false false angle Rotation Basic com.livecode.pi.number true false 0 0 359 1 antialiased Antialiased Basic com.livecode.pi.boolean true false -arcAngle Arc Basic com.livecode.pi.number true false +arcAngle Arc Basic com.livecode.pi.number true false 0 360 1 armedIcon Armed icon Icons com.livecode.pi.imageid true false 0 autoHilite Auto hilite Basic com.livecode.pi.boolean true false autoTab Tab on return Basic com.livecode.pi.boolean true false @@ -16,7 +16,7 @@ blendLevel Blend level Colors com.livecode.pi.number true false 0 100 1 borderColor Border/grid color Colors com.livecode.pi.color true false Border fill borderPattern Border/grid pattern Colors com.livecode.pi.pattern true false Border fill borderWidth Border width Basic com.livecode.pi.integer true false 0 1 -bottom Bottom Position com.livecode.pi.integer true false no_default 1 +bottom::revIDESetRectProperty Bottom Position com.livecode.pi.integer true false no_default 1 bottomColor Inset bevel color Colors com.livecode.pi.color true false Bottom bevel fill bottomPattern Inset bevel pattern Colors com.livecode.pi.pattern true false Bottom bevel fill boundingRect Bounding rect Basic com.livecode.pi.string true false @@ -26,54 +26,54 @@ cantDelete Can't delete Basic com.livecode.pi.boolean true false false cantModify Can't modify Basic com.livecode.pi.boolean true false false cellEdit:revIDEGetTableProperty:revIDESetTableProperty Cell editing Table com.livecode.pi.boolean true false false cellFormat:revIDEGetTableProperty:revIDESetTableProperty Cell formatting Table com.livecode.pi.boolean true false false -clickColor Click color Colors com.livecode.pi.color true false +clipsToRect Clip child controls to rect Position com.livecode.pi.boolean true false false colorOverlay Color overlay Effects com.livecode.pi.graphicEffect true false popup:effectColor,effectBlendMode currentFrame Frame Basic com.livecode.pi.integer true false 1 1 1 currentNode Current node Quicktime com.livecode.pi.string true false currentTime Time Basic com.livecode.pi.integer true false 0 0 1 -customProperties:revIDECustomPropertiesGet:revIDECustomPropertiesSet Custom Properties Custom com.livecode.pi.customprops true false no_default -dashes Dashed lines Basic com.livecode.pi.string true false -decorations Controls Basic com.livecode.pi.decorations true false -default Default button Basic com.livecode.pi.boolean true false -destroyStack Purge stack on close Basic com.livecode.pi.boolean true false false -destroyWindow Purge window on close Basic com.livecode.pi.boolean true false false -disabled Disabled Basic com.livecode.pi.boolean true false false -disabledIcon Disabled icon Icons com.livecode.pi.imageid true false 0 -dontDither Don't dither Basic com.livecode.pi.boolean true false false -dontSearch Don't search Basic com.livecode.pi.boolean true false false -dontWrap Don't wrap Basic com.livecode.pi.boolean true false -dropShadow Drop shadow Effects com.livecode.pi.graphicEffect true false popup:effectColor,effectBlendMode,effectFilter,effectSize,effectSpread,effectDistance,effectAngle +customProperties:revIDECustomPropertiesGet:revIDECustomPropertiesSet Custom Properties Custom com.livecode.pi.customprops true false no_default +dashes Dashed lines Basic com.livecode.pi.string true false +decorations Controls Basic com.livecode.pi.decorations true false +default Default button Basic com.livecode.pi.boolean true false +destroyStack Purge stack on close Basic com.livecode.pi.boolean true false false +destroyWindow Purge window on close Basic com.livecode.pi.boolean true false false +disabled Disabled Basic com.livecode.pi.boolean true false false +disabledIcon Disabled icon Icons com.livecode.pi.imageid true false 0 +dontDither Don't dither Basic com.livecode.pi.boolean true false false +dontSearch Don't search Basic com.livecode.pi.boolean true false false +dontWrap Don't wrap Basic com.livecode.pi.boolean true false +dropShadow Drop shadow Effects com.livecode.pi.graphicEffect true false popup:effectColor,effectBlendMode,effectFilter,effectSize,effectSpread,effectDistance,effectAngle effectAngle Angle Effects com.livecode.pi.number true false 0 360 1 -effectBlendMode Blend mode Effects com.livecode.pi.enum true false normal normal,multiply,colorDodge -effectColor Color Effects com.livecode.pi.colorwithalpha true false 0,0,0,255 +effectBlendMode Blend mode Effects com.livecode.pi.enum true false normal normal,multiply,colorDodge +effectColor Color Effects com.livecode.pi.colorwithalpha true false 0,0,0,255 effectDistance Distance Effects com.livecode.pi.number true false 3 0 359 1 -effectFilter Filter Effects com.livecode.pi.enum true false box3pass gaussian,box3pass,box2pass,box1pass +effectFilter Filter Effects com.livecode.pi.enum true false box3pass gaussian,box3pass,box2pass,box1pass effectSize Size Effects com.livecode.pi.number true false 3 0 255 1 effectSpread Spread Effects com.livecode.pi.number true false 0 0 255 1 -enabledTracks Track is enabled Tracks com.livecode.pi.text true true -endArrow End arrow Basic com.livecode.pi.boolean true false false -endTime End Basic com.livecode.pi.integer true false 0 1 -endValue End value Basic com.livecode.pi.number true false 100 1 -externalReferences External references externalRefs com.livecode.pi.text true false -filename Source Basic com.livecode.pi.file true false -fillGradient::revIDESetGradientProperty Fill gradient Colors com.livecode.pi.gradient true false Background fill popup:gradientType,gradientRamp,gradientQuality,gradientRepeat,gradientMirror,gradientWrap -firstIndent First indent Basic com.livecode.pi.integer true false 0 1 -fixedLineHeight Fixed line height Text com.livecode.pi.boolean true false false -focusBorder Focus border Basic com.livecode.pi.boolean true false -focusColor Focus color Colors com.livecode.pi.color true false Focus fill -focusPattern Focus pattern Colors com.livecode.pi.pattern true false Focus fill -foregroundColor Text color Colors com.livecode.pi.color true false Foreground fill -foregroundPattern Text pattern Colors com.livecode.pi.pattern true false Foreground fill -formatForPrinting Format for printing Basic com.livecode.pi.boolean true false -gradientType Type Gradients com.livecode.pi.enum true false No Gradient No Gradient,Linear,Radial,Conical,Diamond,Spiral,XY,SqrtXY -gradientRamp Ramp Gradients com.livecode.pi.gradientramp true false -gradientFrom From Gradients com.livecode.pi.number true false -gradientTo To Gradients com.livecode.pi.number true false -gradientVia Via Gradients com.livecode.pi.number true false -gradientQuality Quality Gradients com.livecode.pi.enum true false Normal Normal,Good +enabledTracks Track is enabled Tracks com.livecode.pi.text true true +endArrow End arrow Basic com.livecode.pi.boolean true false false +endTime End Basic com.livecode.pi.integer true false 0 1 +endValue End value Basic com.livecode.pi.number true false 100 1 +externals External references externalRefs com.livecode.pi.text true false +filename Source Basic com.livecode.pi.file true false +fillGradient::revIDESetGradientProperty Fill gradient Colors com.livecode.pi.gradient true false popup:gradientType,gradientRamp,gradientQuality,gradientRepeat,gradientMirror,gradientWrap +firstIndent First indent Basic com.livecode.pi.integer true false 0 1 +fixedLineHeight Fixed line height Text com.livecode.pi.boolean true false false +focusBorder Focus border Basic com.livecode.pi.boolean true false +focusColor Focus color Colors com.livecode.pi.color true false Focus fill +focusPattern Focus pattern Colors com.livecode.pi.pattern true false Focus fill +foregroundColor Text color Colors com.livecode.pi.color true false Foreground fill +foregroundPattern Text pattern Colors com.livecode.pi.pattern true false Foreground fill +formatForPrinting Format for printing Basic com.livecode.pi.boolean true false +gradientType Type Gradients com.livecode.pi.enum true false No Gradient No Gradient,Linear,Radial,Conical,Diamond,Spiral,XY,SqrtXY +gradientRamp Ramp Gradients com.livecode.pi.gradientramp true false +gradientFrom From Gradients com.livecode.pi.number true false +gradientTo To Gradients com.livecode.pi.number true false +gradientVia Via Gradients com.livecode.pi.number true false +gradientQuality Quality Gradients com.livecode.pi.enum true false Normal Normal,Good gradientRepeat Repeat Gradients com.livecode.pi.integer true false 0 1 -gradientMirror Mirror Gradients com.livecode.pi.boolean true false false -gradientWrap Wrap Gradients com.livecode.pi.boolean true false false +gradientMirror Mirror Gradients com.livecode.pi.boolean true false false +gradientWrap Wrap Gradients com.livecode.pi.boolean true false false height Height Position com.livecode.pi.integer true false 1 1 hGrid Horizontal grid Table com.livecode.pi.boolean true false hilited Hilited Basic com.livecode.pi.boolean true false false @@ -86,30 +86,33 @@ hotspots Hotspots Quicktime com.livecode.pi.string true true hoverIcon Hover icon Icons com.livecode.pi.imageid true false 0 hScrollbar Horizontal scrollbar Basic com.livecode.pi.boolean true false false icon Icon Icons com.livecode.pi.imageid true false 0 +iconGravity Gravity Icons com.livecode.pi.enum true false ,left,top,right,bottom,topLeft,topRight,bottomLeft,bottomRight,center,resize iconic Minimized Basic com.livecode.pi.boolean true false false -id ID Basic com.livecode.pi.image_id true false -ink Ink Colors com.livecode.pi.enum true false srcCopy blendClear,blendSrc,blendDst,blendSrcOver,blendDstOver,blendSrcIn,blendDstIn,blendSrcOut,blendDstOut,blendSrcAtop,blendDstAtop,blendXor,blendPlus,blendMultiply,blendScreen,blendOverlay,blendDarken,blendLighten,blendDodge,blendBurn,blendHardLight,blendSoftLight,blendDifference,blendExclusion,clear,noop,notSrcAnd,notSrcAndReverse,notSrcCopy,notSrcOr,notSrcOrReverse,notSrcXor,reverse,set,srcAnd,srcAndReverse,srcCopy,srcOr,srcOrReverse,srcXor,blend,addPin,addOver,subPin,transparent,adMin,addMax +id ID Basic com.livecode.pi.imageID true false +ink Ink Colors com.livecode.pi.enum true false srcCopy blendClear,blendSrc,blendDst,blendSrcOver,blendDstOver,blendSrcIn,blendDstIn,blendSrcOut,blendDstOut,blendSrcAtop,blendDstAtop,blendXor,blendPlus,blendMultiply,blendScreen,blendOverlay,blendDarken,blendLighten,blendDodge,blendBurn,blendHardLight,blendSoftLight,blendDifference,blendExclusion,srcCopy innerGlow Inner glow Effects com.livecode.pi.graphicEffect true false popup:effectColor,effectBlendMode,effectFilter,effectSize,effectSpread innerShadow Inner shadow Effects com.livecode.pi.graphicEffect true false popup:effectColor,effectBlendMode,effectFilter,effectSize,effectSpread,effectDistance,effectAngle kind Kind Basic com.livecode.pi.string true true no_default label Label Basic com.livecode.pi.text true false layer Layer Position com.livecode.pi.integer true false no_default 1 1 -layerMode Layer mode Advanced com.livecode.pi.enum true false Static Static,Dynamic,Scrolling -left Left Position com.livecode.pi.integer true false no_default 1 +layerMode Layer mode Advanced com.livecode.pi.enum true false Static Static,Dynamic +left::revIDESetRectProperty Left Position com.livecode.pi.integer true false no_default 1 lineInc Scroll distance on arrow click Basic com.livecode.pi.number true false 512 lineSize Line thickness Basic com.livecode.pi.number true false 1 linkColor Link color Colors com.livecode.pi.color true false +linkHiliteColor Link click color Colors com.livecode.pi.color true false +linkVisitedColor Link visited color Colors com.livecode.pi.color true false listBehavior List behavior Basic com.livecode.pi.boolean true false location Location Position com.livecode.pi.point true false no_default lockLoc Lock size and position Position com.livecode.pi.boolean true false false lockText Lock text Basic com.livecode.pi.boolean true false looping Loop Basic com.livecode.pi.boolean true false false -mainStack Main stack Basic com.livecode.pi.enum true false execute:get revIDEMainstackPropertyOptions() +mainStack Main stack Basic com.livecode.pi.enum true false execute:get ideMainStacks(); sort it margins Margins Text com.livecode.pi.string true false mark Marked Basic com.livecode.pi.boolean true false false markerDrawn Draw shape at vertices Basic com.livecode.pi.boolean true false false markerFilled Marker filled Basic com.livecode.pi.boolean true false false -markerLineSize Marker line thickness Basic com.livecode.pi.nubmber true false 1 +markerLineSize Marker line thickness Basic com.livecode.pi.number true false 1 markerPoints Marker points Basic com.livecode.pi.text true false maxColumnCount:revIDEGetTableProperty:revIDESetTableProperty Maximum editable column Table com.livecode.pi.number true false maxHeight Max height Position com.livecode.pi.number true false 65535 @@ -120,7 +123,8 @@ menuMouseButton Access with mouse button: Basic com.livecode.pi.enum true false menuName Menu panel stack Basic com.livecode.pi.string true false minHeight Min height Position com.livecode.pi.number true false 32 minWidth Min width Position com.livecode.pi.number true false 32 -multipleHilites Multi-line Basic com.livecode.pi.boolean true false false +mirrored Mirrored Basic com.livecode.pi.boolean true false false +multipleHilites Multiline Hilites Basic com.livecode.pi.boolean true false false name Name Basic com.livecode.pi.string true false no_default nonContiguousHilites Non-contiguous Basic com.livecode.pi.boolean true false number Number Advanced com.livecode.pi.integer true true no_default 1 1 @@ -141,13 +145,13 @@ radioBehavior Hilite one radio button at a time Basic com.livecode.pi.boolean tr repeatCount Repeat Basic com.livecode.pi.integer true false 0 1 resizable Resizable Position com.livecode.pi.boolean true false true resizeQuality Resize quality Basic com.livecode.pi.enum true false normal best,good,normal -right Right Position com.livecode.pi.integer true false no_default 1 -roundRadius Corner radius Basic com.livecode.pi.number true false -scaleFactor Scale factor Basic com.livecode.pi.number true false -scrollbarWidth Scrollbar width Basic com.livecode.pi.enum true false 16 12,16,20 -selectGroupedControls Select grouped controls Basic com.livecode.pi.boolean true false true -shadow Shadow Icons com.livecode.pi.boolean true false -shadowColor Shadow color Colors com.livecode.pi.color true false Shadow fill +right::revIDESetRectProperty Right Position com.livecode.pi.integer true false no_default 1 +roundRadius Corner radius Basic com.livecode.pi.number true false +scaleFactor Scale factor Basic com.livecode.pi.number true false +scrollbarWidth Scrollbar width Basic com.livecode.pi.enum true false 16 12,16,20 +selectGroupedControls Select grouped controls Basic com.livecode.pi.boolean true false true +shadow Shadow Icons com.livecode.pi.boolean true false +shadowColor Shadow color Colors com.livecode.pi.color true false Shadow fill shadowOffset Shadow offset Icons com.livecode.pi.integer true false 4 -128 127 1 shadowPattern Shadow pattern Colors com.livecode.pi.pattern true false Shadow fill sharedBehavior Shared group Basic com.livecode.pi.boolean true false false @@ -161,8 +165,9 @@ showLines Text baselines Table com.livecode.pi.boolean true false showName Show name Basic com.livecode.pi.boolean true false showSelection Hilite selection Basic com.livecode.pi.boolean true false showValue Show value Basic com.livecode.pi.boolean true false false +size Size in bytes Basic com.livecode.pi.integer true true stackFiles::revIDESetStackFilesProperty Stack files Stack Files com.livecode.pi.stackfiles true false -startAngle Start Basic com.livecode.pi.number true false +startAngle Start Basic com.livecode.pi.number true false 0 0 360 1 startArrow Start arrow Basic com.livecode.pi.boolean true false startTime Start Basic com.livecode.pi.integer true false 0 1 startupIconic Open minimized Basic com.livecode.pi.boolean true false @@ -173,7 +178,7 @@ styledText Contents Contents com.livecode.pi.styledText true false no_default systemWindow Float above everything Basic com.livecode.pi.boolean true false false tabGroupBehavior Contents focus with keyboard Basic com.livecode.pi.boolean true false false tabStops Tab stops Table com.livecode.pi.string true false -text Text Basic com.livecode.pi.text false false +text Text Basic com.livecode.pi.text false false tabStops|15 textAlign Text align Text com.livecode.pi.textalign true false textFont Font Text com.livecode.pi.font true false textHeight Text height Text com.livecode.pi.integer true false 4 1 @@ -187,8 +192,8 @@ thumbSize Thumb size Basic com.livecode.pi.number false false 1 tilt Tilt Quicktime com.livecode.pi.number true false title Title Basic com.livecode.pi.string true false toggleHilites Click to toggle Basic com.livecode.pi.boolean true false false -tooltip Tooltip Basic com.livecode.pi.string true false -top Top Position com.livecode.pi.integer true false no_default 1 +tooltip Tooltip Basic com.livecode.pi.text true false +top::revIDESetRectProperty Top Position com.livecode.pi.integer true false no_default 1 topColor Outset bevel color Colors com.livecode.pi.color true false Top bevel fill topPattern Outset bevel pattern Colors com.livecode.pi.pattern true false Top bevel fill tracks Tracks Tracks com.livecode.pi.text true true @@ -196,7 +201,6 @@ traversalOn Focus with keyboard Basic com.livecode.pi.boolean true false underlineLinks Underline links Colors com.livecode.pi.boolean true false true vGrid Vertical grid Table com.livecode.pi.boolean true false visible Visible Basic com.livecode.pi.boolean true false true -visitedColor Visited color Colors com.livecode.pi.color true false visitedIcon Visited icon Icons com.livecode.pi.imageid true false 0 vScrollbar Vertical scrollbar Basic com.livecode.pi.boolean true false false width Width Position com.livecode.pi.integer true false 1 1 diff --git a/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.tsv b/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.tsv new file mode 100644 index 0000000000..656997667e --- /dev/null +++ b/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.tsv @@ -0,0 +1,146 @@ +Property Label Section Editor User Visible Read Only Group Default Options Subsection +----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- +name Standalone name General com.livecode.pi.string TRUE FALSE Name +inclusions General com.livecode.pi.radiogroup TRUE FALSE Inclusions search Search for required inclusions when saving the application|search,Select inclusions for the standalone application|select Inclusions +askDialog Ask Dialog General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +answerDialog Answer Dialog General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +cursors Cursors General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +revolutionprintdialogs Print Dialogs General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +Brushes Brushes General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +pdfPrinter PDF Printer General com.livecode.pi.boolean TRUE FALSE Inclusion Options Inclusions +scriptLibraries Script Libraries General com.livecode.pi.set TRUE FALSE execute:dispatch function "revSBLibraryList" to stack "revSBLibrary";get the result;sort it Inclusions +databaseSupport Database Drivers General com.livecode.pi.boolean TRUE FALSE Inclusions +databaseDrivers Database Drivers General com.livecode.pi.set TRUE FALSE execute:get revDatabaseDriverList() Inclusions +extensions Extensions to include General com.livecode.pi.set TRUE FALSE execute: get the loadedExtensions; sort it Inclusions +setToProfile Set to profile General com.livecode.pi.radiogroup TRUE FALSE remove Remove all profiles on objects|remove,Set all objects to profile|set,Include all profiles on objects and the profile library|all,Include selected profiles on objects and the profile library|selected Property Profiles +includeProfiles Profiles to include General com.livecode.pi.enum TRUE FALSE Property Profiles +defaultBuildFolder Default Build Folder General com.livecode.pi.file TRUE FALSE Default Build Folder Default Build Folder +automaticallyBuildInDefaultFolder Automatically build here General com.livecode.pi.boolean TRUE FALSE Default Build Folder Default Build Folder + +destroyStack Set destroyStack property to true for the selected stack Stacks com.livecode.pi.boolean TRUE FALSE For the selected stack +moveSubstacks Move substacks into individual stackfiles Stacks com.livecode.pi.string TRUE FALSE For the selected stack file +password Encrypt with password: Stacks com.livecode.pi.string TRUE FALSE For the selected stack +renameGeneric Stacks com.livecode.pi.boolean TRUE FALSE For the selected stack file +substackFolder Stacks com.livecode.pi.boolean TRUE FALSE For the selected stack file +files Non-stack files Copy Files com.livecode.pi.filelist TRUE FALSE Non-stack files in the application +CopyReferencedFiles Copy Referenced Files Copy Files com.livecode.pi.boolean TRUE FALSE Non-stack files in the application +ReferencedFilesDestination Destination Folder Copy Files com.livecode.pi.string TRUE FALSE Non-stack files in the application +MacOSX x86-32 Mac com.livecode.pi.boolean TRUE FALSE Build for Mac OS X (Intel) +OSX,iconFile Application Icon File Mac com.livecode.pi.file TRUE FALSE Icons +OSX,documenticonFile Document Icon File Mac com.livecode.pi.file TRUE FALSE Icons +OSX,appicon Application Icon Mac com.livecode.pi.icon TRUE FALSE Ask / answer dialog icons +OSX,smallappicon Small Application Icon Mac com.livecode.pi.icon TRUE FALSE Ask / answer dialog icons +OSX,plist Mac com.livecode.pi.boolean TRUE FALSE Enter the information and have LiveCode write the PLIST file for you Enter the information and have LiveCode write the PLIST file for you,Choose a PLIST file to import into the application bundle PLIST +OSX,name Name Mac com.livecode.pi.string TRUE FALSE PLIST +OSX,signature Signature Mac com.livecode.pi.string TRUE FALSE PLIST +OSX,documentType Document Type Mac com.livecode.pi.string TRUE FALSE PLIST +OSX,documentExtension Document Extension Mac com.livecode.pi.string TRUE FALSE PLIST +OSX,shortVersion Short Version Mac com.livecode.pi.string TRUE FALSE Version Information +OSX,longVersion Long Version Mac com.livecode.pi.string TRUE FALSE Version Information +OSX,info Get Info String Mac com.livecode.pi.string TRUE FALSE Version Information +OSX,copyright Copyright Notice Mac com.livecode.pi.string TRUE FALSE Version Information +OSX,identifier Bundle Identifier Mac com.livecode.pi.string TRUE FALSE Version Information +Windows Windows com.livecode.pi.boolean TRUE FALSE Build for Windows +Windows,iconFile Application Icon Windows com.livecode.pi.file TRUE FALSE Icon +Windows,documenticonFile Document Icon Windows com.livecode.pi.file TRUE FALSE Icon +Windows,fileDescription File Description Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,LegalCopyright Copyright Notice Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,comments Comments Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,legalTrademarks Legal Trademarks Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,ProductName Product Name Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,companyname Company Name Windows com.livecode.pi.string TRUE FALSE Version Information + +Windows,fileversion1 Windows com.livecode.pi.number TRUE FALSE File Version Version Information +Windows,fileversion2 . Windows com.livecode.pi.number TRUE FALSE File Version Version Information +Windows,fileversion3 . Windows com.livecode.pi.number TRUE FALSE File Version Version Information +Windows,fileversion4 . Windows com.livecode.pi.number TRUE FALSE File Version Version Information +Windows,productversion1 Windows com.livecode.pi.number TRUE FALSE Product Version Version Information +Windows,productversion2 . Windows com.livecode.pi.number TRUE FALSE Product Version Version Information +Windows,productversion3 . Windows com.livecode.pi.number TRUE FALSE Product Version Version Information +Windows,productversion4 . Windows com.livecode.pi.number TRUE FALSE Product Version Version Information +Windows,originalFilename Original Filename Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,internalName Internal Name Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,privateBuild Private Build Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,specialBuild Special Build Windows com.livecode.pi.string TRUE FALSE Version Information +Windows,uacExecutionLevel Execution Level Windows com.livecode.pi.enum TRUE FALSE Default|,Same as invoker|asInvoker,Highest Available|highestAvailable,Request Administrator|requestAdministrator UAC Execution Level +Windows,usePixelScaling Enable Hi-DPI scaling Windows com.livecode.pi.boolean TRUE FALSE Hi-DPI support +#Windows,UUID UUID Windows com.livecode.pi.string TRUE FALSE UUID +Linux Linux Linux com.livecode.pi.boolean TRUE FALSE Build for: +Linux ARMv6-HF Linux ARMv6-HF Linux com.livecode.pi.boolean TRUE FALSE Build for: +Linux x64 Linux x64 Linux com.livecode.pi.boolean TRUE FALSE Build for: +UNIX,colorChooser Unix Color Chooser Linux com.livecode.pi.boolean TRUE FALSE Inclusions Inclusions +UNIX,fileSelector Unix File Selector Linux com.livecode.pi.boolean TRUE FALSE Inclusions Inclusions +UNIX,pageSetup Unix Page Setup Linux com.livecode.pi.boolean TRUE FALSE Inclusions Inclusions +UNIX,printerChooser Unix Printer Chooser Linux com.livecode.pi.boolean TRUE FALSE Inclusions Inclusions +ios Build for iOS iOS com.livecode.pi.boolean TRUE FALSE +ios,device family Device Family iOS com.livecode.pi.set TRUE FALSE 1 iPod and iPhone|1,iPad|2 Build Settings +ios,minimum version Minimum Version iOS com.livecode.pi.enum TRUE FALSE 5.1.1 5.1.1 or later|5.1.1,6.0 or later|6.0,6.1 or later|6.1,7.0 or later|7.0,7.1 or later|7.1,8.0 or later|8.0,8.1 or later|8.1,8.2 or later|8.2 Build Settings +ios,display name Display Name iOS com.livecode.pi.string TRUE FALSE Basic Application Settings +ios,bundle version Version iOS com.livecode.pi.string TRUE FALSE Basic Application Settings +ios,bundle id Internal App ID iOS com.livecode.pi.string TRUE FALSE Basic Application Settings +ios,profile Profile iOS com.livecode.pi.enum TRUE FALSE Basic Application Settings +ios,include revzip revZip iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,include revxml revXML iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,include dbsqlite SQLite iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,include dbmysql MySQL iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,include revpdfprinter PDF Printing iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,include revsecurity Encryption iOS com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +ios,status bar hidden iPhone Status Bar iOS com.livecode.pi.radiogroup TRUE FALSE Status Bar FALSE Visible|false,Hidden|true Status Bar +ios,iPad status bar hidden iPad Status Bar iOS com.livecode.pi.radiogroup TRUE FALSE Status Bar FALSE Visible|false,Hidden|true Status Bar +ios,status bar style Status Bar Style iOS com.livecode.pi.enum TRUE FALSE Default Default|Default,Black Opaque|BlackOpaque,Black Translucent|BlackTranslucent,Solid|Solid Status Bar +ios,iphone initial orientation iPhone Initial Orientation iOS com.livecode.pi.enum TRUE FALSE Portrait Portrait|Portrait,Portrait Upside-Down|PortraitUpsideDown,Landscape Left|LandscapeLeft,Landscape Right|LandscapeRight Orientation Options +ios,ipad initial orientations iPad Supported Initial Orientations iOS com.livecode.pi.set TRUE FALSE Portrait Portrait|Portrait,Portrait Upside-Down|PortraitUpsideDown,Landscape Left|LandscapeLeft,Landscape Right|LandscapeRight Orientation Options +ios,url name URL Name iOS com.livecode.pi.string TRUE FALSE Custom URL Scheme +ios,location auth type Authorize iOS com.livecode.pi.radiogroup TRUE FALSE Always Always,When In Use Location Authorization Type +ios,persistent wifi Persistent WiFi iOS com.livecode.pi.boolean TRUE FALSE Allow FALSE Requirements and Restrictions +ios,file sharing File Sharing iOS com.livecode.pi.boolean TRUE FALSE Allow FALSE Requirements and Restrictions +ios,local notifications Local Notifications iOS com.livecode.pi.boolean TRUE FALSE Allow FALSE Requirements and Restrictions +ios,push notifications Push Notifications iOS com.livecode.pi.boolean TRUE FALSE Allow FALSE Requirements and Restrictions +ios,device capabilities Capabilities iOS com.livecode.pi.multiplechoice TRUE FALSE n/a Required|true,Prohibited|false,n/a:Telephony|telephony,Peer-Peer|peer-peer,SMS|sms,Still Camera|still-camera,Auto-Focus Camera|auto-focus-camera,Front-Facing Camera|front-facing-camera,Camera Flash|camera-flash,Video Camera|video-camera,Accelerometer|accelerometer,Gyroscope|gyroscope,Location Services|location-services,GPS|gps,Magnetometer|magnetometer,Microphone|microphone,Game-Kit|gamekit,WiFi|wifi,OpenGL ES 1.1|opengles-1,OpenGL ES 2.0|opengles-2 Requirements and Restrictions +ios,prerendered icon Prerendered Icon iOS com.livecode.pi.boolean TRUE FALSE Icons +ios,iphone icon iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,retina icon Hi-Res iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,iOS 7 retina icon iOS 7 Hi-Res iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,iPhone 6 Plus icon iPhone 6 Plus iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,ipad icon iPad iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,ipad retina icon Hi-Res iPad iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,iOS 7 ipad icon iOS 7 iPad iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,iOS 7 ipad retina icon iOS 7 Hi-Res iPad iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Icons +ios,iphone splash iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,retina splash Hi-Res iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,iphone 4inch splash icon 4 Inch iPhone iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,iphone 6 splash iPhone 6 iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,iPhone 6 Plus Portrait splash iPhone 6 Plus Portrait iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,iPhone 6 Plus Landscape splash iPhone 6 Plus Landscape iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,ipad portrait splash iPad Portrait iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,ipad landscape splash iPad Landscape iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,ipad retina portrait splash Hi-Res iPad Portrait iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens +ios,ipad retina landscape splash Hi-Res iPad Landscape iOS com.livecode.pi.file TRUE FALSE PNG Images|png,All files Splash Screens + +android Build for Android Android com.livecode.pi.boolean TRUE FALSE +android,label Label Android com.livecode.pi.string TRUE FALSE Basic Application Settings +android,identifier Identifier Android com.livecode.pi.string TRUE FALSE Basic Application Settings +android,version name Version Name Android com.livecode.pi.string TRUE FALSE Basic Application Settings +android,version code Version Code Android com.livecode.pi.string TRUE FALSE Basic Application Settings +android,icon Icon Android com.livecode.pi.file TRUE FALSE PNG Images|png,All files Basic Application Settings +android,splash Splash Android com.livecode.pi.file TRUE FALSE PNG Images|png,All files Basic Application Settings +android,signing Signing Android com.livecode.pi.enum TRUE FALSE Sign with my key Sign with my key,Sign for development only,Do not sign Basic Application Settings +android,key Key Android com.livecode.pi.file TRUE FALSE Java keystores|keystore,All files Basic Application Settings +android,install location Install Location com.livecode.pi.enum TRUE FALSE Internal Storage Only Internal Storage Only,Allow External Storage,Prefer External Storage Basic Application Settings +android,include revzip revZip Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,include revxml revXML Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,include dbsqlite SQLite Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,include dbmysql MySQL Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,include revpdfprinter PDF Printing Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,include revsecurity SSL & Encryption Android com.livecode.pi.boolean TRUE FALSE Externals FALSE Basic Application Settings +android,customUrlScheme URL Name Android com.livecode.pi.string TRUE FALSE Custom URL Scheme +android,pushSenderID Push Sender ID Android com.livecode.pi.string TRUE FALSE Basic Application Settings +android,statusBarIcon Status Bar Icon Android com.livecode.pi.file TRUE FALSE PNG Images|png,All files Basic Application Settings +android,inAppPurchasing In App Purchasing Android com.livecode.pi.boolean TRUE FALSE In App Purchasing +android,billingProvider Store Android com.livecode.pi.enum TRUE FALSE Google Google,Samsung In App Purchasing +android,storeKey Store Public Key Android com.livecode.pi.string TRUE FALSE In App Purchasing +android,initial orientation Initial Orientation Android com.livecode.pi.enum TRUE FALSE Portrait Portrait,Landscape User Interface Options +android,status bar hidden Status Bar Android com.livecode.pi.radiogroup TRUE FALSE FALSE Visible|false,Hidden|true User Interface Options +android,minimum version Minimum Android Version Android com.livecode.pi.enum TRUE FALSE 2.2 - Froyo 2.2 - Froyo,2.3 - Gingerbread,2.3.3,3.0 - Honeycomb,3.1 Requirements and Restrictions +android,device capabilities Device capabilities Android com.livecode.pi.multiplechoice TRUE FALSE n/a Required|true,Prohibited|false,n/a:Camera|hardware.camera,Camera Autofocus|hardware.camera.autofocus,Camera Flash|hardware.camera.flash,Front Camera|hardware.camera.front,Accelerometer|hardware.accelerometer,Telephony|hardware.telephony,Telephony CDMA|hardware.telephony.cdma,Telephony GSM|hardware.telephony.gsm,Fake Touch|hardware.faketouch,Multitouch|hardware.touchscreen.multitouch,Multitouch Distinct|hardware.touchscreen.multitouch.distinct,Multitouch Jazzhand|hardware.touchscreen.multitouch.jazzhand Requirements and Restrictions +android,application permissions Android com.livecode.pi.set TRUE FALSE Application Permissions Write External Storage,Internet,Camera,Read Contacts,Write Contacts,Fine Location,Coarse Location,Vibration,Idle Timer,Ad Support Application Permissions \ No newline at end of file diff --git a/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.txt b/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.txt deleted file mode 100644 index cfc3a62306..0000000000 --- a/Toolset/resources/supporting_files/standalone_settings/standaloneSettings.txt +++ /dev/null @@ -1,185 +0,0 @@ -Property Label Section Editor User Visible Read Only Group Default Options Subsection ----------------------------------------------------------------------------------------------------- - -name Standalone name General com.livecode.pi.string true false Name - -inclusions General com.livecode.pi.radiogroup true false Inclusions search Search for required inclusions when saving the application|search,Select inclusions for the standalone application|select Inclusions -askDialog Ask Dialog General com.livecode.pi.boolean true false Inclusion Options Inclusions -answerDialog Answer Dialog General com.livecode.pi.boolean true false Inclusion Options Inclusions -cursors Cursors General com.livecode.pi.boolean true false Inclusion Options Inclusions -revolutionprintdialogs Print Dialogs General com.livecode.pi.boolean true false Inclusion Options Inclusions -Brushes Brushes General com.livecode.pi.boolean true false Inclusion Options Inclusions -pdfPrinter PDF Printer General com.livecode.pi.boolean true false Inclusion Options Inclusions -scriptLibraries Script Libraries General com.livecode.pi.set true false execute:dispatch function "revSBLibraryList" to stack "revSBLibrary";get the result;sort it Inclusions - -databaseSupport Database Drivers General com.livecode.pi.boolean true false Inclusions -databaseDrivers Database Drivers General com.livecode.pi.set true false execute:get revDatabaseDriverList() Inclusions - -extensions Extensions to include General com.livecode.pi.set true false execute: get the loadedExtensions; sort it Inclusions - -setToProfile Set to profile General com.livecode.pi.radiogroup true false remove Remove all profiles on objects|remove,Set all objects to profile|set,Include all profiles on objects and the profile library|all,Include selected profiles on objects and the profile library|selected Property Profiles -includeProfiles Profiles to include General com.livecode.pi.enum true false Property Profiles - -defaultBuildFolder Default Build Folder General com.livecode.pi.file true false Default Build Folder Default Build Folder -automaticallyBuildInDefaultFolder Automatically build here General com.livecode.pi.boolean true false Default Build Folder Default Build Folder - - -destroyStack Set destroyStack property to true for the selected stack Stacks com.livecode.pi.boolean true false For the selected stack -moveSubstacks Move substacks into individual stackfiles Stacks com.livecode.pi.string true false For the selected stack file -password Encrypt with password: Stacks com.livecode.pi.string true false For the selected stack -renameGeneric Stacks com.livecode.pi.boolean true false For the selected stack file -substackFolder Stacks com.livecode.pi.boolean true false For the selected stack file - -files Non-stack files Copy Files com.livecode.pi.filelist true false Non-stack files in the application -CopyReferencedFiles Copy Referenced Files Copy Files com.livecode.pi.boolean true false Non-stack files in the application -ReferencedFilesDestination Destination Folder Copy Files com.livecode.pi.string true false Non-stack files in the application - -MacOSX x86-32 Mac com.livecode.pi.boolean true false Build for Mac OS X (Intel) - -OSX,iconFile Application Icon File Mac com.livecode.pi.file true false Icons -OSX,documenticonFile Document Icon File Mac com.livecode.pi.file true false Icons - -OSX,appicon Application Icon Mac com.livecode.pi.icon true false Ask / answer dialog icons -OSX,smallappicon Small Application Icon Mac com.livecode.pi.icon true false Ask / answer dialog icons - -OSX,plist Mac com.livecode.pi.boolean true false Enter the information and have LiveCode write the PLIST file for you Enter the information and have LiveCode write the PLIST file for you,Choose a PLIST file to import into the application bundle PLIST -OSX,name Name Mac com.livecode.pi.string true false PLIST -OSX,signature Signature Mac com.livecode.pi.string true false PLIST -OSX,documentType Document Type Mac com.livecode.pi.string true false PLIST -OSX,documentExtension Document Extension Mac com.livecode.pi.string true false PLIST - -OSX,shortVersion Short Version Mac com.livecode.pi.string true false Version Information -OSX,longVersion Long Version Mac com.livecode.pi.string true false Version Information -OSX,info Get Info String Mac com.livecode.pi.string true false Version Information -OSX,copyright Copyright Notice Mac com.livecode.pi.string true false Version Information -OSX,identifier Bundle Identifier Mac com.livecode.pi.string true false Version Information - -Windows Windows com.livecode.pi.boolean true false Build for Windows - -Windows,iconFile Application Icon Windows com.livecode.pi.file true false Icon -Windows,documenticonFile Document Icon Windows com.livecode.pi.file true false Icon - -Windows,fileDescription File Description Windows com.livecode.pi.string true false Version Information -Windows,LegalCopyright Copyright Notice Windows com.livecode.pi.string true false Version Information -Windows,comments Comments Windows com.livecode.pi.string true false Version Information -Windows,legalTrademarks Legal Trademarks Windows com.livecode.pi.string true false Version Information -Windows,ProductName Product Name Windows com.livecode.pi.string true false Version Information -Windows,companyname Company Name Windows com.livecode.pi.string true false Version Information - -Windows,fileversion1 Windows com.livecode.pi.number true false File Version Version Information -Windows,fileversion2 . Windows com.livecode.pi.number true false File Version Version Information -Windows,fileversion3 . Windows com.livecode.pi.number true false File Version Version Information -Windows,fileversion4 . Windows com.livecode.pi.number true false File Version Version Information -Windows,productversion1 Windows com.livecode.pi.number true false Product Version Version Information -Windows,productversion2 . Windows com.livecode.pi.number true false Product Version Version Information -Windows,productversion3 . Windows com.livecode.pi.number true false Product Version Version Information -Windows,productversion4 . Windows com.livecode.pi.number true false Product Version Version Information -Windows,originalFilename Original Filename Windows com.livecode.pi.string true false Version Information -Windows,internalName Internal Name Windows com.livecode.pi.string true false Version Information -Windows,privateBuild Private Build Windows com.livecode.pi.string true false Version Information -Windows,specialBuild Special Build Windows com.livecode.pi.string true false Version Information - -Windows,uacExecutionLevel Execution Level Windows com.livecode.pi.enum true false Default|,Same as invoker|asInvoker,Highest Available|highestAvailable,Request Administrator|requestAdministrator UAC Execution Level - -Windows,usePixelScaling Enable Hi-DPI scaling Windows com.livecode.pi.boolean true false Hi-DPI support - -#Windows,UUID UUID Windows com.livecode.pi.string true false UUID - -Linux Linux Linux com.livecode.pi.boolean true false Build for: -Linux ARMv6-HF Linux ARMv6-HF Linux com.livecode.pi.boolean true false Build for: -Linux x64 Linux x64 Linux com.livecode.pi.boolean true false Build for: -UNIX,colorChooser Unix Color Chooser Linux com.livecode.pi.boolean true false Inclusions Inclusions -UNIX,fileSelector Unix File Selector Linux com.livecode.pi.boolean true false Inclusions Inclusions -UNIX,pageSetup Unix Page Setup Linux com.livecode.pi.boolean true false Inclusions Inclusions -UNIX,printerChooser Unix Printer Chooser Linux com.livecode.pi.boolean true false Inclusions Inclusions - -ios Build for iOS iOS com.livecode.pi.boolean true false -ios,device family Device Family iOS com.livecode.pi.set true false 1 iPod and iPhone|1,iPad|2 Build Settings -ios,minimum version Minimum Version iOS com.livecode.pi.enum true false 5.1.1 5.1.1 or later|5.1.1,6.0 or later|6.0,6.1 or later|6.1,7.0 or later|7.0,7.1 or later|7.1,8.0 or later|8.0,8.1 or later|8.1,8.2 or later|8.2 Build Settings - -ios,display name Display Name iOS com.livecode.pi.string true false Basic Application Settings -ios,bundle version Version iOS com.livecode.pi.string true false Basic Application Settings -ios,bundle id Internal App ID iOS com.livecode.pi.string true false Basic Application Settings -ios,profile Profile iOS com.livecode.pi.enum true false Basic Application Settings -ios,include revzip revZip iOS com.livecode.pi.boolean true false Externals false Basic Application Settings -ios,include revxml revXML iOS com.livecode.pi.boolean true false Externals false Basic Application Settings -ios,include dbsqlite SQLite iOS com.livecode.pi.boolean true false Externals false Basic Application Settings -ios,include dbmysql MySQL iOS com.livecode.pi.boolean true false Externals false Basic Application Settings -ios,include revpdfprinter PDF Printing iOS com.livecode.pi.boolean true false Externals false Basic Application Settings -ios,include revsecurity Encryption iOS com.livecode.pi.boolean true false Externals false Basic Application Settings - -ios,status bar hidden iPhone Status Bar iOS com.livecode.pi.radiogroup true false Status Bar false Visible|false,Hidden|true Status Bar -ios,iPad status bar hidden iPad Status Bar iOS com.livecode.pi.radiogroup true false Status Bar false Visible|false,Hidden|true Status Bar -ios,status bar style Status Bar Style iOS com.livecode.pi.enum true false Default Default|Default,Black Opaque|BlackOpaque,Black Translucent|BlackTranslucent,Solid|Solid Status Bar - -ios,iphone initial orientation iPhone Initial Orientation iOS com.livecode.pi.enum true false Portrait Portrait|Portrait,Portrait Upside-Down|PortraitUpsideDown,Landscape Left|LandscapeLeft,Landscape Right|LandscapeRight Orientation Options -ios,ipad initial orientations iPad Supported Initial Orientations iOS com.livecode.pi.set true false Portrait Portrait|Portrait,Portrait Upside-Down|PortraitUpsideDown,Landscape Left|LandscapeLeft,Landscape Right|LandscapeRight Orientation Options - -ios,url name URL Name iOS com.livecode.pi.string true false Custom URL Scheme - -ios,location auth type Authorize iOS com.livecode.pi.radiogroup true false Always Always,When In Use Location Authorization Type - -ios,persistent wifi Persistent WiFi iOS com.livecode.pi.boolean true false Allow false Requirements and Restrictions -ios,file sharing File Sharing iOS com.livecode.pi.boolean true false Allow false Requirements and Restrictions -ios,local notifications Local Notifications iOS com.livecode.pi.boolean true false Allow false Requirements and Restrictions -ios,push notifications Push Notifications iOS com.livecode.pi.boolean true false Allow false Requirements and Restrictions - -ios,device capabilities Capabilities iOS com.livecode.pi.multiplechoice true false n/a Required|true,Prohibited|false,n/a:Telephony|telephony,Peer-Peer|peer-peer,SMS|sms,Still Camera|still-camera,Auto-Focus Camera|auto-focus-camera,Front-Facing Camera|front-facing-camera,Camera Flash|camera-flash,Video Camera|video-camera,Accelerometer|accelerometer,Gyroscope|gyroscope,Location Services|location-services,GPS|gps,Magnetometer|magnetometer,Microphone|microphone,Game-Kit|gamekit,WiFi|wifi,OpenGL ES 1.1|opengles-1,OpenGL ES 2.0|opengles-2 Requirements and Restrictions - -ios,prerendered icon Prerendered Icon iOS com.livecode.pi.boolean true false Icons -ios,iphone icon iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,retina icon Hi-Res iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,iOS 7 retina icon iOS 7 Hi-Res iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,iPhone 6 Plus icon iPhone 6 Plus iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,ipad icon iPad iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,ipad retina icon Hi-Res iPad iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,iOS 7 ipad icon iOS 7 iPad iOS com.livecode.pi.file true false PNG Images|png,All files Icons -ios,iOS 7 ipad retina icon iOS 7 Hi-Res iPad iOS com.livecode.pi.file true false PNG Images|png,All files Icons - -ios,iphone splash iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,retina splash Hi-Res iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,iphone 4inch splash icon 4 Inch iPhone iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,iphone 6 splash iPhone 6 iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,iPhone 6 Plus Portrait splash iPhone 6 Plus Portrait iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,iPhone 6 Plus Landscape splash iPhone 6 Plus Landscape iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,ipad portrait splash iPad Portrait iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,ipad landscape splash iPad Landscape iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,ipad retina portrait splash Hi-Res iPad Portrait iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens -ios,ipad retina landscape splash Hi-Res iPad Landscape iOS com.livecode.pi.file true false PNG Images|png,All files Splash Screens - - -android Build for Android Android com.livecode.pi.boolean true false - -android,label Label Android com.livecode.pi.string true false Basic Application Settings -android,identifier Identifier Android com.livecode.pi.string true false Basic Application Settings -android,version name Version Name Android com.livecode.pi.string true false Basic Application Settings -android,version code Version Code Android com.livecode.pi.string true false Basic Application Settings -android,icon Icon Android com.livecode.pi.file true false PNG Images|png,All files Basic Application Settings -android,splash Splash Android com.livecode.pi.file true false PNG Images|png,All files Basic Application Settings -android,signing Signing Android com.livecode.pi.enum true false Sign with my key Sign with my key,Sign for development only,Do not sign Basic Application Settings -android,key Key Android com.livecode.pi.file true false Java keystores|keystore,All files Basic Application Settings -android,install location Install Location com.livecode.pi.enum true false Internal Storage Only Internal Storage Only,Allow External Storage,Prefer External Storage Basic Application Settings - -android,include revzip revZip Android com.livecode.pi.boolean true false Externals false Basic Application Settings -android,include revxml revXML Android com.livecode.pi.boolean true false Externals false Basic Application Settings -android,include dbsqlite SQLite Android com.livecode.pi.boolean true false Externals false Basic Application Settings -android,include dbmysql MySQL Android com.livecode.pi.boolean true false Externals false Basic Application Settings -android,include revpdfprinter PDF Printing Android com.livecode.pi.boolean true false Externals false Basic Application Settings -android,include revsecurity SSL & Encryption Android com.livecode.pi.boolean true false Externals false Basic Application Settings - -android,customUrlScheme URL Name Android com.livecode.pi.string true false Custom URL Scheme - -android,pushSenderID Push Sender ID Android com.livecode.pi.string true false Basic Application Settings -android,statusBarIcon Status Bar Icon Android com.livecode.pi.file true false PNG Images|png,All files Basic Application Settings - -android,inAppPurchasing In App Purchasing Android com.livecode.pi.boolean true false In App Purchasing -android,billingProvider Store Android com.livecode.pi.enum true false Google Google,Samsung In App Purchasing -android,storeKey Store Public Key Android com.livecode.pi.string true false In App Purchasing - -android,initial orientation Initial Orientation Android com.livecode.pi.enum true false Portrait Portrait,Landscape User Interface Options -android,status bar hidden Status Bar Android com.livecode.pi.radiogroup true false false Visible|false,Hidden|true User Interface Options - -android,minimum version Minimum Android Version Android com.livecode.pi.enum true false 2.2 - Froyo 2.2 - Froyo,2.3 - Gingerbread,2.3.3,3.0 - Honeycomb,3.1 Requirements and Restrictions -android,device capabilities Device capabilities Android com.livecode.pi.multiplechoice true false n/a Required|true,Prohibited|false,n/a:Camera|hardware.camera,Camera Autofocus|hardware.camera.autofocus,Camera Flash|hardware.camera.flash,Front Camera|hardware.camera.front,Accelerometer|hardware.accelerometer,Telephony|hardware.telephony,Telephony CDMA|hardware.telephony.cdma,Telephony GSM|hardware.telephony.gsm,Fake Touch|hardware.faketouch,Multitouch|hardware.touchscreen.multitouch,Multitouch Distinct|hardware.touchscreen.multitouch.distinct,Multitouch Jazzhand|hardware.touchscreen.multitouch.jazzhand Requirements and Restrictions - -android,application permissions Android com.livecode.pi.set true false Application Permissions Write External Storage,Internet,Camera,Read Contacts,Write Contacts,Fine Location,Coarse Location,Vibration,Idle Timer,Ad Support Application Permissions \ No newline at end of file diff --git a/notes/bugfix-11204.md b/notes/bugfix-11204.md new file mode 100644 index 0000000000..0788d10300 --- /dev/null +++ b/notes/bugfix-11204.md @@ -0,0 +1 @@ +# Script Editor: Use same background color for both editing field and handler list diff --git a/notes/bugfix-11295.md b/notes/bugfix-11295.md new file mode 100644 index 0000000000..509efa2a24 --- /dev/null +++ b/notes/bugfix-11295.md @@ -0,0 +1 @@ +# Fix error in DataGrid when form controls are cached, fixed line height is true, and showing the vertical scrollbar is set to auto. diff --git a/notes/bugfix-12400.md b/notes/bugfix-12400.md new file mode 100644 index 0000000000..d43c511079 --- /dev/null +++ b/notes/bugfix-12400.md @@ -0,0 +1 @@ +# Ensure Datagrid refreshes when switching its style from table to form and back to table diff --git a/notes/bugfix-14079.md b/notes/bugfix-14079.md new file mode 100644 index 0000000000..9d6ab60f41 --- /dev/null +++ b/notes/bugfix-14079.md @@ -0,0 +1 @@ +# Ensure subscripts and superscripts can be set more than once diff --git a/notes/bugfix-14163.md b/notes/bugfix-14163.md new file mode 100644 index 0000000000..ecdb186f09 --- /dev/null +++ b/notes/bugfix-14163.md @@ -0,0 +1 @@ +# Fixed bug preventing users from adding Build Numbers to S/B's \ No newline at end of file diff --git a/notes/bugfix-14863.md b/notes/bugfix-14863.md new file mode 100644 index 0000000000..1b362dee5a --- /dev/null +++ b/notes/bugfix-14863.md @@ -0,0 +1 @@ +# Use native scrollers for DataGrid scrollbars on mobile diff --git a/notes/bugfix-15157.md b/notes/bugfix-15157.md new file mode 100644 index 0000000000..9003c75ba7 --- /dev/null +++ b/notes/bugfix-15157.md @@ -0,0 +1 @@ +# Ensure Android app identifier is valid diff --git a/notes/bugfix-15218.md b/notes/bugfix-15218.md new file mode 100644 index 0000000000..b9b17ee7f7 --- /dev/null +++ b/notes/bugfix-15218.md @@ -0,0 +1 @@ +# Reduce PI size to available screen space where necessary diff --git a/notes/bugfix-15638.md b/notes/bugfix-15638.md new file mode 100644 index 0000000000..5146924934 --- /dev/null +++ b/notes/bugfix-15638.md @@ -0,0 +1 @@ +# Remove `cantModify` from stack basic properties palette \ No newline at end of file diff --git a/notes/bugfix-15917.md b/notes/bugfix-15917.md new file mode 100644 index 0000000000..7e32a23c4a --- /dev/null +++ b/notes/bugfix-15917.md @@ -0,0 +1 @@ +# Font Size for Project Browser can now be set from LiveCode Preferences -> Project Browser diff --git a/notes/bugfix-16933.md b/notes/bugfix-16933.md new file mode 100644 index 0000000000..2bd42dab7a --- /dev/null +++ b/notes/bugfix-16933.md @@ -0,0 +1 @@ +# Adapt icon size to text size in Project Browser diff --git a/notes/bugfix-17152.md b/notes/bugfix-17152.md new file mode 100644 index 0000000000..6a59e9f47e --- /dev/null +++ b/notes/bugfix-17152.md @@ -0,0 +1 @@ +# Updated broken behavior references in message box objects diff --git a/notes/bugfix-17287.md b/notes/bugfix-17287.md new file mode 100644 index 0000000000..65be708fb3 --- /dev/null +++ b/notes/bugfix-17287.md @@ -0,0 +1 @@ +# Image filename property is not relativized with the PI diff --git a/notes/bugfix-17447.md b/notes/bugfix-17447.md new file mode 100644 index 0000000000..00efcf20f9 --- /dev/null +++ b/notes/bugfix-17447.md @@ -0,0 +1 @@ +# Reinstate resize checkbox in property inspector Position pane \ No newline at end of file diff --git a/notes/bugfix-17448.md b/notes/bugfix-17448.md new file mode 100644 index 0000000000..3b83d2b488 --- /dev/null +++ b/notes/bugfix-17448.md @@ -0,0 +1 @@ +# Make sure messages are sent when going to stacks/cards from the Project Browser diff --git a/notes/bugfix-17476.md b/notes/bugfix-17476.md new file mode 100644 index 0000000000..ae1dc97749 --- /dev/null +++ b/notes/bugfix-17476.md @@ -0,0 +1 @@ +# Use numeric sort for variables/keys in SE variables lists \ No newline at end of file diff --git a/notes/bugfix-17485.md b/notes/bugfix-17485.md new file mode 100644 index 0000000000..8690ff16b9 --- /dev/null +++ b/notes/bugfix-17485.md @@ -0,0 +1 @@ +# Allow accessing Image Library and Object Library from LiveCode menubar diff --git a/notes/bugfix-17536.md b/notes/bugfix-17536.md new file mode 100644 index 0000000000..e4c5fc5d59 --- /dev/null +++ b/notes/bugfix-17536.md @@ -0,0 +1 @@ +# Fix or mitigate effect of nudging many controls at once \ No newline at end of file diff --git a/notes/bugfix-17583.md b/notes/bugfix-17583.md new file mode 100644 index 0000000000..ced71c6b18 --- /dev/null +++ b/notes/bugfix-17583.md @@ -0,0 +1 @@ +# Allow increased height in inspector windows diff --git a/notes/bugfix-17618.md b/notes/bugfix-17618.md new file mode 100644 index 0000000000..e1c5bca44a --- /dev/null +++ b/notes/bugfix-17618.md @@ -0,0 +1 @@ +# Reinstate 'fit content' button in property inspector Position pane \ No newline at end of file diff --git a/notes/bugfix-17683.md b/notes/bugfix-17683.md new file mode 100644 index 0000000000..06f06a7ad0 --- /dev/null +++ b/notes/bugfix-17683.md @@ -0,0 +1 @@ +# Ensure Start Center stays open when a Plugin opens on startup diff --git a/notes/bugfix-17819.md b/notes/bugfix-17819.md new file mode 100644 index 0000000000..772dbbf38e --- /dev/null +++ b/notes/bugfix-17819.md @@ -0,0 +1 @@ +# Enable cmd+c in dictionary diff --git a/notes/bugfix-17823.md b/notes/bugfix-17823.md new file mode 100644 index 0000000000..30f8058372 --- /dev/null +++ b/notes/bugfix-17823.md @@ -0,0 +1 @@ +# Updated DG property label from "Empty row height" to "Fixed row height" in the Property Inspector diff --git a/notes/bugfix-17851.md b/notes/bugfix-17851.md new file mode 100644 index 0000000000..7e327217ab --- /dev/null +++ b/notes/bugfix-17851.md @@ -0,0 +1 @@ +# Add default script to scrollbar diff --git a/notes/bugfix-17889.md b/notes/bugfix-17889.md new file mode 100644 index 0000000000..2b1a79b202 --- /dev/null +++ b/notes/bugfix-17889.md @@ -0,0 +1 @@ +# Repaired confusing layout of fill gradient control in Property Inspector diff --git a/notes/bugfix-18035.md b/notes/bugfix-18035.md new file mode 100644 index 0000000000..c01628c4be --- /dev/null +++ b/notes/bugfix-18035.md @@ -0,0 +1 @@ +# Make sure the gradient popup stack is displayed as expected diff --git a/notes/bugfix-18037.md b/notes/bugfix-18037.md new file mode 100644 index 0000000000..d0676dd595 --- /dev/null +++ b/notes/bugfix-18037.md @@ -0,0 +1 @@ +# Apply property defaults from metadata when testing widgets diff --git a/notes/bugfix-18088.md b/notes/bugfix-18088.md new file mode 100644 index 0000000000..e4cbdbd231 --- /dev/null +++ b/notes/bugfix-18088.md @@ -0,0 +1 @@ +# Allow setting multi-line tooltips from the Property Inspector diff --git a/notes/bugfix-18177.md b/notes/bugfix-18177.md new file mode 100644 index 0000000000..5fd84370b7 --- /dev/null +++ b/notes/bugfix-18177.md @@ -0,0 +1 @@ +# Reinstate text properties and graphic effects to datagrid inspector \ No newline at end of file diff --git a/notes/bugfix-18201.md b/notes/bugfix-18201.md new file mode 100644 index 0000000000..3a3ee5c39b --- /dev/null +++ b/notes/bugfix-18201.md @@ -0,0 +1 @@ +# Make sure rulers can be hidden diff --git a/notes/bugfix-18300.md b/notes/bugfix-18300.md new file mode 100644 index 0000000000..d678a0345c --- /dev/null +++ b/notes/bugfix-18300.md @@ -0,0 +1 @@ +# property inspector custom property list is not sorted diff --git a/notes/bugfix-18302.md b/notes/bugfix-18302.md new file mode 100644 index 0000000000..6292de423d --- /dev/null +++ b/notes/bugfix-18302.md @@ -0,0 +1 @@ +# Retain custom prop changes when clicking on tree view in editor \ No newline at end of file diff --git a/notes/bugfix-18366.md b/notes/bugfix-18366.md new file mode 100644 index 0000000000..a4ebcb3d29 --- /dev/null +++ b/notes/bugfix-18366.md @@ -0,0 +1 @@ +# Enable control+tab on MacOS \ No newline at end of file diff --git a/notes/bugfix-18393.md b/notes/bugfix-18393.md new file mode 100644 index 0000000000..c7d167cc3f --- /dev/null +++ b/notes/bugfix-18393.md @@ -0,0 +1 @@ +# [Project Browser] Change "Sort controls by number" to "Sort controls by layer" to avoid confusion + make sure they are sorted numerically diff --git a/notes/bugfix-18460.md b/notes/bugfix-18460.md new file mode 100644 index 0000000000..d692e95d08 --- /dev/null +++ b/notes/bugfix-18460.md @@ -0,0 +1 @@ +# Mark stack as edited when property changed from the PI \ No newline at end of file diff --git a/notes/bugfix-18485.md b/notes/bugfix-18485.md new file mode 100644 index 0000000000..f4f3ed99fb --- /dev/null +++ b/notes/bugfix-18485.md @@ -0,0 +1 @@ +# Ensure relayering menu items don't relayer objects out of owner groups diff --git a/notes/bugfix-18491.md b/notes/bugfix-18491.md new file mode 100644 index 0000000000..2ea77cc3e1 --- /dev/null +++ b/notes/bugfix-18491.md @@ -0,0 +1,6 @@ +# Allow substack to become a mainstack via property inspector + +The property inspector Basic pane for substacks now has a +button beneath the mainstack labelled "Make mainstack". Note +that once pressed this button will disappear, as the stack +will no longer a substack. \ No newline at end of file diff --git a/notes/bugfix-18507.md b/notes/bugfix-18507.md new file mode 100644 index 0000000000..3b6944186b --- /dev/null +++ b/notes/bugfix-18507.md @@ -0,0 +1 @@ +# Permit standalone deployment with minimum iOS version > 9 diff --git a/notes/bugfix-18528.md b/notes/bugfix-18528.md new file mode 100644 index 0000000000..4c4a1a4d81 --- /dev/null +++ b/notes/bugfix-18528.md @@ -0,0 +1 @@ +# Find Next/Previous in the SE now respects current cursor location diff --git a/notes/bugfix-18549.md b/notes/bugfix-18549.md new file mode 100644 index 0000000000..27db2e816c --- /dev/null +++ b/notes/bugfix-18549.md @@ -0,0 +1 @@ +# Make sure `lock cursor` works in the IDE diff --git a/notes/bugfix-18557.md b/notes/bugfix-18557.md new file mode 100644 index 0000000000..b4ac20498d --- /dev/null +++ b/notes/bugfix-18557.md @@ -0,0 +1 @@ +# Ensure dragging object from tools palette is smooth \ No newline at end of file diff --git a/notes/bugfix-18585.md b/notes/bugfix-18585.md new file mode 100644 index 0000000000..0b8f731b64 --- /dev/null +++ b/notes/bugfix-18585.md @@ -0,0 +1 @@ +# Ensure Dictionary does not pass cmd+A diff --git a/notes/bugfix-18586.md b/notes/bugfix-18586.md new file mode 100644 index 0000000000..3e270f1a04 --- /dev/null +++ b/notes/bugfix-18586.md @@ -0,0 +1 @@ +# Make sure the Project Browser stack/card/group view can always expand diff --git a/notes/bugfix-18595.md b/notes/bugfix-18595.md new file mode 100644 index 0000000000..70f60a7d83 --- /dev/null +++ b/notes/bugfix-18595.md @@ -0,0 +1 @@ +# Clicking left of text now moves caret to the beginning of text diff --git a/notes/bugfix-18598.md b/notes/bugfix-18598.md new file mode 100644 index 0000000000..91ff58a7c5 --- /dev/null +++ b/notes/bugfix-18598.md @@ -0,0 +1 @@ +# Prevent error on backspace in empty script editor diff --git a/notes/bugfix-18631.md b/notes/bugfix-18631.md new file mode 100644 index 0000000000..0e7ee169d8 --- /dev/null +++ b/notes/bugfix-18631.md @@ -0,0 +1 @@ +# Only use development team preferences when running from the repository diff --git a/notes/bugfix-18636.md b/notes/bugfix-18636.md new file mode 100644 index 0000000000..c127eb091b --- /dev/null +++ b/notes/bugfix-18636.md @@ -0,0 +1 @@ +# [SE Interactive search] Ensure pressing the return key cycles through all instances of the string to be found diff --git a/notes/bugfix-18637.md b/notes/bugfix-18637.md new file mode 100644 index 0000000000..9007c9f5d1 --- /dev/null +++ b/notes/bugfix-18637.md @@ -0,0 +1 @@ +# Fix searching in "Stack File and its stack files" from the script editor diff --git a/notes/bugfix-18644.md b/notes/bugfix-18644.md new file mode 100644 index 0000000000..413ffbe1ff --- /dev/null +++ b/notes/bugfix-18644.md @@ -0,0 +1 @@ +# Deactivate breakpoints correctly diff --git a/notes/bugfix-18654.md b/notes/bugfix-18654.md new file mode 100644 index 0000000000..614266a197 --- /dev/null +++ b/notes/bugfix-18654.md @@ -0,0 +1 @@ +# Added "Size" field to the Property Inspector of the image object diff --git a/notes/bugfix-18682.md b/notes/bugfix-18682.md new file mode 100644 index 0000000000..7cc128b562 --- /dev/null +++ b/notes/bugfix-18682.md @@ -0,0 +1 @@ +# Ensure debugger ignores breakpoints and errors if a modal stack is presented diff --git a/notes/bugfix-18685.md b/notes/bugfix-18685.md new file mode 100644 index 0000000000..a523eec056 --- /dev/null +++ b/notes/bugfix-18685.md @@ -0,0 +1 @@ +# Remember the last position of menubar on Windows and Linux diff --git a/notes/bugfix-18701.md b/notes/bugfix-18701.md new file mode 100644 index 0000000000..cd04f92fe1 --- /dev/null +++ b/notes/bugfix-18701.md @@ -0,0 +1 @@ +# Prevent over-enthusiastic save prompts \ No newline at end of file diff --git a/notes/bugfix-18721.md b/notes/bugfix-18721.md new file mode 100644 index 0000000000..5067d05fd0 --- /dev/null +++ b/notes/bugfix-18721.md @@ -0,0 +1 @@ +# Make sure unchecking "Notify me of development releases" is respected diff --git a/notes/bugfix-18726.md b/notes/bugfix-18726.md new file mode 100644 index 0000000000..40595369cc --- /dev/null +++ b/notes/bugfix-18726.md @@ -0,0 +1 @@ +# Make sure the Bug Report checkmark appears at the correct place in Standalone Settings diff --git a/notes/bugfix-18739.md b/notes/bugfix-18739.md new file mode 100644 index 0000000000..750b1349c9 --- /dev/null +++ b/notes/bugfix-18739.md @@ -0,0 +1 @@ +# Dictionary auto-search on first char freezing cursor diff --git a/notes/bugfix-18791.md b/notes/bugfix-18791.md new file mode 100644 index 0000000000..92956272de --- /dev/null +++ b/notes/bugfix-18791.md @@ -0,0 +1 @@ +# Fix PI list editors not updating when value changed diff --git a/notes/bugfix-18804.md b/notes/bugfix-18804.md new file mode 100644 index 0000000000..5b2840c65e --- /dev/null +++ b/notes/bugfix-18804.md @@ -0,0 +1 @@ +# Update locked inspectors when mainstack names change \ No newline at end of file diff --git a/notes/bugfix-18835.md b/notes/bugfix-18835.md new file mode 100644 index 0000000000..486c2d070c --- /dev/null +++ b/notes/bugfix-18835.md @@ -0,0 +1 @@ +# linkVisitedColor and linkHiliteColor can now be set from property inspector diff --git a/notes/bugfix-18857.md b/notes/bugfix-18857.md new file mode 100644 index 0000000000..44c0175b5e --- /dev/null +++ b/notes/bugfix-18857.md @@ -0,0 +1 @@ +# Import as control > Text file doesn't set text of control \ No newline at end of file diff --git a/notes/bugfix-18878.md b/notes/bugfix-18878.md new file mode 100644 index 0000000000..a666f11afe --- /dev/null +++ b/notes/bugfix-18878.md @@ -0,0 +1 @@ +# Setting stackFiles in PI causes an error if you "cancel" the file dialog or select multiple files \ No newline at end of file diff --git a/notes/bugfix-18881.md b/notes/bugfix-18881.md new file mode 100644 index 0000000000..c32aeb06ea --- /dev/null +++ b/notes/bugfix-18881.md @@ -0,0 +1 @@ +# Dictionary: sort API menu diff --git a/notes/bugfix-18897.md b/notes/bugfix-18897.md new file mode 100644 index 0000000000..02499beeea --- /dev/null +++ b/notes/bugfix-18897.md @@ -0,0 +1 @@ +# "Show Sections" for Project Browser can now be set from LiveCode Preferences -> Project Browser diff --git a/notes/bugfix-18915.md b/notes/bugfix-18915.md new file mode 100644 index 0000000000..638475e32f --- /dev/null +++ b/notes/bugfix-18915.md @@ -0,0 +1 @@ +# Allow a 'set the name of stack' step in interactive tutorials diff --git a/notes/bugfix-18920.md b/notes/bugfix-18920.md new file mode 100644 index 0000000000..5134c5e6d5 --- /dev/null +++ b/notes/bugfix-18920.md @@ -0,0 +1 @@ +# Reinstate that a single char can be selected with the mouse in ScriptEditor diff --git a/notes/bugfix-18930.md b/notes/bugfix-18930.md new file mode 100644 index 0000000000..fb90b93d4e --- /dev/null +++ b/notes/bugfix-18930.md @@ -0,0 +1,4 @@ +# Reinstate store tab of extension manager + +The store tab of the extension manager has been reinstated and the +revBrowser implementation has been replaced with a browser widget. \ No newline at end of file diff --git a/notes/bugfix-18931.md b/notes/bugfix-18931.md new file mode 100644 index 0000000000..b44ef1ba4c --- /dev/null +++ b/notes/bugfix-18931.md @@ -0,0 +1 @@ +# Update widget creation docs with extension store instructions diff --git a/notes/bugfix-18932.md b/notes/bugfix-18932.md new file mode 100644 index 0000000000..391363a6fc --- /dev/null +++ b/notes/bugfix-18932.md @@ -0,0 +1,9 @@ +# SVG icon support in the Extension Builder + +The 'Extension Builder' now displays LiveCode Builder extensions' SVG +icons, if present. You can add an SVG icon to an LCB extension by +setting its "svgicon" metadata to an SVG path that could be displayed +by the 'SVG Icon' widget. + +When an extension provides an SVG icon, packaging the extension no +longer requires you to choose bitmap icon files. diff --git a/notes/bugfix-18937.md b/notes/bugfix-18937.md new file mode 100644 index 0000000000..de68fda35d --- /dev/null +++ b/notes/bugfix-18937.md @@ -0,0 +1,4 @@ +# <Shift+Tab> reformats entire script + +Holding down the Shift key while pressing the Tab key will reformat +the entire script in the Script Editor. diff --git a/notes/bugfix-18956.md b/notes/bugfix-18956.md new file mode 100644 index 0000000000..da04c59121 --- /dev/null +++ b/notes/bugfix-18956.md @@ -0,0 +1 @@ +# Make sure oauth2 library is loaded correctly diff --git a/notes/bugfix-18966.md b/notes/bugfix-18966.md new file mode 100644 index 0000000000..8ca67a87a2 --- /dev/null +++ b/notes/bugfix-18966.md @@ -0,0 +1 @@ +# Remove size limitation for creating graphics diff --git a/notes/bugfix-18981.md b/notes/bugfix-18981.md new file mode 100644 index 0000000000..178b352091 --- /dev/null +++ b/notes/bugfix-18981.md @@ -0,0 +1 @@ +# Added tooltip to iOS icon and splash screen selection diff --git a/notes/bugfix-18987.md b/notes/bugfix-18987.md new file mode 100644 index 0000000000..eab55fb6d2 --- /dev/null +++ b/notes/bugfix-18987.md @@ -0,0 +1 @@ +# Reinstate fixedLineHeight for tableField diff --git a/notes/bugfix-18991.md b/notes/bugfix-18991.md new file mode 100644 index 0000000000..e990ce8f09 --- /dev/null +++ b/notes/bugfix-18991.md @@ -0,0 +1 @@ +# Disable custom property editor when no node selected diff --git a/notes/bugfix-19013.md b/notes/bugfix-19013.md new file mode 100644 index 0000000000..aae59c3d02 --- /dev/null +++ b/notes/bugfix-19013.md @@ -0,0 +1 @@ +# Default PI color picker to RGB unless already set to color name diff --git a/notes/bugfix-19015.md b/notes/bugfix-19015.md new file mode 100644 index 0000000000..202545c5b0 --- /dev/null +++ b/notes/bugfix-19015.md @@ -0,0 +1 @@ +# Reset the templateStack after datagrid creation \ No newline at end of file diff --git a/notes/bugfix-19031.md b/notes/bugfix-19031.md new file mode 100644 index 0000000000..6b296b995d --- /dev/null +++ b/notes/bugfix-19031.md @@ -0,0 +1 @@ +# Searching the Dictionary for $ diff --git a/notes/bugfix-19072.md b/notes/bugfix-19072.md new file mode 100644 index 0000000000..ab5f071dd9 --- /dev/null +++ b/notes/bugfix-19072.md @@ -0,0 +1 @@ +# Add slider to PI for startAngle and arcAngle for oval graphics diff --git a/notes/bugfix-19152.md b/notes/bugfix-19152.md new file mode 100644 index 0000000000..e648166ba7 --- /dev/null +++ b/notes/bugfix-19152.md @@ -0,0 +1 @@ +# Show warning if the new stack name begins with "rev" diff --git a/notes/bugfix-19153.md b/notes/bugfix-19153.md new file mode 100644 index 0000000000..404a35422e --- /dev/null +++ b/notes/bugfix-19153.md @@ -0,0 +1 @@ +# Ensure objects can not be dragged to invisible open stacks from the tools palette diff --git a/notes/bugfix-19160.md b/notes/bugfix-19160.md new file mode 100644 index 0000000000..a5ae5386f1 --- /dev/null +++ b/notes/bugfix-19160.md @@ -0,0 +1 @@ +# Make sure the S/B respects the "iPad initial orientations" settings diff --git a/notes/bugfix-19177.md b/notes/bugfix-19177.md new file mode 100644 index 0000000000..d42d4a6e2c --- /dev/null +++ b/notes/bugfix-19177.md @@ -0,0 +1 @@ +# Update guide images for LiveCode 8 diff --git a/notes/bugfix-19178.md b/notes/bugfix-19178.md new file mode 100644 index 0000000000..59186b24c9 --- /dev/null +++ b/notes/bugfix-19178.md @@ -0,0 +1 @@ +# Add test to ensure default folder doesn't change when loading IDE diff --git a/notes/bugfix-19179.md b/notes/bugfix-19179.md new file mode 100644 index 0000000000..f91abc7a4b --- /dev/null +++ b/notes/bugfix-19179.md @@ -0,0 +1 @@ +# Add tests for standalone builder inclusions diff --git a/notes/bugfix-19181.md b/notes/bugfix-19181.md new file mode 100644 index 0000000000..b88f586c1e --- /dev/null +++ b/notes/bugfix-19181.md @@ -0,0 +1 @@ +# Ensure tutorial has location set when being skipped diff --git a/notes/bugfix-19188.md b/notes/bugfix-19188.md new file mode 100644 index 0000000000..a84bd8e17d --- /dev/null +++ b/notes/bugfix-19188.md @@ -0,0 +1 @@ +# Make outputting debug vars from message box work in all contexts diff --git a/notes/bugfix-19195.md b/notes/bugfix-19195.md new file mode 100644 index 0000000000..2916504c5f --- /dev/null +++ b/notes/bugfix-19195.md @@ -0,0 +1 @@ +# Allow vertical scrolling in "Value" field of Variable Visualizer window diff --git a/notes/bugfix-19196.md b/notes/bugfix-19196.md new file mode 100644 index 0000000000..679c45bbd9 --- /dev/null +++ b/notes/bugfix-19196.md @@ -0,0 +1 @@ +# Ensure extension is installed before deleting files diff --git a/notes/bugfix-19264.md b/notes/bugfix-19264.md new file mode 100644 index 0000000000..582bf69114 --- /dev/null +++ b/notes/bugfix-19264.md @@ -0,0 +1 @@ +# Ensure LCB errors display reasonably in script editor diff --git a/notes/bugfix-19339.md b/notes/bugfix-19339.md new file mode 100644 index 0000000000..a75da6e042 --- /dev/null +++ b/notes/bugfix-19339.md @@ -0,0 +1 @@ +# Fix "Pending Messages" tab of the message box in Business Edition diff --git a/notes/bugfix-19359.md b/notes/bugfix-19359.md new file mode 100644 index 0000000000..9d21b71023 --- /dev/null +++ b/notes/bugfix-19359.md @@ -0,0 +1 @@ +# Ensure the debugger and remote debugger ignore breakpoints and errors if they are repeatedly triggered when execution has not been continued diff --git a/notes/bugfix-19384.md b/notes/bugfix-19384.md new file mode 100644 index 0000000000..1168857f03 --- /dev/null +++ b/notes/bugfix-19384.md @@ -0,0 +1 @@ +# Set JAVA_HOME at startup if not set diff --git a/notes/bugfix-19406.md b/notes/bugfix-19406.md new file mode 100644 index 0000000000..0616eec504 --- /dev/null +++ b/notes/bugfix-19406.md @@ -0,0 +1 @@ +# Correctly re-enable debugger when setting Script Debug Mode diff --git a/notes/bugfix-19439.md b/notes/bugfix-19439.md new file mode 100644 index 0000000000..78eeb3def5 --- /dev/null +++ b/notes/bugfix-19439.md @@ -0,0 +1 @@ +# Ensure the "Effects" settings stack always appears onscreen diff --git a/notes/bugfix-19451.md b/notes/bugfix-19451.md new file mode 100644 index 0000000000..4f69794f6b --- /dev/null +++ b/notes/bugfix-19451.md @@ -0,0 +1 @@ +# Don't try to delete breakpoint while it is a target in the call stack diff --git a/notes/bugfix-19480.md b/notes/bugfix-19480.md new file mode 100644 index 0000000000..c2b1094ba9 --- /dev/null +++ b/notes/bugfix-19480.md @@ -0,0 +1 @@ +# Ensure message box execution succeeds first time if no compile error diff --git a/notes/bugfix-19491.md b/notes/bugfix-19491.md new file mode 100644 index 0000000000..2793288877 --- /dev/null +++ b/notes/bugfix-19491.md @@ -0,0 +1 @@ +# Allow PI to be resized to smaller than content height diff --git a/notes/bugfix-19504.md b/notes/bugfix-19504.md new file mode 100644 index 0000000000..7d88ecf773 --- /dev/null +++ b/notes/bugfix-19504.md @@ -0,0 +1 @@ +# Allow entry of tabs into the text property field of the property inspector diff --git a/notes/bugfix-19511.md b/notes/bugfix-19511.md new file mode 100644 index 0000000000..5313a3a9a0 --- /dev/null +++ b/notes/bugfix-19511.md @@ -0,0 +1 @@ +# Move "User Guide" higher in Help menu diff --git a/notes/bugfix-19547.md b/notes/bugfix-19547.md new file mode 100644 index 0000000000..0c6837578b --- /dev/null +++ b/notes/bugfix-19547.md @@ -0,0 +1 @@ +# Fixed bug preventing users from finding | and - in the script editor diff --git a/notes/bugfix-19564.md b/notes/bugfix-19564.md new file mode 100644 index 0000000000..648721d625 --- /dev/null +++ b/notes/bugfix-19564.md @@ -0,0 +1 @@ +# Prevent error when deleting script editor tab diff --git a/notes/bugfix-19585.md b/notes/bugfix-19585.md new file mode 100644 index 0000000000..de403c2ab2 --- /dev/null +++ b/notes/bugfix-19585.md @@ -0,0 +1 @@ +# Improve rendering of Interactive Tutorial on Windows when screenPixelScale > 1 diff --git a/notes/bugfix-19589.md b/notes/bugfix-19589.md new file mode 100644 index 0000000000..1b873fcc86 --- /dev/null +++ b/notes/bugfix-19589.md @@ -0,0 +1 @@ +# Fix 'put globalVar' in msg box diff --git a/notes/bugfix-19627.md b/notes/bugfix-19627.md new file mode 100644 index 0000000000..7062b50ee0 --- /dev/null +++ b/notes/bugfix-19627.md @@ -0,0 +1 @@ +# Clear deleted objects from project browser correctly diff --git a/notes/bugfix-19629.md b/notes/bugfix-19629.md new file mode 100644 index 0000000000..9dc68a2235 --- /dev/null +++ b/notes/bugfix-19629.md @@ -0,0 +1 @@ +# Check for changes in filename when getting object row in project browser diff --git a/notes/bugfix-19741.md b/notes/bugfix-19741.md new file mode 100644 index 0000000000..f63048dbec --- /dev/null +++ b/notes/bugfix-19741.md @@ -0,0 +1 @@ +# Remove legacy inks from property inspector diff --git a/notes/bugfix-19749.md b/notes/bugfix-19749.md new file mode 100644 index 0000000000..e70cf8faa2 --- /dev/null +++ b/notes/bugfix-19749.md @@ -0,0 +1 @@ +# Unsubscribe from ideExtensionLog when extension builder closes diff --git a/notes/bugfix-19821.md b/notes/bugfix-19821.md new file mode 100644 index 0000000000..8cfe93389f --- /dev/null +++ b/notes/bugfix-19821.md @@ -0,0 +1 @@ +# Set the default of the Mac S/B to 64-bit \ No newline at end of file diff --git a/notes/bugfix-19832.md b/notes/bugfix-19832.md new file mode 100644 index 0000000000..a8fe9481f2 --- /dev/null +++ b/notes/bugfix-19832.md @@ -0,0 +1 @@ +# Format multi-line message box when pasting script diff --git a/notes/bugfix-19838.md b/notes/bugfix-19838.md new file mode 100644 index 0000000000..019220c5fd --- /dev/null +++ b/notes/bugfix-19838.md @@ -0,0 +1 @@ +# Add explicit 'select object' steps to the Interactive Tutorials to ensure the correct object is always selected. diff --git a/notes/bugfix-19856.md b/notes/bugfix-19856.md new file mode 100644 index 0000000000..e8cdd91c88 --- /dev/null +++ b/notes/bugfix-19856.md @@ -0,0 +1 @@ +# Prevent extension builder from duplicating logs diff --git a/notes/bugfix-19887.md b/notes/bugfix-19887.md new file mode 100644 index 0000000000..8c882d7c29 --- /dev/null +++ b/notes/bugfix-19887.md @@ -0,0 +1 @@ +# Make sure script loads correctly when Script Editor is not already opened diff --git a/notes/bugfix-19888.md b/notes/bugfix-19888.md new file mode 100644 index 0000000000..c1136485bc --- /dev/null +++ b/notes/bugfix-19888.md @@ -0,0 +1 @@ +# Fix some minor typos and errors in interactive tutorials diff --git a/notes/bugfix-19889.md b/notes/bugfix-19889.md new file mode 100644 index 0000000000..ac56b353be --- /dev/null +++ b/notes/bugfix-19889.md @@ -0,0 +1 @@ +# Allow tutorial instruction window to be moved diff --git a/notes/bugfix-19897.md b/notes/bugfix-19897.md new file mode 100644 index 0000000000..38bf5c34aa --- /dev/null +++ b/notes/bugfix-19897.md @@ -0,0 +1 @@ +# Downgrade status of HTML5 builds from "highly experimental" to "experimental" diff --git a/notes/bugfix-19940.md b/notes/bugfix-19940.md new file mode 100644 index 0000000000..3f98e6cc58 --- /dev/null +++ b/notes/bugfix-19940.md @@ -0,0 +1 @@ +# Always use Return key in tutorial instructions instead of Enter key. diff --git a/notes/bugfix-19942.md b/notes/bugfix-19942.md new file mode 100644 index 0000000000..b19b339a7e --- /dev/null +++ b/notes/bugfix-19942.md @@ -0,0 +1 @@ +# Fix typos in BMI tutorial diff --git a/notes/bugfix-19943.md b/notes/bugfix-19943.md new file mode 100644 index 0000000000..e9e74ee8d4 --- /dev/null +++ b/notes/bugfix-19943.md @@ -0,0 +1 @@ +# Fix ambiguity in a couple of BMI tutorial instructions diff --git a/notes/bugfix-19946.md b/notes/bugfix-19946.md new file mode 100644 index 0000000000..ed332d3261 --- /dev/null +++ b/notes/bugfix-19946.md @@ -0,0 +1,9 @@ +# Add extension search folders preference +Any folder containing a folder containing an extension selected for +loading by the user is added to the `cDeveloperExtensionsFolders` +preference. There is now a new preference +`cDeveloperExtensionsActiveFolders` which controls which of the +folders are actually searched for extensions in the extension +builder. This preference can be set using the cog at the top-right +of the extension builder stack. + diff --git a/notes/bugfix-19951.md b/notes/bugfix-19951.md new file mode 100644 index 0000000000..f866988317 --- /dev/null +++ b/notes/bugfix-19951.md @@ -0,0 +1 @@ +# Fix a range of edge case indentation issues related to line continuation diff --git a/notes/bugfix-19961.md b/notes/bugfix-19961.md new file mode 100644 index 0000000000..275367dd90 --- /dev/null +++ b/notes/bugfix-19961.md @@ -0,0 +1 @@ +# Prevent property inspector 'set type' property editor from expanding at will diff --git a/notes/bugfix-19967.md b/notes/bugfix-19967.md new file mode 100644 index 0000000000..838ba74163 --- /dev/null +++ b/notes/bugfix-19967.md @@ -0,0 +1 @@ +# Fix second parameter evaluation for script in message box diff --git a/notes/bugfix-19969.md b/notes/bugfix-19969.md new file mode 100644 index 0000000000..e8c40f809b --- /dev/null +++ b/notes/bugfix-19969.md @@ -0,0 +1 @@ +# Geometry Manager 'Left object' alignment issue diff --git a/notes/bugfix-19978.md b/notes/bugfix-19978.md new file mode 100644 index 0000000000..fbe417dabc --- /dev/null +++ b/notes/bugfix-19978.md @@ -0,0 +1 @@ +# Ensure default script is editable from within the Extensions Builder diff --git a/notes/bugfix-19984.md b/notes/bugfix-19984.md new file mode 100644 index 0000000000..637ca2e514 --- /dev/null +++ b/notes/bugfix-19984.md @@ -0,0 +1 @@ +# Ensure custom props value comparison is case-sensitive diff --git a/notes/bugfix-19985.md b/notes/bugfix-19985.md new file mode 100644 index 0000000000..b9ec029628 --- /dev/null +++ b/notes/bugfix-19985.md @@ -0,0 +1 @@ +# Remove errant group from the script editor diff --git a/notes/bugfix-19988.md b/notes/bugfix-19988.md new file mode 100644 index 0000000000..15c36268cd --- /dev/null +++ b/notes/bugfix-19988.md @@ -0,0 +1 @@ +# Add Edit Behavior Script contextual menu item diff --git a/notes/bugfix-19998.md b/notes/bugfix-19998.md new file mode 100644 index 0000000000..9e96ebf313 --- /dev/null +++ b/notes/bugfix-19998.md @@ -0,0 +1 @@ +# Add default points for polygon graphic diff --git a/notes/bugfix-20039.md b/notes/bugfix-20039.md new file mode 100644 index 0000000000..38811d0970 --- /dev/null +++ b/notes/bugfix-20039.md @@ -0,0 +1 @@ +# Position tutorial controls in better location when using 'Do It For Me' diff --git a/notes/bugfix-20040.md b/notes/bugfix-20040.md new file mode 100644 index 0000000000..f5b4939c63 --- /dev/null +++ b/notes/bugfix-20040.md @@ -0,0 +1 @@ +# Use smaller images of todo list on smaller screens diff --git a/notes/bugfix-20041.md b/notes/bugfix-20041.md new file mode 100644 index 0000000000..13fa21b1c9 --- /dev/null +++ b/notes/bugfix-20041.md @@ -0,0 +1 @@ +# Prevent tutorials breaking when stack name is changed diff --git a/notes/bugfix-20044.md b/notes/bugfix-20044.md new file mode 100644 index 0000000000..cb7de3b2c4 --- /dev/null +++ b/notes/bugfix-20044.md @@ -0,0 +1 @@ +# Detect specific errors in user scripts in tutorial diff --git a/notes/bugfix-20046.md b/notes/bugfix-20046.md new file mode 100644 index 0000000000..6855c2d544 --- /dev/null +++ b/notes/bugfix-20046.md @@ -0,0 +1 @@ +# Ensure there are separate scripting / apply steps in tutorial diff --git a/notes/bugfix-20064.md b/notes/bugfix-20064.md new file mode 100644 index 0000000000..38ba0d2bd6 --- /dev/null +++ b/notes/bugfix-20064.md @@ -0,0 +1 @@ +# Show only valid provisioning profiles on iOS Standalone Settings diff --git a/notes/bugfix-20071.md b/notes/bugfix-20071.md new file mode 100644 index 0000000000..5434525d2f --- /dev/null +++ b/notes/bugfix-20071.md @@ -0,0 +1 @@ +# Make default handler name text grey diff --git a/notes/bugfix-20072.md b/notes/bugfix-20072.md new file mode 100644 index 0000000000..55f5e60d24 --- /dev/null +++ b/notes/bugfix-20072.md @@ -0,0 +1 @@ +# Add space above default handler list and before each name diff --git a/notes/bugfix-20074.md b/notes/bugfix-20074.md new file mode 100644 index 0000000000..ee8ea5eddb --- /dev/null +++ b/notes/bugfix-20074.md @@ -0,0 +1 @@ +# Prevent removal of initial P from default handler name diff --git a/notes/bugfix-20077.md b/notes/bugfix-20077.md new file mode 100644 index 0000000000..ab155df86a --- /dev/null +++ b/notes/bugfix-20077.md @@ -0,0 +1 @@ +# Default to 3-column tools palette diff --git a/notes/bugfix-20094.md b/notes/bugfix-20094.md new file mode 100644 index 0000000000..72c1abbc58 --- /dev/null +++ b/notes/bugfix-20094.md @@ -0,0 +1 @@ +# Fix multi-line message box not executing if the first line is a comment diff --git a/notes/bugfix-20102.md b/notes/bugfix-20102.md new file mode 100644 index 0000000000..eaf04d385c --- /dev/null +++ b/notes/bugfix-20102.md @@ -0,0 +1 @@ +# Don't shortcut 'is changed' property steps diff --git a/notes/bugfix-20103.md b/notes/bugfix-20103.md new file mode 100644 index 0000000000..173b1bdbde --- /dev/null +++ b/notes/bugfix-20103.md @@ -0,0 +1 @@ +# Clear highlights before epilogue of interactive tutorial diff --git a/notes/bugfix-20112.md b/notes/bugfix-20112.md new file mode 100644 index 0000000000..55d3d34afd --- /dev/null +++ b/notes/bugfix-20112.md @@ -0,0 +1 @@ +# Unlock cursor on tab-command-alt key diff --git a/notes/bugfix-20117.md b/notes/bugfix-20117.md new file mode 100644 index 0000000000..3bbac9bc35 --- /dev/null +++ b/notes/bugfix-20117.md @@ -0,0 +1 @@ +# Don't override existing users' backdrop setting diff --git a/notes/bugfix-20121.md b/notes/bugfix-20121.md new file mode 100644 index 0000000000..410454e0e4 --- /dev/null +++ b/notes/bugfix-20121.md @@ -0,0 +1 @@ +# Icon Picker: Use a popup stack for icon property setting to allow filtering diff --git a/notes/bugfix-20133.md b/notes/bugfix-20133.md new file mode 100644 index 0000000000..7d318252e3 --- /dev/null +++ b/notes/bugfix-20133.md @@ -0,0 +1 @@ +# Ensure cloning stacks or cards from the Project Browser works correctly diff --git a/notes/bugfix-20140.md b/notes/bugfix-20140.md new file mode 100644 index 0000000000..18caa44ac0 --- /dev/null +++ b/notes/bugfix-20140.md @@ -0,0 +1 @@ +# breakpoints better tracking of editor scrolling \ No newline at end of file diff --git a/notes/bugfix-20145.md b/notes/bugfix-20145.md new file mode 100644 index 0000000000..1b4376e0ee --- /dev/null +++ b/notes/bugfix-20145.md @@ -0,0 +1 @@ +# Move breakpoints appropriately when editing scripts diff --git a/notes/bugfix-20170.md b/notes/bugfix-20170.md new file mode 100644 index 0000000000..e2a7c1c323 --- /dev/null +++ b/notes/bugfix-20170.md @@ -0,0 +1 @@ +# Fixed incorrect name of PI template stack diff --git a/notes/bugfix-20171.md b/notes/bugfix-20171.md new file mode 100644 index 0000000000..e99615834a --- /dev/null +++ b/notes/bugfix-20171.md @@ -0,0 +1 @@ +# Make sure LiveCode 8+ launches correctly if only an old (livecode.rev) Preferences file is present diff --git a/notes/bugfix-20214.md b/notes/bugfix-20214.md new file mode 100644 index 0000000000..25350c8702 --- /dev/null +++ b/notes/bugfix-20214.md @@ -0,0 +1 @@ +# Breakpoints may not toggle when clicked \ No newline at end of file diff --git a/notes/bugfix-20220.md b/notes/bugfix-20220.md new file mode 100644 index 0000000000..bfd3be5b49 --- /dev/null +++ b/notes/bugfix-20220.md @@ -0,0 +1 @@ +# Ensure fillGradient window displays its full content diff --git a/notes/bugfix-20258.md b/notes/bugfix-20258.md new file mode 100644 index 0000000000..05b88d6401 --- /dev/null +++ b/notes/bugfix-20258.md @@ -0,0 +1,6 @@ +# Complete switch case and if ... then control structures + +Support has been added to the script editor for completing the `case` +statement with `break` and `if ... then` with `end if`. Due to the many +variations of the `if` control structure it will only complete with +`end if` when the last token is `then`. diff --git a/notes/bugfix-20264.md b/notes/bugfix-20264.md new file mode 100644 index 0000000000..eb3a2cf997 --- /dev/null +++ b/notes/bugfix-20264.md @@ -0,0 +1 @@ +# Fix infinite loop when looking for bracket pairs and right bracket is at the beginning of the line diff --git a/notes/bugfix-20289.md b/notes/bugfix-20289.md new file mode 100644 index 0000000000..a888bc9544 --- /dev/null +++ b/notes/bugfix-20289.md @@ -0,0 +1 @@ +# Improve dictionary sort ("me" was difficult to find) diff --git a/notes/bugfix-20307.md b/notes/bugfix-20307.md new file mode 100644 index 0000000000..8d9a9b4d31 --- /dev/null +++ b/notes/bugfix-20307.md @@ -0,0 +1 @@ +# Ensure cantSelect buttons on Broject Browser have appropriate toolTips diff --git a/notes/bugfix-20330.md b/notes/bugfix-20330.md new file mode 100644 index 0000000000..7056c496e7 --- /dev/null +++ b/notes/bugfix-20330.md @@ -0,0 +1 @@ +# Show error dialog when the name of the stack contains quotes diff --git a/notes/bugfix-20332.md b/notes/bugfix-20332.md new file mode 100644 index 0000000000..2653d7dc7d --- /dev/null +++ b/notes/bugfix-20332.md @@ -0,0 +1 @@ +# Show error dialog when choosing a provisioning profile that does not support the current application identifier diff --git a/notes/bugfix-20342.md b/notes/bugfix-20342.md new file mode 100644 index 0000000000..50cdbfe6bd --- /dev/null +++ b/notes/bugfix-20342.md @@ -0,0 +1 @@ +# Ensure selection is retained when opening/closing scripts or returning to a tab diff --git a/notes/bugfix-20345.md b/notes/bugfix-20345.md new file mode 100644 index 0000000000..02f0fdf5c9 --- /dev/null +++ b/notes/bugfix-20345.md @@ -0,0 +1 @@ +# Ensure the IDE reopens a DB connection if this was previously closed by the user diff --git a/notes/bugfix-20366.md b/notes/bugfix-20366.md new file mode 100644 index 0000000000..da1fae6f8b --- /dev/null +++ b/notes/bugfix-20366.md @@ -0,0 +1 @@ +# Add icon to edition element in docs and upgrade button for APIs not in the current edition diff --git a/notes/bugfix-20386.md b/notes/bugfix-20386.md new file mode 100644 index 0000000000..89c1ceba58 --- /dev/null +++ b/notes/bugfix-20386.md @@ -0,0 +1 @@ +# Add an options menu for a number of script editor preferences diff --git a/notes/bugfix-20388.md b/notes/bugfix-20388.md new file mode 100644 index 0000000000..3b0705d460 --- /dev/null +++ b/notes/bugfix-20388.md @@ -0,0 +1 @@ +# Layout menu buttons in script editor for platforms where they are visible diff --git a/notes/bugfix-20391.md b/notes/bugfix-20391.md new file mode 100644 index 0000000000..504653104a --- /dev/null +++ b/notes/bugfix-20391.md @@ -0,0 +1 @@ +# Fix location of upgrade button diff --git a/notes/bugfix-20392.md b/notes/bugfix-20392.md new file mode 100644 index 0000000000..17b4f42474 --- /dev/null +++ b/notes/bugfix-20392.md @@ -0,0 +1 @@ +# Type over closing brackets if they match the next char diff --git a/notes/bugfix-20431.md b/notes/bugfix-20431.md new file mode 100644 index 0000000000..2cc81d3500 --- /dev/null +++ b/notes/bugfix-20431.md @@ -0,0 +1 @@ +# Show ask and answer dialogs in correct location when the screen top is not 0 diff --git a/notes/bugfix-20439.md b/notes/bugfix-20439.md new file mode 100644 index 0000000000..e472d7c745 --- /dev/null +++ b/notes/bugfix-20439.md @@ -0,0 +1 @@ +# Scroll main property inspector group with mouse wheel and navigation keys diff --git a/notes/bugfix-20465.md b/notes/bugfix-20465.md new file mode 100644 index 0000000000..256f29e843 --- /dev/null +++ b/notes/bugfix-20465.md @@ -0,0 +1 @@ +# Fix special key codes being entered into the script editor when the option key is down diff --git a/notes/bugfix-20471.md b/notes/bugfix-20471.md new file mode 100644 index 0000000000..f95af855fe --- /dev/null +++ b/notes/bugfix-20471.md @@ -0,0 +1 @@ +# [Start Center] Ensure "Skip interactive tour and take me to the Start Center" responds to clicks diff --git a/notes/bugfix-20475.md b/notes/bugfix-20475.md new file mode 100644 index 0000000000..3bbc7049ac --- /dev/null +++ b/notes/bugfix-20475.md @@ -0,0 +1 @@ +# Improve `Go to definition` for behaviors in use diff --git a/notes/bugfix-20483.md b/notes/bugfix-20483.md new file mode 100644 index 0000000000..7c5f92e214 --- /dev/null +++ b/notes/bugfix-20483.md @@ -0,0 +1 @@ +# Ensure effects popup palettes have correct height diff --git a/notes/bugfix-20514.md b/notes/bugfix-20514.md new file mode 100644 index 0000000000..95853724ad --- /dev/null +++ b/notes/bugfix-20514.md @@ -0,0 +1 @@ +# Add a way to launch sample extension sample stacks diff --git a/notes/bugfix-20535.md b/notes/bugfix-20535.md new file mode 100644 index 0000000000..07700bebe6 --- /dev/null +++ b/notes/bugfix-20535.md @@ -0,0 +1 @@ +# Check for IDE stacks correctly when toggling `Suppress Messages` diff --git a/notes/bugfix-20536.md b/notes/bugfix-20536.md new file mode 100644 index 0000000000..03493feed6 --- /dev/null +++ b/notes/bugfix-20536.md @@ -0,0 +1 @@ +# Check for IDE stacks correctly when suspending development tools diff --git a/notes/bugfix-20537.md b/notes/bugfix-20537.md new file mode 100644 index 0000000000..a10e2cea5e --- /dev/null +++ b/notes/bugfix-20537.md @@ -0,0 +1 @@ +# Navigate the property inspector tabs with Control+tab diff --git a/notes/bugfix-20557.md b/notes/bugfix-20557.md new file mode 100644 index 0000000000..a87a3226c0 --- /dev/null +++ b/notes/bugfix-20557.md @@ -0,0 +1 @@ +# Ensure installation of custom widgets works, and their documentation is added to the dictionary diff --git a/notes/bugfix-20558.md b/notes/bugfix-20558.md new file mode 100644 index 0000000000..95dcc3c4ee --- /dev/null +++ b/notes/bugfix-20558.md @@ -0,0 +1 @@ +# Allow enabling NFC support in the Android Standalone Settings diff --git a/notes/bugfix-20560.md b/notes/bugfix-20560.md new file mode 100644 index 0000000000..8ca73035d0 --- /dev/null +++ b/notes/bugfix-20560.md @@ -0,0 +1 @@ +# Improve layout of dictionary filter list diff --git a/notes/bugfix-20561.md b/notes/bugfix-20561.md new file mode 100644 index 0000000000..ff34d0d3a3 --- /dev/null +++ b/notes/bugfix-20561.md @@ -0,0 +1 @@ +# Fix 'show documentation' for widgets diff --git a/notes/bugfix-20603.md b/notes/bugfix-20603.md new file mode 100644 index 0000000000..9ed04c55f0 --- /dev/null +++ b/notes/bugfix-20603.md @@ -0,0 +1 @@ +# Fix error when building standalone with extension with resources diff --git a/notes/bugfix-20618.md b/notes/bugfix-20618.md new file mode 100644 index 0000000000..6df514c97c --- /dev/null +++ b/notes/bugfix-20618.md @@ -0,0 +1 @@ +# Make ideDocsFetchLibraryEntries public diff --git a/notes/bugfix-20619.md b/notes/bugfix-20619.md new file mode 100644 index 0000000000..24aeef61d7 --- /dev/null +++ b/notes/bugfix-20619.md @@ -0,0 +1 @@ +# Property Inspector / Geometry: Limit Object check box not selected correctly diff --git a/notes/bugfix-20621.md b/notes/bugfix-20621.md new file mode 100644 index 0000000000..0b4f2f3c9d --- /dev/null +++ b/notes/bugfix-20621.md @@ -0,0 +1 @@ +# Script Editor: Fix indention for some IF forms diff --git a/notes/bugfix-20645.md b/notes/bugfix-20645.md new file mode 100644 index 0000000000..a01880ae6c --- /dev/null +++ b/notes/bugfix-20645.md @@ -0,0 +1,3 @@ +# Create mobile scroller when reopening a Data Grid + +When running on mobile the DataGrid mobile scroller was not being created if a DataGrid was closed and then opened again. For example, if you navigated away from a card with a DataGrid and then returned to the card. \ No newline at end of file diff --git a/notes/bugfix-20646.md b/notes/bugfix-20646.md new file mode 100644 index 0000000000..875ac8a2a5 --- /dev/null +++ b/notes/bugfix-20646.md @@ -0,0 +1 @@ +# Prevent error when building a custom widget's Guide diff --git a/notes/bugfix-20647.md b/notes/bugfix-20647.md new file mode 100644 index 0000000000..4a82bc73c0 --- /dev/null +++ b/notes/bugfix-20647.md @@ -0,0 +1 @@ +# Ensure Dictionary responds to cmd+W shortcut diff --git a/notes/bugfix-20666.md b/notes/bugfix-20666.md new file mode 100644 index 0000000000..75a7ada7d7 --- /dev/null +++ b/notes/bugfix-20666.md @@ -0,0 +1 @@ +# Property Inspector / Geometry: Remove All button does not work diff --git a/notes/bugfix-20672.md b/notes/bugfix-20672.md new file mode 100644 index 0000000000..29281d9a72 --- /dev/null +++ b/notes/bugfix-20672.md @@ -0,0 +1 @@ +# Fix very slow arrow key nudge of multiple objects diff --git a/notes/bugfix-20673.md b/notes/bugfix-20673.md new file mode 100644 index 0000000000..0c6c4835ef --- /dev/null +++ b/notes/bugfix-20673.md @@ -0,0 +1 @@ +# Ensure custom widget's `guide.md` is added to the Dictionary Guides diff --git a/notes/bugfix-20692.md b/notes/bugfix-20692.md new file mode 100644 index 0000000000..ac80f8195b --- /dev/null +++ b/notes/bugfix-20692.md @@ -0,0 +1 @@ +# Add search in scripts to `Find in` script editor contextual menu diff --git a/notes/bugfix-20701.md b/notes/bugfix-20701.md new file mode 100644 index 0000000000..f5a11b3dbc --- /dev/null +++ b/notes/bugfix-20701.md @@ -0,0 +1 @@ +# Make manual height of PI consitent, increase value field in Custom Props diff --git a/notes/bugfix-20706.md b/notes/bugfix-20706.md new file mode 100644 index 0000000000..4c88c88db2 --- /dev/null +++ b/notes/bugfix-20706.md @@ -0,0 +1 @@ +# Ensure Ctrl | Cmd + left arrow moves cursor to beginning of line diff --git a/notes/bugfix-20713.md b/notes/bugfix-20713.md new file mode 100644 index 0000000000..e552e48d76 --- /dev/null +++ b/notes/bugfix-20713.md @@ -0,0 +1 @@ +# Enable lock/unlock text from popUp for fields diff --git a/notes/bugfix-20725.md b/notes/bugfix-20725.md new file mode 100644 index 0000000000..3cf28cec46 --- /dev/null +++ b/notes/bugfix-20725.md @@ -0,0 +1 @@ +# Show red breakpoint dot immediately when set via popUp in SE diff --git a/notes/bugfix-20736.md b/notes/bugfix-20736.md new file mode 100644 index 0000000000..3d0c595242 --- /dev/null +++ b/notes/bugfix-20736.md @@ -0,0 +1 @@ +# Fix size of label fields in script editor search and replace dialog diff --git a/notes/bugfix-20783.md b/notes/bugfix-20783.md new file mode 100644 index 0000000000..f36a1ab44d --- /dev/null +++ b/notes/bugfix-20783.md @@ -0,0 +1 @@ +# Import SVG from IDE file menu diff --git a/notes/bugfix-20794.md b/notes/bugfix-20794.md new file mode 100644 index 0000000000..50901b8c4a --- /dev/null +++ b/notes/bugfix-20794.md @@ -0,0 +1 @@ +# Show warning when creating a Map widget on OSX 10.9 and 10.10 diff --git a/notes/bugfix-20799.md b/notes/bugfix-20799.md new file mode 100644 index 0000000000..335972edb7 --- /dev/null +++ b/notes/bugfix-20799.md @@ -0,0 +1 @@ +# Removed errant copy/paste from DataGrid lib code diff --git a/notes/bugfix-20806.md b/notes/bugfix-20806.md new file mode 100644 index 0000000000..1b019732f3 --- /dev/null +++ b/notes/bugfix-20806.md @@ -0,0 +1 @@ +# Ensure Home and End Keys are not intercepted by the PI scroller when the target is a PI field diff --git a/notes/bugfix-20809.md b/notes/bugfix-20809.md new file mode 100644 index 0000000000..f26fef8b79 --- /dev/null +++ b/notes/bugfix-20809.md @@ -0,0 +1 @@ +# [DG2] Fixed typo preventing EditModeReorderCompleted and EditModeReorderStarted messages from being sent to the Datagrid diff --git a/notes/bugfix-20830.md b/notes/bugfix-20830.md new file mode 100644 index 0000000000..225f36889d --- /dev/null +++ b/notes/bugfix-20830.md @@ -0,0 +1 @@ +# Add `iconGravity` property to inspector diff --git a/notes/bugfix-20841.md b/notes/bugfix-20841.md new file mode 100644 index 0000000000..5a01a28344 --- /dev/null +++ b/notes/bugfix-20841.md @@ -0,0 +1 @@ +# Remove duplicate handlers from IDE diff --git a/notes/bugfix-20851.md b/notes/bugfix-20851.md new file mode 100644 index 0000000000..8acee1178f --- /dev/null +++ b/notes/bugfix-20851.md @@ -0,0 +1 @@ +# Fix adding `break` after `case` in switch control structure when one exists diff --git a/notes/bugfix-20857.md b/notes/bugfix-20857.md new file mode 100644 index 0000000000..3ec149d48f --- /dev/null +++ b/notes/bugfix-20857.md @@ -0,0 +1 @@ +# Fix widget property ordering diff --git a/notes/bugfix-20862.md b/notes/bugfix-20862.md new file mode 100644 index 0000000000..04e8d8f25d --- /dev/null +++ b/notes/bugfix-20862.md @@ -0,0 +1,16 @@ +# Fix multi-module assembly support +The extension builder now supports multi-module assemblies properly. +An extension folder can contain a main module, eg main.lcb, and any +number of support modules, named <main name>-<suffix>.lcb, which are +then compiled together into one bytecode file. + +For example, it is useful when building cross-platform extensions to +put the platform-specific code in a support module, so the extension +folder would contain for example + + button.lcb + button-android.lcb + button-ios.lcb + ... +etc + diff --git a/notes/bugfix-20879.md b/notes/bugfix-20879.md new file mode 100644 index 0000000000..61d51cc707 --- /dev/null +++ b/notes/bugfix-20879.md @@ -0,0 +1 @@ +# Fix error in script editor find behavior on first open diff --git a/notes/bugfix-20882.md b/notes/bugfix-20882.md new file mode 100644 index 0000000000..3a79f72da6 --- /dev/null +++ b/notes/bugfix-20882.md @@ -0,0 +1 @@ +# Ensure PI editors can control multiple props diff --git a/notes/bugfix-20894.md b/notes/bugfix-20894.md new file mode 100644 index 0000000000..06c48048be --- /dev/null +++ b/notes/bugfix-20894.md @@ -0,0 +1 @@ +# [Start Center] Ensure creating new stack with tablet Landscape button works as expected diff --git a/notes/bugfix-20901.md b/notes/bugfix-20901.md new file mode 100644 index 0000000000..2cc4417943 --- /dev/null +++ b/notes/bugfix-20901.md @@ -0,0 +1 @@ +# Fix issues with users' extension guides diff --git a/notes/bugfix-20909.md b/notes/bugfix-20909.md new file mode 100644 index 0000000000..65e0dd3db9 --- /dev/null +++ b/notes/bugfix-20909.md @@ -0,0 +1 @@ +# Fix formatting of indents in SE when autocomplete is false and autoformat is true diff --git a/notes/bugfix-20929.md b/notes/bugfix-20929.md new file mode 100644 index 0000000000..18e34bca5b --- /dev/null +++ b/notes/bugfix-20929.md @@ -0,0 +1 @@ +# Don't overwrite existing module.lcm files with new version diff --git a/notes/bugfix-20979.md b/notes/bugfix-20979.md new file mode 100644 index 0000000000..392e0d48f6 --- /dev/null +++ b/notes/bugfix-20979.md @@ -0,0 +1 @@ +# Escape `&` in recent files and window menus diff --git a/notes/bugfix-21014.md b/notes/bugfix-21014.md new file mode 100644 index 0000000000..89666d0fa7 --- /dev/null +++ b/notes/bugfix-21014.md @@ -0,0 +1 @@ +# Fix installing extensions from local .lce files diff --git a/notes/bugfix-21017.md b/notes/bugfix-21017.md new file mode 100644 index 0000000000..794193054d --- /dev/null +++ b/notes/bugfix-21017.md @@ -0,0 +1 @@ +# Add `resizeControl` to the list of handlers not to trace in the debugger as doing so locks up the IDE diff --git a/notes/bugfix-21022.md b/notes/bugfix-21022.md new file mode 100644 index 0000000000..40bb5c9aec --- /dev/null +++ b/notes/bugfix-21022.md @@ -0,0 +1 @@ +# Ensure nested groups' scripts can be searched diff --git a/notes/bugfix-21032.md b/notes/bugfix-21032.md new file mode 100644 index 0000000000..9114fa8c5a --- /dev/null +++ b/notes/bugfix-21032.md @@ -0,0 +1 @@ +# Layer tab button on iOS standalone settings below other controls diff --git a/notes/bugfix-21044.md b/notes/bugfix-21044.md new file mode 100644 index 0000000000..19b80ee9b4 --- /dev/null +++ b/notes/bugfix-21044.md @@ -0,0 +1 @@ +# Prevent removal of trailing empty lines when formatting script diff --git a/notes/bugfix-21065.md b/notes/bugfix-21065.md new file mode 100644 index 0000000000..b3e66a3dcd --- /dev/null +++ b/notes/bugfix-21065.md @@ -0,0 +1 @@ +# Set loc of extension builder generated test stack correctly on first test diff --git a/notes/bugfix-21082.md b/notes/bugfix-21082.md new file mode 100644 index 0000000000..53ed1f32c7 --- /dev/null +++ b/notes/bugfix-21082.md @@ -0,0 +1 @@ +# Notify when attempting to install package that doesn't validate diff --git a/notes/bugfix-21086.md b/notes/bugfix-21086.md new file mode 100644 index 0000000000..027fc4f2db --- /dev/null +++ b/notes/bugfix-21086.md @@ -0,0 +1 @@ +# Keep correct selection when formatting whole script diff --git a/notes/bugfix-21090.md b/notes/bugfix-21090.md new file mode 100644 index 0000000000..3f735c4892 --- /dev/null +++ b/notes/bugfix-21090.md @@ -0,0 +1 @@ +# Ensure project browser updates when DG2 controls are added to the template stack diff --git a/notes/bugfix-21093.md b/notes/bugfix-21093.md new file mode 100644 index 0000000000..c8e48ebf3f --- /dev/null +++ b/notes/bugfix-21093.md @@ -0,0 +1 @@ +# Fix the display of errors thrown by the throw command in the script editor diff --git a/notes/bugfix-21095.md b/notes/bugfix-21095.md new file mode 100644 index 0000000000..287bd460a6 --- /dev/null +++ b/notes/bugfix-21095.md @@ -0,0 +1 @@ +# Ensure extensions required by the IDE load on startup diff --git a/notes/bugfix-21100.md b/notes/bugfix-21100.md new file mode 100644 index 0000000000..4b626d82ca --- /dev/null +++ b/notes/bugfix-21100.md @@ -0,0 +1 @@ +# Ensure the defaultStack does not change after opening revVariableVisualizer stack diff --git a/notes/bugfix-21116.md b/notes/bugfix-21116.md new file mode 100644 index 0000000000..5103749059 --- /dev/null +++ b/notes/bugfix-21116.md @@ -0,0 +1 @@ +# Table style DataGrid should also have mobile scrollers diff --git a/notes/bugfix-21122.md b/notes/bugfix-21122.md new file mode 100644 index 0000000000..9590597041 --- /dev/null +++ b/notes/bugfix-21122.md @@ -0,0 +1 @@ +# Fix user stacks opening offscreen when last opened on a different monitor diff --git a/notes/bugfix-21167.md b/notes/bugfix-21167.md new file mode 100644 index 0000000000..24f3698c6d --- /dev/null +++ b/notes/bugfix-21167.md @@ -0,0 +1 @@ +# Ensure Replace history is remembered diff --git a/notes/bugfix-21169.md b/notes/bugfix-21169.md new file mode 100644 index 0000000000..e9d9f2dc5b --- /dev/null +++ b/notes/bugfix-21169.md @@ -0,0 +1 @@ +# Ensure splash screen always hides on Windows diff --git a/notes/bugfix-21172.md b/notes/bugfix-21172.md new file mode 100644 index 0000000000..11de1244d1 --- /dev/null +++ b/notes/bugfix-21172.md @@ -0,0 +1 @@ +# Fix revMail on mobile diff --git a/notes/bugfix-21174.md b/notes/bugfix-21174.md new file mode 100644 index 0000000000..5c31461a0f --- /dev/null +++ b/notes/bugfix-21174.md @@ -0,0 +1 @@ +# Ensure "Sample Stacks" window does show up in menu "Windows" diff --git a/notes/bugfix-21176.md b/notes/bugfix-21176.md new file mode 100644 index 0000000000..99647acd56 --- /dev/null +++ b/notes/bugfix-21176.md @@ -0,0 +1 @@ +# Make sure the Start Center can always show the Upgrade Options diff --git a/notes/bugfix-21179.md b/notes/bugfix-21179.md new file mode 100644 index 0000000000..8a63f9b428 --- /dev/null +++ b/notes/bugfix-21179.md @@ -0,0 +1 @@ +# Add 'show documentation' option to contextual menu in extension manager diff --git a/notes/bugfix-21202.md b/notes/bugfix-21202.md new file mode 100644 index 0000000000..739886465b --- /dev/null +++ b/notes/bugfix-21202.md @@ -0,0 +1 @@ +# Fix deselection of next find after replace in Script Editor diff --git a/notes/bugfix-21206.md b/notes/bugfix-21206.md new file mode 100644 index 0000000000..42579f7277 --- /dev/null +++ b/notes/bugfix-21206.md @@ -0,0 +1 @@ +# Fix execution error opening message box from script editor via Cmd/Ctrl+M diff --git a/notes/bugfix-21222.md b/notes/bugfix-21222.md new file mode 100644 index 0000000000..1abfa41ac8 --- /dev/null +++ b/notes/bugfix-21222.md @@ -0,0 +1 @@ +# Ensure File -> Close option is disabled when the topstack is stack revMenubar diff --git a/notes/bugfix-21232.md b/notes/bugfix-21232.md new file mode 100644 index 0000000000..a0de602586 --- /dev/null +++ b/notes/bugfix-21232.md @@ -0,0 +1 @@ +# Fix wandering breakpoints when undoing paste diff --git a/notes/bugfix-21245.md b/notes/bugfix-21245.md new file mode 100644 index 0000000000..c62499d5f6 --- /dev/null +++ b/notes/bugfix-21245.md @@ -0,0 +1 @@ +# SE indent errors with inline block comments and line continuation diff --git a/notes/bugfix-21247.md b/notes/bugfix-21247.md new file mode 100644 index 0000000000..ff01c6be5c --- /dev/null +++ b/notes/bugfix-21247.md @@ -0,0 +1 @@ +# Fix setting Project Browser Prefs from the LC Prefs pane diff --git a/notes/bugfix-21323.md b/notes/bugfix-21323.md new file mode 100644 index 0000000000..51cef8c80c --- /dev/null +++ b/notes/bugfix-21323.md @@ -0,0 +1 @@ +# correction to syntax for DG2's new props diff --git a/notes/bugfix-21379.md b/notes/bugfix-21379.md new file mode 100644 index 0000000000..eece18caeb --- /dev/null +++ b/notes/bugfix-21379.md @@ -0,0 +1 @@ +# [NavBar PI] Fix setting an itemName when navbar has more than 9 items diff --git a/notes/bugfix-21414.md b/notes/bugfix-21414.md new file mode 100644 index 0000000000..6101f95af4 --- /dev/null +++ b/notes/bugfix-21414.md @@ -0,0 +1 @@ +# Fix error when closing the Script Editor and the Find window is still open diff --git a/notes/bugfix-21418.md b/notes/bugfix-21418.md new file mode 100644 index 0000000000..aa12ca29ab --- /dev/null +++ b/notes/bugfix-21418.md @@ -0,0 +1 @@ +# Ensure arrays with comma in the key name are displayed correctly in the variable viewer window diff --git a/notes/bugfix-21430.md b/notes/bugfix-21430.md new file mode 100644 index 0000000000..4cd8e0c4fe --- /dev/null +++ b/notes/bugfix-21430.md @@ -0,0 +1 @@ +# Ensure arrowKeys work correctly when editing a control's name in the Project Browser diff --git a/notes/bugfix-21484.md b/notes/bugfix-21484.md new file mode 100644 index 0000000000..a3e6f9e5f8 --- /dev/null +++ b/notes/bugfix-21484.md @@ -0,0 +1 @@ +# Allow scroll wheel to work in PI text fields \ No newline at end of file diff --git a/notes/bugfix-21514.md b/notes/bugfix-21514.md new file mode 100644 index 0000000000..fd5c99f0d2 --- /dev/null +++ b/notes/bugfix-21514.md @@ -0,0 +1 @@ +# Automatically select text of fields in PI \ No newline at end of file diff --git a/notes/bugfix-21528.md b/notes/bugfix-21528.md new file mode 100644 index 0000000000..7f7a54f734 --- /dev/null +++ b/notes/bugfix-21528.md @@ -0,0 +1 @@ +# Ensure graphics can be reshaped more than once from the Object menu diff --git a/notes/bugfix-21555.md b/notes/bugfix-21555.md new file mode 100644 index 0000000000..dd6ae856ec --- /dev/null +++ b/notes/bugfix-21555.md @@ -0,0 +1 @@ +# Ensure mobileControlTarget() returns the long id of the target, if the target is a DataGrid diff --git a/notes/bugfix-21576.md b/notes/bugfix-21576.md new file mode 100644 index 0000000000..c53845e8b1 --- /dev/null +++ b/notes/bugfix-21576.md @@ -0,0 +1 @@ +# Split non-synonymous DataGrid commands deleteIndex and deleteIndexes as well as deleteLine and deleteLines in the documentation. diff --git a/notes/bugfix-21580.md b/notes/bugfix-21580.md new file mode 100644 index 0000000000..c822e97648 --- /dev/null +++ b/notes/bugfix-21580.md @@ -0,0 +1 @@ +# Make button "show grid" toggle diff --git a/notes/bugfix-21585.md b/notes/bugfix-21585.md new file mode 100644 index 0000000000..7f3111349d --- /dev/null +++ b/notes/bugfix-21585.md @@ -0,0 +1 @@ +# Make height of sample graphics in PI-> Effects stable diff --git a/notes/bugfix-21721.md b/notes/bugfix-21721.md new file mode 100644 index 0000000000..5278aa98d7 --- /dev/null +++ b/notes/bugfix-21721.md @@ -0,0 +1 @@ +# Keep selection when formatting handler diff --git a/notes/bugfix-21746.md b/notes/bugfix-21746.md new file mode 100644 index 0000000000..84de657b14 --- /dev/null +++ b/notes/bugfix-21746.md @@ -0,0 +1 @@ +Android Standalone Settings: disable Splash option on Indy and Business editions diff --git a/notes/bugfix-21767.md b/notes/bugfix-21767.md new file mode 100644 index 0000000000..92be62587c --- /dev/null +++ b/notes/bugfix-21767.md @@ -0,0 +1 @@ +# Added support for splash screens for iPhone XR and XSMAX diff --git a/notes/bugfix-21798.md b/notes/bugfix-21798.md new file mode 100644 index 0000000000..4d97788e73 --- /dev/null +++ b/notes/bugfix-21798.md @@ -0,0 +1 @@ +# Ensure the button's iconGravity can be set from the Property Inspector diff --git a/notes/bugfix-21802.md b/notes/bugfix-21802.md new file mode 100644 index 0000000000..8245fa1d3f --- /dev/null +++ b/notes/bugfix-21802.md @@ -0,0 +1 @@ +# Ensure textChanged msg is sent when we cut text of a field diff --git a/notes/bugfix-21809.md b/notes/bugfix-21809.md new file mode 100644 index 0000000000..a1b2339985 --- /dev/null +++ b/notes/bugfix-21809.md @@ -0,0 +1 @@ +# Ensure stack name cannot be set to a number via the Project Browser diff --git a/notes/bugfix-21834.md b/notes/bugfix-21834.md new file mode 100644 index 0000000000..e8bb171d2c --- /dev/null +++ b/notes/bugfix-21834.md @@ -0,0 +1 @@ +# Fix display of unresolvable behaviors and flag them in PB diff --git a/notes/bugfix-21841.md b/notes/bugfix-21841.md new file mode 100644 index 0000000000..9e21a6cd40 --- /dev/null +++ b/notes/bugfix-21841.md @@ -0,0 +1 @@ +# Ensure iOS minimum supported version is 8.0 diff --git a/notes/bugfix-21856.md b/notes/bugfix-21856.md new file mode 100644 index 0000000000..6b3c133a83 --- /dev/null +++ b/notes/bugfix-21856.md @@ -0,0 +1 @@ +# Ensure Plugin stacks are not loaded into memory on startup diff --git a/notes/bugfix-21885.md b/notes/bugfix-21885.md new file mode 100644 index 0000000000..632b08df7a --- /dev/null +++ b/notes/bugfix-21885.md @@ -0,0 +1 @@ +# Prevent unnecessary disk writes of revPreferences stack that can cause slowdown on Windows diff --git a/notes/bugfix-21896.md b/notes/bugfix-21896.md new file mode 100644 index 0000000000..80ddd43477 --- /dev/null +++ b/notes/bugfix-21896.md @@ -0,0 +1 @@ +# Fix Autocomplete IF-structs diff --git a/notes/bugfix-21969.md b/notes/bugfix-21969.md new file mode 100644 index 0000000000..6053468b69 --- /dev/null +++ b/notes/bugfix-21969.md @@ -0,0 +1 @@ +# Ensure the templategroup is reset before creating the tools palette diff --git a/notes/bugfix-22014.md b/notes/bugfix-22014.md new file mode 100644 index 0000000000..ddf4f2d9b6 --- /dev/null +++ b/notes/bugfix-22014.md @@ -0,0 +1 @@ +# Ensure no dialog is shown about closing the last stack in file when building a standalone diff --git a/notes/bugfix-22033.md b/notes/bugfix-22033.md new file mode 100644 index 0000000000..77b48636c8 --- /dev/null +++ b/notes/bugfix-22033.md @@ -0,0 +1 @@ +# Keep value of global props linkcolor and underlinelink diff --git a/notes/bugfix-22036.md b/notes/bugfix-22036.md new file mode 100644 index 0000000000..385ec9b0c7 --- /dev/null +++ b/notes/bugfix-22036.md @@ -0,0 +1 @@ +# Allow setting the label of a graphic from the Property Inspector diff --git a/notes/bugfix-22091.md b/notes/bugfix-22091.md new file mode 100644 index 0000000000..5a5c3667b8 --- /dev/null +++ b/notes/bugfix-22091.md @@ -0,0 +1 @@ +# Ensure selecting the same SVG icon does not cause the icon to disappear diff --git a/notes/bugfix-22092.md b/notes/bugfix-22092.md new file mode 100644 index 0000000000..6017ca80f0 --- /dev/null +++ b/notes/bugfix-22092.md @@ -0,0 +1 @@ +# Sync auto complete field when msg box is scrolled horizontally diff --git a/notes/bugfix-22137.md b/notes/bugfix-22137.md new file mode 100644 index 0000000000..43bb892562 --- /dev/null +++ b/notes/bugfix-22137.md @@ -0,0 +1 @@ +# Fix issue causing conditional breakpoints in repeat loops to only be evaluated once \ No newline at end of file diff --git a/notes/bugfix-22145.md b/notes/bugfix-22145.md new file mode 100644 index 0000000000..f63ebbbde0 --- /dev/null +++ b/notes/bugfix-22145.md @@ -0,0 +1 @@ +# Add missing variable declaration to editorcommon diff --git a/notes/bugfix-22269.md b/notes/bugfix-22269.md new file mode 100644 index 0000000000..14476e4ecd --- /dev/null +++ b/notes/bugfix-22269.md @@ -0,0 +1 @@ +# Ensure S/B includes database drivers of the correct architecture diff --git a/notes/bugfix-22285.md b/notes/bugfix-22285.md new file mode 100644 index 0000000000..b9a1affae4 --- /dev/null +++ b/notes/bugfix-22285.md @@ -0,0 +1 @@ +# Only reselect key field in customprops editor in response to a change in hilite diff --git a/notes/bugfix-22300.md b/notes/bugfix-22300.md new file mode 100644 index 0000000000..2a4486d81d --- /dev/null +++ b/notes/bugfix-22300.md @@ -0,0 +1 @@ +# Ensure right-clicking on the Project Browser object list selects the correct row diff --git a/notes/bugfix-22400.md b/notes/bugfix-22400.md new file mode 100644 index 0000000000..2b0d2cd09a --- /dev/null +++ b/notes/bugfix-22400.md @@ -0,0 +1 @@ +# Added support for unblocking http requests on Android browser diff --git a/notes/bugfix-22440.md b/notes/bugfix-22440.md new file mode 100644 index 0000000000..ef967cc0cb --- /dev/null +++ b/notes/bugfix-22440.md @@ -0,0 +1 @@ +# Fix card indentation in PB if stack name contains "of" diff --git a/notes/bugfix-22443.md b/notes/bugfix-22443.md new file mode 100644 index 0000000000..e641b3bc34 --- /dev/null +++ b/notes/bugfix-22443.md @@ -0,0 +1 @@ +# Align widget "icon" with connectors in Project Browser diff --git a/notes/bugfix-22477.md b/notes/bugfix-22477.md new file mode 100644 index 0000000000..224052d89e --- /dev/null +++ b/notes/bugfix-22477.md @@ -0,0 +1 @@ +# Fix broken links in Resource Center diff --git a/notes/bugfix-22486.md b/notes/bugfix-22486.md new file mode 100644 index 0000000000..23617caa25 --- /dev/null +++ b/notes/bugfix-22486.md @@ -0,0 +1 @@ +# Fix missing return in commoneditor scriptFormat diff --git a/notes/bugfix-22627.md b/notes/bugfix-22627.md new file mode 100644 index 0000000000..2004b8efdd --- /dev/null +++ b/notes/bugfix-22627.md @@ -0,0 +1 @@ +# Fix wandering breakpoints in when deleting lines diff --git a/notes/bugfix-22655.md b/notes/bugfix-22655.md new file mode 100644 index 0000000000..57dd0a5696 --- /dev/null +++ b/notes/bugfix-22655.md @@ -0,0 +1 @@ +# Ensure upload of a .livecode stack is possible in revOnline diff --git a/notes/bugfix-22727.md b/notes/bugfix-22727.md new file mode 100644 index 0000000000..9dd701fc3f --- /dev/null +++ b/notes/bugfix-22727.md @@ -0,0 +1 @@ +# Modal defaultStacks no longer forgotten after calling revPrintText diff --git a/notes/bugfix-22847.md b/notes/bugfix-22847.md new file mode 100644 index 0000000000..e940635bf4 --- /dev/null +++ b/notes/bugfix-22847.md @@ -0,0 +1 @@ +# Improve display of enum values in dictionary \ No newline at end of file diff --git a/notes/bugfix-22873.md b/notes/bugfix-22873.md new file mode 100644 index 0000000000..93c56faf2f --- /dev/null +++ b/notes/bugfix-22873.md @@ -0,0 +1 @@ +# Added missing text to the entry for dgEditMode. diff --git a/notes/bugfix-22897.md b/notes/bugfix-22897.md new file mode 100644 index 0000000000..22fd1c9784 --- /dev/null +++ b/notes/bugfix-22897.md @@ -0,0 +1 @@ +# Ensure colorization in the script editor is preserved on MacOS Big Sur with Source Code Pro fonts. diff --git a/notes/bugfix-22903.md b/notes/bugfix-22903.md new file mode 100644 index 0000000000..18d7e20793 --- /dev/null +++ b/notes/bugfix-22903.md @@ -0,0 +1 @@ +# Ensure RowLeftSwipeControlClicked message is sent with a target parameter diff --git a/notes/bugfix-22979.md b/notes/bugfix-22979.md new file mode 100644 index 0000000000..92fac0d377 --- /dev/null +++ b/notes/bugfix-22979.md @@ -0,0 +1 @@ +# Added dgRectOfIndex and dgRectOfLine to DataGrid documentation diff --git a/notes/bugfix-23202.md b/notes/bugfix-23202.md new file mode 100644 index 0000000000..8722fdfe01 --- /dev/null +++ b/notes/bugfix-23202.md @@ -0,0 +1 @@ +# Added missing property dgLineOfIndex to documentation. diff --git a/notes/bugfix-23219.md b/notes/bugfix-23219.md new file mode 100644 index 0000000000..3656018e71 --- /dev/null +++ b/notes/bugfix-23219.md @@ -0,0 +1 @@ +# Extensionbuilder: enable display of defaultScript and userguide diff --git a/notes/bugfix-23221.md b/notes/bugfix-23221.md new file mode 100644 index 0000000000..19942d5b1d --- /dev/null +++ b/notes/bugfix-23221.md @@ -0,0 +1 @@ +# Enable show names in svgIconPicker when used in Properties Inspector diff --git a/notes/bugfix-23257.md b/notes/bugfix-23257.md new file mode 100644 index 0000000000..d7a2d6a067 --- /dev/null +++ b/notes/bugfix-23257.md @@ -0,0 +1 @@ +# Fix build error on Android when 'Allow Http Connections' button is checked diff --git a/notes/bugfix-4010.md b/notes/bugfix-4010.md new file mode 100644 index 0000000000..0e866fc251 --- /dev/null +++ b/notes/bugfix-4010.md @@ -0,0 +1 @@ +# Ensure Image/Object Library places images/objects only on user's stack diff --git a/notes/bugfix-4382.md b/notes/bugfix-4382.md new file mode 100644 index 0000000000..76ca5259c0 --- /dev/null +++ b/notes/bugfix-4382.md @@ -0,0 +1 @@ +# Add `Clear Recent Files` option to Open Recent File menu diff --git a/notes/bugfix-5787.md b/notes/bugfix-5787.md new file mode 100644 index 0000000000..5dfaad3a0d --- /dev/null +++ b/notes/bugfix-5787.md @@ -0,0 +1,3 @@ +# Drag and drop stackfiles + +You can now drag and drop stack files onto the stackFiles field in the PI. diff --git a/notes/bugfix-6289.md b/notes/bugfix-6289.md new file mode 100644 index 0000000000..1972a33211 --- /dev/null +++ b/notes/bugfix-6289.md @@ -0,0 +1 @@ +# Ensure navigation with arrow keys works in the LiveCode Preferences window diff --git a/notes/bugfix-8228.md b/notes/bugfix-8228.md new file mode 100644 index 0000000000..4ff19b05c9 --- /dev/null +++ b/notes/bugfix-8228.md @@ -0,0 +1 @@ +# Indent scripts correctly when a comment is after the line continuation character diff --git a/notes/bugfix-8704.md b/notes/bugfix-8704.md new file mode 100644 index 0000000000..b25adafb71 --- /dev/null +++ b/notes/bugfix-8704.md @@ -0,0 +1 @@ +# Ensure the autoupdater on Linux can be launched diff --git a/notes/feature-create-script-only-stack-behavior.md b/notes/feature-create-script-only-stack-behavior.md new file mode 100644 index 0000000000..36452a5615 --- /dev/null +++ b/notes/feature-create-script-only-stack-behavior.md @@ -0,0 +1,7 @@ +# Create script only stack behavior +The menu for assigning a behavior to a control has two additional options: +- Create behavior from new script only stack +- Create behavior using control script and script only stack +Either option will prompt you for a stack name and a location for the script only stack. +The new stack will be saved, assigned as the behavior of the control, and then added +to the stackfiles property of control's stack. \ No newline at end of file diff --git a/notes/feature-custom_editors.md b/notes/feature-custom_editors.md new file mode 100644 index 0000000000..dcbb82dc9f --- /dev/null +++ b/notes/feature-custom_editors.md @@ -0,0 +1,13 @@ +# Custom property inspector editors +Extensions may now include their own property inspector editors +for use when editing their properties. The stack containing the +editor, and the behavior must be named <extension id>.editor.<name>.livecode +and <extension id>.editor.<name>.behavior.livecodescript respectively. + +The editor stack must contain one group called "template", which is the +editor. It is cloned onto the inspector stack when any property that +uses it as an editor is inspected. + +Please see the [property inspector feature note](https://github.com/livecode/livecode-ide/blob/develop/notes/feature-property_inspector.md#editors) +for more details on property inspector editors. + diff --git a/notes/feature-datagrid2_edit_swipe.md b/notes/feature-datagrid2_edit_swipe.md new file mode 100644 index 0000000000..593566720d --- /dev/null +++ b/notes/feature-datagrid2_edit_swipe.md @@ -0,0 +1,195 @@ +# DataGrid 2: Edit Mode and Swipe Actions + +The DataGrid has been updated to to include an edit mode and swipe actions. This only applies to DataGrids in form mode. + +When in edit mode, customizable action and reorder controls will be displayed for each row, allowing for action handling and dynamic reordering. + +When enabled, swipe actions allow the user to drag rows left and right as well as swiping them. + +## Edit Mode + +A DataGrid can be put into edit mode by setting its *dgEditMode* property. + +``` +set the dgEditMode of group "DataGrid 1" to true +``` + +Only form DataGrids with fixed row height can be put into edit mode. + +### Action Select and Reorder Controls + +By default, when in edit mode, an action select control will appear on the right hand side of each row and a reorder control on the left. + +You can customize the appearance of these controls in 3 ways: + +The first method is to specify your own controls using the the properties *"edit mode action select control"* and *"edit mode reorder control"*. + +``` +set the dgProps["edit mode action select control"] of group "DataGrid 1" to group "my action select control" +set the dgProps["edit mode reorder control"] of group "DataGrid 1" to group empty +``` + +Setting either of these properties to empty will result in the given control not being displayed. This way you can turn reordering off, or have only the reordering controls visible. + +The second method is to handle the messages *GetEditModeActionSelectControl* and *GetEditModeReorderControl* in your row behavior script. + +``` +on GetEditModeActionSelectControl + return the long id of group "my action select control" of me +end GetEditModeActionSelectControl +``` + +You can also use this method to prevent the reordering of certain rows. For example: + +``` +on GetEditModeReorderControl + if the dgIndex of me is 5 then + return empty + end if + pass GetEditModeReorderControl +end GetEditModeReorderControl +``` + +This will mean the row with DataGrid index 5 cannot be reordered. + +The third method is to directly edit the template controls, which are hidden groups your DataGrid template stack. + +### Laying Out Rows + +When positioning controls in your row behavior script, you can take into account any edit mode controls that have been overlaid onto the row by using the rows working rect. The working rect is passed as the second parameter to the LayoutControl message that is sent to your row behavior script. + +``` +on LayoutControl pControlRect, pWorkingRect + ... +end LayoutControl +``` + +### Action Controls + +By default, when an action select control is clicked, an action control will appear on the right hand side of the corresponding row. The default action control is a delete button. + +The default behavior of a user click on the action select control can be overridden by handling the message *EditModeActionSelectControlClicked* in your row behavior. The default implementation is as follows: + +``` +on EditModeActionSelectControlClicked pTarget + EditModeShowActionControlForIndex the dgIndex of me +end EditModeActionSelectControlClicked +``` +The target of the click is passed as a parameter. The command *EditModeShowActionControlForIndex* can be used make the action control appear for the given row. + +The appearance of the action control can be customized in the same way as the action select and reorder controls: By either setting the *dgProps["edit mode action control"]* of the DataGrid, handling the message *GetActionControl* in your row behavior or editing the template control in the template stack. This allows you to potentially add multiple buttons to the action control or customize the action control for specific rows. + +By default, when the action control is clicked, the given row will be deleted. This behavior can be overridden by handling the message *EditModeActionControlClicked*. For example, if you want to display a confirmation dialog, you would add the following to your row behavior script. + +``` +on EditModeActionControlClicked pTarget + answer "Are you sure you want to delete?" with "Yes" and "No" + if it is "Yes" then + DeleteIndex the dgIndex of me + else + EditModeHideActionControl + end if +end EditModeActionControlClicked +``` + +The target of the click is passed as a parameter to the message. Use this if you want to determine where the user clicked within the action control. + +The command *EditModeHideActionControl* is used here to hide the action control and return things to the standard edit mode view. + +### Reordering + +When the user starts a dynamic reorder, the message *EditModeReorderStarted* is sent to the DataGrid. + +``` +on EditModeReorderStarted pIndex, pLineNo + ... +end EditModeReorderStarted +``` + +The DataGrid index of the row being reordered is passed as the first parameter. The position of the row within the DataGrid is passed as the second parameter. + +When a reorder has been completed, the message *EditModeReorderCompleted* is sent to the DataGrid. + +``` +on EditModeReorderCompleted pIndex, pStartLineNo, pEndLineNo + ... +end EditModeReorderCompleted +``` + +The DataGrid index of the row reordered is passed as the first parameter. The original position of the row within the DataGrid is passed as the second parameter. The new position of the row within the DataGrid is passed as the third parameter. + +## Swipe Actions + +To turn on swipe actions, set the DataGrid property *"enable swipes"* to true. + +``` +set the dgProps["enable swipes"] of group "DataGrid 1" to true +``` + +When enabled, users can drag and swipe rows left and right. + +By default, when a user drags a row left or right, a swipe control will be revealed. When a user swipes left or right, the right or left swipe control will be fully revealed. When a user clicks on the left or right swipe control, the row will be deleted. + +The appearance of the left and right swipe controls can be customized in the same way as the edit mode controls, by either setting the DataGrid properties *"left swipe control"* or *"right swipe control"*, handling the messages *"GetLeftSwipeControl"* or "GetRightSwipeControl"* or editing the template swipe control in the template stack. + +For example, if you only want the right hand side swipe control to appear, you can do the following: + +``` +set the dgProps["left swipe control"] of group "DataGrid 1" to empty +``` + +The default left and right swipe actions can be overridden by handling the messages *"RowSwipedLeft"* and *"RowSwipedRight"* in your row behavior. + +For example, if you want left swipes to immediately delete the row rather than fully reveal the right swipe control, you can do the following: + +``` +on RowSwipedLeft + DeleteIndex the dgIndex of me +end RowSwipedLeft +``` + +The command *RowSwipeShowControlForIndexAndSide* can be used to fully reveal a swipe control. For example: + +``` +dispatch "RowSwipeShowControlForIndexAndSide" to group "DataGrid 1" with 5, "left" +``` + +This will result in the left hand side swipe control being shown for the row with index 5. + +Any visible swipe control can be dismissed using the command *RowSwipeHideControl* + +``` +dispatch "RowSwipeHideControl" to group "DataGrid 1" to group "DataGrid 1" +``` + +The default behavior for when a swipe control is clicked can be overridden by handling the messages *"RowLeftSwipeControlClicked"* and *"RowLeftRightControlClicked"* in your row behavior script. + +For example: + +``` +on RowLeftRightControlClicked pTarget + switch the name of pTarget + case "archive" + ... + DeleteIndex the dgIndex of me + break + case "delete" + ... + DeleteIndex the dgIndex of me + break + default + RowSwipeHideControl + break + end switch +end RowLeftRightControlClicked +``` + +The target of the click is passed as the first parameter, allowing you to determine where in the swipe control the user clicked. + +## Enabling and Disabling Animations + +By default, all of the edit mode and swipe actions will be animated. Animations can be turned off by setting the DataGrid property *"animate actions"* to false. + +``` +set the dgProps["animate actions"] of group "DataGrid 1" to false +``` diff --git a/notes/feature-default_handlers.md b/notes/feature-default_handlers.md new file mode 100644 index 0000000000..2d3d0d7b0d --- /dev/null +++ b/notes/feature-default_handlers.md @@ -0,0 +1,20 @@ +# Default handlers +Objects no longer have default scripts that appear in the script +editor when their empty scripts are edited. Instead, all the +associated message handlers for the object type now appear in a +list underneath the list of handlers that are present in the +script. When clicked, these lines add the selected default +handler to the end of the current script. + +If there is a default script for this handler and object type +in the appropriate location +(Toolset/resources/supporting_files/default_scripts/ for +'classic' objects, <widget_path>/support/ for widgets), the +content of the handler is obtained from that script (including +preceding comments) + +If there is no default script for this handler and object type, +the handler is constructed using information from the +documentation, namely the Summary element is used as a preceding +comment to describe the handler, and then the handler declared +with all the specified parameters. diff --git a/notes/feature-default_mac_64.md b/notes/feature-default_mac_64.md new file mode 100644 index 0000000000..ec6c33a64b --- /dev/null +++ b/notes/feature-default_mac_64.md @@ -0,0 +1,3 @@ +# The IDE is now 64-bit by default on Mac + +Moreover, the "Build for Mac OS X 64-bit" is checked by default on newly created stacks in the standalone settings for OS X. Existing stacks will retain their current settings. diff --git a/notes/feature-dictionary_apis.md b/notes/feature-dictionary_apis.md new file mode 100644 index 0000000000..db92b78c3c --- /dev/null +++ b/notes/feature-dictionary_apis.md @@ -0,0 +1,5 @@ +# Dictionary APIs +The dictionary now includes extension APIs in the section of the +dictionary to which they are applicable. Library and widget APIs +appear in the LiveCode Script dictionary, and module APIs in the +LiveCode Builder dictionary. diff --git a/notes/feature-exonsusp.md b/notes/feature-exonsusp.md new file mode 100644 index 0000000000..143b948046 --- /dev/null +++ b/notes/feature-exonsusp.md @@ -0,0 +1,5 @@ +# Added "Exit on suspend" checkbox in iOS S/B + +Users can now set the .plist property of whether +their applications should exit when suspended. +Added warning as this is still experimental behaviour. \ No newline at end of file diff --git a/notes/feature-faster_dg.md b/notes/feature-faster_dg.md new file mode 100644 index 0000000000..b19ff71876 --- /dev/null +++ b/notes/feature-faster_dg.md @@ -0,0 +1,20 @@ +# Accelerated DataGrid + +The DataGrid has been updated to use the new container layer mode +feature when running in form view mode. + +To take advantage of this, the datagrid must be at top-level or +contained withing groups all having container layer mode set. It +must have showBorder set to false, and the acceleratedRendering +property must be enabled on the stack with appropriate compositor +property settings. + +To get the maximum benefit from accelerated rendering, the behavior +script for a row template should changing properties within the +template unnecessarily. + +A new datagrid property `minimal layout` has been added. When this +property is true, a row template will only receive the `LayoutControl` +message if its data or its width or height has changed as opposed +to every time its rect changes (e.g. due to scrolling). + diff --git a/notes/feature-first_run_backdrop.md b/notes/feature-first_run_backdrop.md new file mode 100644 index 0000000000..5caacbd033 --- /dev/null +++ b/notes/feature-first_run_backdrop.md @@ -0,0 +1,4 @@ +# First run backdrop +The IDE now has a backdrop by default on first-run. This can be +turned off as usual via the view menu. Users with existing preferences +should be unaffected. diff --git a/notes/feature-ide_script_edited.md b/notes/feature-ide_script_edited.md new file mode 100644 index 0000000000..3a7dc64a2e --- /dev/null +++ b/notes/feature-ide_script_edited.md @@ -0,0 +1,10 @@ +# ideScriptEdited message + +A new IDE message has been added: + + ideScriptEdited pScript, pObj + +This message is sent when the script of an object as displayed +in the script editor is changed. pScript contains the current +contents of the script editor field for pObj, which, until applied, +is not necessarily the same as `the script of pObj`. diff --git a/notes/feature-live_errors.md b/notes/feature-live_errors.md new file mode 100644 index 0000000000..2df604d693 --- /dev/null +++ b/notes/feature-live_errors.md @@ -0,0 +1,4 @@ +# Live Script Parsing Errors + +The script editor has been enhanced to indicate parsing errors as the +script is edited. This provides immediate feedback on incorrect syntax. diff --git a/notes/feature-nested_behaviors_in_project_browser.md b/notes/feature-nested_behaviors_in_project_browser.md new file mode 100644 index 0000000000..d3ba0c0459 --- /dev/null +++ b/notes/feature-nested_behaviors_in_project_browser.md @@ -0,0 +1,6 @@ +# Show up to 10 nested behavior in the Project Browser + +It is now possible to view up to 10 nested behaviors of an object in the PB. +The behaviors are shown using oval graphics. +Clicking on the graphic takes you to the script of the behavior. +The tooltip of the graphic shows the long name of the behavior. diff --git a/notes/feature-property_inspector.md b/notes/feature-property_inspector.md index e633c2618e..c3058ceca7 100644 --- a/notes/feature-property_inspector.md +++ b/notes/feature-property_inspector.md @@ -99,9 +99,10 @@ override the defaults. ### Editors Currently an editor must be a stack consisting of a group named -"template" and a button named "behavior". The property inspector looks -up the specified editor for a given property, clones the template -group, and sets its behavior to the long id of the button. +"template", together with an editor behavior script-only stack. +The property inspector looks up the specified editor for a given +property, clones the template group, and sets its behavior to the +stack script. The behavior script must at a minimum implement the following three handlers: @@ -165,3 +166,6 @@ There are also some bespoke editors for particular object properties: It is our intention that ultimately a widget alone will be able to function as a property editor, however currently this feature is not available. + +See the [editors folder of the IDE repository](https://github.com/livecode/livecode-ide/tree/develop/Toolset/palettes/inspector/editors) +for more examples of property inspector editors. diff --git a/notes/feature-sbiosbuildno.md b/notes/feature-sbiosbuildno.md new file mode 100644 index 0000000000..f1c5af2aee --- /dev/null +++ b/notes/feature-sbiosbuildno.md @@ -0,0 +1,5 @@ +# Added Build Number to iOS Standalone Builder + +This will add a Build Number to the plist file +of the standalone builder, enabling resubmission of the +same build to the app store multiple times \ No newline at end of file diff --git a/notes/feature-script_editor_handler_menu.md b/notes/feature-script_editor_handler_menu.md new file mode 100644 index 0000000000..b5a6cca28b --- /dev/null +++ b/notes/feature-script_editor_handler_menu.md @@ -0,0 +1,14 @@ +# Script editor handler menu +The Handler menu of the script editor menubar has been modified +in accordance with the default handler changes to the script +editor handler list. It now has the following structure: + +Go to handler... + -> list of extant handlers +Add default handler... + -> list of default handlers +Show default handlers + +The show default handlers menu item toggles the script editor +preference to show the default handler list, which defaults +to true. diff --git a/notes/feature-script_extensions.md b/notes/feature-script_extensions.md new file mode 100644 index 0000000000..72ebac2f29 --- /dev/null +++ b/notes/feature-script_extensions.md @@ -0,0 +1,88 @@ +# Script Extensions +Support has been added for installing script libraries contained +in livecode extension packages (.lce files). + +## extensionInitialize and extensionFinalize messages + +`extensionInitialize` and `extensionFinalize` handlers should be implemented +to govern how the script library extension is loaded in the IDE and in +a standalone. + +### Example + + on extensionInitialize + if the target is not me then + pass extensionInitialize + end if + + insert the script of me into back + + if the environment contains "development" then + -- Do IDE-specific initialisation + end if + end extensionInitialize + + on extensionFinalize + if the target is not me then + pass extensionFinalize + end if + + remove the script of me from back + end extensionFinalize + +## extensionStartupScript message + +A `extensionStartupScript` handler can be implemented to provide code +which will be executed after the library is loaded in a standalone +application. + +### Example + + on extensionStartupScript + if the target is not me then + pass extensionStartupScript + end if + + -- Initialise library for use in standalone + end extensionStartupScript + +## Metadata +Metadata for script libraries should be contained in the library +level docs. The following docs elements are used for library +metadata: +- Title: the display name of the library +- Version: the version number (using the semantic versioning system) +- Author: the library author +- Requires: a comma-delimited list of other extension IDs (eg + widget kinds, lcb or lcs library extension ids) +- Uses: a comma-delimited list of the library's requirements when + building a standalone. Currently only android permissions and + hardware features are supported. + +Other docs elements are used for display in the docs. Any tags and +associations applied to the library in this section are applied to all +elements of the library's API. + +### Example + + script "com.livecode.library.networking" + /** + Title: My Networking Library + + Version: 1.0.0 + + Author: LiveCode + + Description: + This library provides a networking API. + + Requires: com.livecode.library.messageauthentication + + Uses: INTERNET (android permission) + + Tags: networking + */ + + on extensionInitialize + ... + \ No newline at end of file diff --git a/notes/feature-sebrackets.md b/notes/feature-sebrackets.md new file mode 100644 index 0000000000..de8c574627 --- /dev/null +++ b/notes/feature-sebrackets.md @@ -0,0 +1,14 @@ +# Script Editor - Brackets & Quotes + +Two new features have been added to the script editor: + +- The script editor will now wrap the selection when typing an opening +square bracket `[`, parenthesis `(` or double quote `"`. If the +selection is just an insertion point the insertion point is placed +between the brackets/quotes. If a larger block of text is highlighted +it the text will be wrapped by the brackets/quotes and the insertion +point will be after the replaced text. In the case of quotes an attempt +is made to ensure that a second quote is desired by counting quotes on +the line and ensuring the number is even. +- The script editor will now highlight matching pairs of square brackets +and parentheses. diff --git a/notes/feature-tutorial_load_stack.md b/notes/feature-tutorial_load_stack.md new file mode 100644 index 0000000000..fc9707dd45 --- /dev/null +++ b/notes/feature-tutorial_load_stack.md @@ -0,0 +1,9 @@ +# Interactive Tutorial syntax +The syntax `load stack <FileName>` has been added to interactive +tutorials. This allows prepared stacks to be imported as operating +stacks in the current tutorial. + +The prepared stack will be loaded from the internal resources folder +of the tutorial (i.e. from `_resources/<FileName>`). Any `cTutorialTag` +custom property of objects on the stack will be converted to tags for +objects which can subsequently be used in the current tutorial. diff --git a/tests/_testrunner.livecodescript b/tests/_testrunner.livecodescript index 36213cf151..1ab2fa1801 100644 --- a/tests/_testrunner.livecodescript +++ b/tests/_testrunner.livecodescript @@ -16,8 +16,35 @@ for more details. You should have received a copy of the GNU General Public License along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ --- FIXME provide this on the command line -constant kLogFilename = "_test_suite.log" +private function getTestRunnerBehavior + -- Compute the filename of the test runner + local tRepoPath, tStack + set the itemdelimiter to "/" + put item 1 to -4 of the effective filename of me into tRepoPath + put tRepoPath & "/tests/_testrunnerbehavior.livecodescript" into tStack + return the long id of stack tStack +end getTestRunnerBehavior + +local sStarted +local sTestsRun = false +private command startTestRunner + if sStarted then + exit startTestRunner + end if + put true into sStarted + + local tTestRunner + put getTestRunnerBehavior() into tTestRunner + set the behavior of me to tTestRunner + if the environment begins with "development" then + if not sTestsRun then + send "TestRunnerImpl_DoInvoke" to me in 0 + end if + put true into sTestsRun + else + send "TestRunnerMain" to me in 0 + end if +end startTestRunner on startup local tTarget @@ -28,124 +55,43 @@ on startup end if if tTarget is the long id of me then - if the environment begins with "development" then - send "TestRunnerInvokeAll" to me in 0 - else - send "TestRunnerMain" to me in 0 - end if + startTestRunner end if -end startup +end startup on openStack if the long id of the target is the long id of this card of me then - send "TestRunnerInvokeAll" to me in 0 + startTestRunner end if end openStack ----------------------------------------------------------------- --- Command-line processing ----------------------------------------------------------------- - -private function getCommandLineInfo - local tRawArg, tSelfCommand, tSelfScript, tInArgs, tArgs - - put false into tInArgs - - -- Treat everything up to & including the first - -- ".livecodescript" file as the command for running the test - -- runner, and everything after it as test runner arguments - put the commandName into tSelfCommand[1] - repeat for each element tRawArg in the commandArguments - - if tInArgs then - put tRawArg into tArgs[1 + the number of elements in tArgs] - else - put tRawArg into tSelfCommand[1 + the number of elements in tSelfCommand] - if tRawArg ends with ".livecodescript" then - put tRawArg into tSelfScript - put true into tInArgs - end if - end if - - end repeat - - local tInfo - put tSelfCommand into tInfo["self-command"] - put tSelfScript into tInfo["self-script"] - put tArgs into tInfo["args"] - - return tInfo -end getCommandLineInfo - ---------------------------------------------------------------- -- Top-level actions ---------------------------------------------------------------- -command TestRunnerMain - local tInfo - put getCommandLineInfo() into tInfo - logInit - - switch tInfo["args"][1] - case "run" - doRun tInfo - break - case "--help" - case "-h" - case "help" - doUsage 0 - break - default - doUsage 1 - break - end switch - quit 0 -end TestRunnerMain - -command TestRunnerInvokeAll - logInit +command TestRunnerImpl_DoInvoke pInfo + TestRunnerRunLoadLibraries + TestRunnerInvokeLoadLibraries + + -- Don't output to stdout + TestOutputToVariable - if there is not a stack "home" then - invokeLoadIDE + if pInfo["invoke"]["script"] is not empty then + invokeTest pInfo + else + invokeAllTests end if - invokeAllTests -end TestRunnerInvokeAll +end TestRunnerImpl_DoInvoke -private command doRun pInfo - if pInfo["args"][2] is empty then - doUsage 1 - end if +command TestRunnerImpl_DoRun pInfo + runAllTests pInfo + return the result for value +end TestRunnerImpl_DoRun - runLoadLibrary pInfo - - local tAnalysis - runAllTests pInfo - put the result into tAnalysis - - -- Save the log to file. - -- We process to binary data ourselves to ensure encoding and - -- line endings are appropriate. - local tLogForWriting - put textEncode(tAnalysis["log"], "utf8") into tLogForWriting - if the platform is "win32" then - replace return with numToChar(13) & numToChar(10) in tLogForWriting - end if - put tLogForWriting into url ("binfile:" & kLogFilename) - - if TesterTapGetWorstResult(tAnalysis) is "FAIL" then - quit 1 - end if -end doRun - -private command doUsage pStatus +private command TestRunnerImpl_DoUsage pStatus write "Usage: _testrunner.livecodescript run DEV-ENGINE" & return to stderr quit pStatus -end doUsage - -on ErrorDialog pExecutionError - write "ERROR:" && pExecutionError & return to stderr - quit 1 -end ErrorDialog +end TestRunnerImpl_DoUsage ---------------------------------------------------------------- -- Support for invoking test commands @@ -160,49 +106,119 @@ private command invokeLoadIDE put "Toolset/home.livecodescript" into item -2 to -1 of tFilename local tStackName + -- load home stack put the name of stack tFilename into tStackName + + -- Set the 'test environment' to true + dispatch "revSetTestEnvironment" to stack tStackName with true insert the script of tStackName into back - dispatch "startup" to tStackName - open tStackName + dispatch "startup" to tStackName + TestAssert "IDE startup without error", the result is empty - -- Set the 'test environment' to true - revSetTestEnvironment true + open tStackName end invokeLoadIDE -private command invokeAllTests +private command TestLoadIDE + if there is not a stack "home" then + local tDefaultFolder + put the defaultFolder into tDefaultFolder + + try + invokeLoadIDE + catch tError + end try + + TestAssert "Home stack opens without error", tError is empty + TestDiagnostic tError + + TestAssert "IDE load preserves defaultFolder", \ + the defaultFolder is tDefaultFolder + + TestDiagnostic "original default folder:" && tDefaultFolder + TestDiagnostic "new default folder:" && the defaultFolder + end if + -- gRevDevelopment should be true by default global gRevDevelopment put true into gRevDevelopment - invokeLoadLibrary + local tStartupError + put revEnvironmentGetStartupLog("Error") into tStartupError + TestAssert "Home stack opens without error", tStartupError is empty + + if tStartupError is not empty then + TestDiagnostic revEnvironmentGetStartupLog("Message") + end if - local tTopLevel - put revIDESpecialFolderPath("IDE") & "/tests" into tTopLevel + local tAnalysis + TestUpdateAnalysis the effective filename of me, \ + "TestLoadIDE", tAnalysis + return tAnalysis +end TestLoadIDE + +private command TestUpdateAnalysis pFilename, pTestCommand, @xAnalysis + local tOutput + put TestFetchAndClearOutput() into tOutput + write textEncode(tOutput,"utf-8") to stdout + TestRunnerProcessOutput pFilename, pTestCommand, tOutput + put TesterTapCombine(xAnalysis, the result) into xAnalysis +end TestUpdateAnalysis + +private command appendToList pElt, @xList + put pElt into xList[the number of elements in xList + 1] +end appendToList + +private function getAllTestFileNames + local tIDETests, tIDESupportTests + put TestGetIDERepositoryPath() & "/tests" into tIDETests + put TestGetEngineRepositoryPath() & "/tests/ide-support" into tIDESupportTests + + local tFiles + repeat for each element tFile in TesterGetTestFileNames(tIDETests) + appendToList tIDETests & slash & tFile, tFiles + end repeat - local tFile, tAnalysis - repeat for each element tFile in TesterGetTestFileNames(tTopLevel) - invokeTestScript tTopLevel & slash & tFile + repeat for each element tFile in TesterGetTestFileNames(tIDESupportTests) + appendToList tIDESupportTests & slash & tFile, tFiles + end repeat + + return tFiles +end getAllTestFileNames + +private command invokeAllTests + local tAnalysis + TestLoadIDE + put the result into tAnalysis + + repeat for each element tFile in getAllTestFileNames() + invokeTestScript tFile put TesterTapCombine(tAnalysis, the result) into tAnalysis end repeat - runPrintSummary tAnalysis + TesterRunPrintSummary tAnalysis quit 0 end invokeAllTests +private command invokeTest pInfo + local tScriptFile, tCommand + + -- This should auto-load the test script + put pInfo["invoke"]["script"] into tScriptFile + put pInfo["invoke"]["command"] into tCommand + TestRunnerInvokeTestCommand tScriptFile, tCommand +end invokeTest + -- Run the tests found in one specific script file private command invokeTestScript pScriptFile -- Don't output to stdout TestOutputToVariable - + local tCommand, tAnalysis, tOutput repeat for each element tCommand in TesterParseTestCommandNames(pScriptFile) invokeTestCommand pScriptFile, tCommand - put TestFetchAndClearOutput() into tOutput - write textEncode(tOutput,"utf-8") to stdout - runTestProcessOutput pScriptFile, tCommand, tOutput - put TesterTapCombine(tAnalysis, the result) into tAnalysis + TestUpdateAnalysis pScriptFile, tCommand, tAnalysis end repeat return tAnalysis end invokeTestScript @@ -213,42 +229,13 @@ private command invokeTestCommand pScriptFile, pCommand local tStacks put the openstacks into tStacks - local tStackName, tResult - - -- This should auto-load the test script - put the name of stack pScriptFile into tStackName - - -- Check that the stack script actually compiles - lock messages - set the script of tStackname to the script of tStackname - put the result into tResult - unlock messages - if tResult is not empty then - TestDiagnostic tResult - end if - TestAssert "script compiles", tResult is empty - --Make sure this is not the default stack create stack set the defaultStack to the short name of it + + TestRunnerInvokeTestCommand pScriptFile, pCommand - -- Dispatch the test setup command, and check if skipping was requested - dispatch "TestSetup" to tStackName - put the result into tResult - if word 1 of tResult is "SKIP" then - TestSkip pCommand, word 2 to -1 of tResult - else - -- Run the actual test itself - try - dispatch pCommand to tStackName - catch tError - TestAssert "execution failure:" && tError, false - end try - - -- Do common cleanup tasks - dispatch "TestTearDown" to tStackName - end if - + -- Attempt to restore IDE to its pre-test state global gRevStackStatus repeat for each line tStack in the openstacks if tStack is not among the lines of tStacks then @@ -259,208 +246,74 @@ private command invokeTestCommand pScriptFile, pCommand end repeat end invokeTestCommand --- Add the unit test library stack and the input library to the backscripts -private command invokeLoadLibrary - local tLibrary, tStackName, tStackFile, tRepoPath - put revEnvironmentRepositoryPath() into tRepoPath - repeat for each item tLibrary in "_testlib,_inputlib,_testerlib" - -- Compute the filename of the library stack and load it - put tRepoPath & slash & "tests" & slash & tLibrary & ".livecodescript" into tStackFile - put the name of stack tStackFile into tStackName - - send "revLoadLibrary" to stack tStackname - end repeat -end invokeLoadLibrary - - ---------------------------------------------------------------- -- Support for running tests ---------------------------------------------------------------- --- Add the test runner library stack to the backscripts -private command runLoadLibrary pInfo - -- Compute the filename of the library stack - local tFilename - put pInfo["self-script"] into tFilename - - set the itemDelimiter to slash - put "_testerlib.livecodescript" into item -1 of tFilename - put "../" before tFilename - -- Load the library - local tStackname - put the name of stack tFilename into tStackname - - send "revLoadLibrary" to stack tStackname -end runLoadLibrary - -- Launch this stack in the IDE private command runAllTests pInfo local tAnalysis - + -- Invoke the test in a subprocess. This ensures that we can detect -- if a crash occurs local tTestOutput, tTestExitStatus, tCommand -- First put the target engine into the command to run put pInfo["args"][2] into tCommand - + -- Add the command line args repeat with x = 3 to the number of elements in pInfo["args"] put tCommand && pInfo["args"][x] into tCommand end repeat -- Add the target stack (this one) - put tCommand && pInfo["self-script"] into tCommand + put tCommand && pInfo["self-script"] && "2>/dev/null" into tCommand -- Execute the shell command - put shell(tCommand) into tTestOutput - put the result into tTestExitStatus + open process tCommand for text read + set the itemDelimiter to ":" + repeat + if tCommand is not among the lines of the openProcesses then + exit repeat + end if + + local tResult + read from process tCommand for 1 line + put the result into tResult + + local tOutput + -- The output from the subprocesses will be native encoded utf-8. + put textDecode(it, "utf8") into tOutput + + if item 1 of tOutput is "PASS" or \ + item 1 of tOutput is "XPASS" or \ + item 1 of tOutput is "FAIL" or \ + item 1 of tOutput is "XFAIL" then + TesterLog item 1 of tOutput, item 2 to -1 of line 1 of tOutput + else if tOutput begins with "not ok" then + write tOutput to stdout + end if + + put tOutput after tTestOutput + if tResult is not empty then + exit repeat + end if + end repeat + set the itemDelimiter to comma + close process tCommand - -- The output from the subprocesses will be native encoded utf-8. - put textDecode(tTestOutput, "utf8") into tTestOutput - -- Check the exit status. If it suggests failure, add a "not ok" stanza -- to the tail of the TAP output + --!TODO Can't get exit status from open process if tTestExitStatus is not empty then put return after tTestOutput put "not ok # Subprocess exited with status" && \ tTestExitStatus & return after tTestOutput end if - - local tUsefulOutput - repeat for each line tLine in tTestOutput - if tLine begins with "PASS:" then - put tLine & return after tUsefulOutput - else if tLine begins with "FAIL:" then - put tLine & return after tUsefulOutput - else if tLine begins with "not ok" then - put tLine & return after tUsefulOutput - end if - end repeat - write tUsefulOutput to stdout - - runTestProcessOutput "IDE", "All IDE tests", tTestOutput + + TestRunnerProcessOutput "IDE", "All IDE tests", tTestOutput put TesterTapCombine(tAnalysis, the result) into tAnalysis - runPrintSummary(tAnalysis) + TesterRunPrintSummary tAnalysis return tAnalysis end runAllTests - -private command runTestProcessOutput pScriptfile, pCommand, pOutput - -- Create test log - local tTestLog - put "###" && TesterGetPrettyTestName(pScriptFile) && pCommand \ - & return & return into tTestLog - put pOutput & return after tTestLog - - -- Analyse the results and print a summary line - local tTapResults - put TesterTapAnalyse(tTestLog) into tTapResults - - logSummaryLine tTapResults, (TesterGetPrettyTestName(pScriptFile) & ":" && pCommand) - - return tTapResults -end runTestProcessOutput - - --- Print out a table of statistics -private command runPrintSummary pAnalysis - local tSummaryString, tTotal, tDecoration - - put TesterTapGetTestCount(pAnalysis) into tTotal - - -- Format basic summary information - if pAnalysis["xfail"] is 0 and pAnalysis["fail"] is 0 then - put "All" && tTotal && "tests passed" into tSummaryString - - else if pAnalysis["fail"] is 0 then - put "All" && tTotal && "tests behaved as expected" into tSummaryString - - else - put pAnalysis["fail"] && "OF" && tTotal && "TESTS FAILED" into tSummaryString - end if - - put return after tSummaryString - - -- Add extra summary info from expected failure & skip directives - if pAnalysis["xpass"] > 0 then - put tab & pAnalysis["xpass"] && "unexpected passes" & return after tSummaryString - end if - if pAnalysis["xfail"] > 0 then - put tab & pAnalysis["xfail"] && "expected failures" & return after tSummaryString - end if - if pAnalysis["skip"] > 0 then - put tab & pAnalysis["skip"] && "skipped" & return after tSummaryString - end if - - put "================================================================" into tDecoration - put tDecoration & return before tSummaryString - put tDecoration & return after tSummaryString - - write tSummaryString to stdout -end runPrintSummary - ----------------------------------------------------------------- --- Logging helpers ----------------------------------------------------------------- - -local sLogInfo - --- Figure out what the highlighting escape codes are for the terminal --- --- FIXME this really doesn't work properly if LiveCode's stdout --- *isn't* a TTY. -private command logInit - -- We can only do colour on Linux and OS X - if the platform is not "Linux" and the platform is not "MacOS" then - put false into sLogInfo - end if - - -- Check if colouring is possible - local tTput - put shell("tput colors") into tTput - if the result is not empty or tTput <= 8 then - put false into sLogInfo - end if - - -- Get colours - put shell("tput sgr0") into sLogInfo["normal"] - put shell("tput bold") into sLogInfo["bold"] - put shell("tput setaf 1") into sLogInfo["red"] - put shell("tput setaf 2") into sLogInfo["green"] - put shell("tput setaf 3") into sLogInfo["yellow"] - put shell("tput setaf 6") into sLogInfo["cyan"] -end logInit - -private function logHighlight pString - if pString is "fail" then - return sLogInfo["red"] & sLogInfo["bold"] & pString & sLogInfo["normal"] - else if pString is "xfail" or pString is "xpass" then - return sLogInfo["yellow"] & pString & sLogInfo["normal"] - else if pString is "pass" then - return sLogInfo["green"] & pString & sLogInfo["normal"] - else if pString is "skip" then - return sLogInfo["cyan"] & pString & sLogInfo["normal"] - else - return pString - end if -end logHighlight - -private command logSummaryLine pTapResults, pTestName - local tTotal, tPassed, tWorst, tMessage - - put pTapResults["xpass"] + pTapResults["pass"] + pTapResults["skip"] into tPassed - put TesterTapGetTestCount(pTapResults) into tTotal - - put TesterTapGetWorstResult(pTapResults) into tWorst - put logHighLight(the toUpper of tWorst) into tMessage - put ":" after tMessage - if the number of chars in tWorst < 5 then - put space after tMessage - end if - - put space & pTestName after tMessage - - put space & "[" & tPassed & "/" & tTotal & "]" after tMessage - write tMessage & return to stdout -end logSummaryLine diff --git a/tests/core/ideelements/colortexts.livecodescript b/tests/core/ideelements/colortexts.livecodescript new file mode 100644 index 0000000000..bfd05a9954 --- /dev/null +++ b/tests/core/ideelements/colortexts.livecodescript @@ -0,0 +1,157 @@ +script "CoreGraphics" +/* +Copyright (C) 2015 LiveCode Ltd. + +This file is part of LiveCode. + +LiveCode is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License v3 as published by the Free +Software Foundation. + +LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ + +on TestGrayNamesToColors + local tColorNames + local tGrayValue + local tRGB + local tColorRGBValue + + put the colornames into tColorNames + filter tColorNames with "Gray*" + TestAssert "Gray colors are among color names", tColorNames is not empty + repeat for each line tColor in tColorNames + put tColor into tGrayValue + replace "Gray" with empty in tGrayValue + put revIDENamedColorToRGB(tColor) into tRGB + if tGrayValue is not empty then + # use the engine to convert from colorname to rgb value + put round(tGrayValue*255/100) into tColorRGBValue + else + # special case "Gray" is 190,190,190 + put 190 into tColorRGBValue + end if + TestAssert tColor && "is a valid Gray shade", item 1 of tRGB is item 2 of tRGB and item 2 of tRGB is item 3 of tRGB + TestAssert tColor && "is" && tColorRGBValue && "but should be" && tRGB, item 1 of tRGB is tColorRGBValue + end repeat +end TestGrayNamesToColors + +on TestGrayColorsToNames + local tColorNames + local tGrayValue + local tColorName + local tRGB + local tGrayRGB + + put the colornames into tColorNames + filter tColorNames with "Gray*" + TestAssert "Gray colors are among color names", tColorNames is not empty + repeat for each line tColor in tColorNames + put tColor into tGrayValue + replace "Gray" with empty in tGrayValue + if tGrayValue is not empty then + put round(tGrayValue*255/100) into tRGB + else + put 190 into tRGB + end if + # the next line looks up the value in colorsToNames.txt + put tRGB,tRGB,tRGB into tGrayRGB + put revIDERGBToNamedColor(tGrayRGB) into tColorName + # Gray100 is 255,255,255 which is a alias for White + if tColor is "Gray100" then + put "White" into tColor + end if + TestAssert tColor && "is" && tColorName && "but should be" && tColor, tColor is tColorName + TestAssert tColor && "rgb value is" && tGrayRGB, tColor is tColorName + end repeat +end TestGrayColorsToNames + +on TestNamesToColors + local tColorRGBValue + local tRGB + + repeat for each line tColor in the colornames + # get the RGB value from the engine + put revIDENamedColorToRGB(tColor) into tColorRGBValue + # get the actual RGB value + put revIDENamedColorToRGB(tColor) into tRGB + TestAssert tColor && "rgb value is" && tColorRGBValue && "but should be" && tRGB, tRGB is tColorRGBValue + end repeat +end TestNamesToColors + +# handle the aliased colors +private function DisambiguateColorName pColorName + switch pColorName + case "MediumAquamarine" + return "Aquamarine3" + case "Azure1" + return "Azure" + case "Gray0" + return "Black" + case "Red4" + case "OrangeRed4" + case "Firebrick4" + return "Brown4" + case "Chartreuse1" + return "Chartreuse" + case "DarkOrange1" + return "Chocolate1" + case "DarkOrange2" + return "Chocolate2" + case "DarkOrange3" + return "Chocolate3" + case "DarkOrange4" + case "SaddleBrown" + return "Chocolate4" + case "Coral1" + return "Coral" + case "CornSilk1" + return "CornSilk" + case "Magenta4" + return "DarkOrchid" + case "Salmon" + return "DarkSalmon" + case "Red3" + return "Firebrick3" + case "Gray100" + return "White" + case "Tomato4" + return "IndianRed4" + case "Ivory1" + return "Ivory" + case "LightCyan1" + return "LightCyan" + case "LightGreen" + return "PaleGreen2" + case "NavyBlue" + return "Navy" + case "Tan4" + return "Orange4" + case "Tan3" + return "Peru" + case "SeaGreen4" + return "SeaGreen" + case "Yellow1" + return "Yellow" + end switch + return pColorName +end DisambiguateColorName + +on TestColorsToNames + local tColorName + local tRGB + + repeat for each line tColor in the colornames + # get the RGB value from the engine + put revIDENamedColorToRGB(tColor) into tRGB + # get the colorname from our array + put DisambiguateColorName(revIDERGBToNamedColor(tRGB)) into tColorName + TestAssert tColor && "is the correct color name for" && tRGB && "got" && tColorName, DisambiguateColorName(tColor) is tColorName + end repeat +end TestColorsToNames + diff --git a/tests/core/idelibrary/.gitignore b/tests/core/idelibrary/.gitignore new file mode 100644 index 0000000000..40acfc5618 --- /dev/null +++ b/tests/core/idelibrary/.gitignore @@ -0,0 +1 @@ +/_TestIsFilesetStale diff --git a/tests/core/idelibrary/errors.livecodescript b/tests/core/idelibrary/errors.livecodescript new file mode 100644 index 0000000000..7606c64342 --- /dev/null +++ b/tests/core/idelibrary/errors.livecodescript @@ -0,0 +1,25 @@ +script "IDECoreErrors" +/* +Copyright (C) 2017 LiveCode Ltd. + +This file is part of LiveCode. + +LiveCode is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License v3 as published by the Free +Software Foundation. + +LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ + +constant kExtensionErrorCode = 863 +constant kExpectedError = "extension: error occurred with domain" +on TestExtensionErrorCode + TestAssert "extension error code is" && kExtensionErrorCode, \ + line kExtensionErrorCode of the scriptExecutionErrors is \ + kExpectedError +end TestExtensionErrorCode \ No newline at end of file diff --git a/tests/core/idelibrary/stackedited.livecodescript b/tests/core/idelibrary/stackedited.livecodescript new file mode 100644 index 0000000000..26e1d218e8 --- /dev/null +++ b/tests/core/idelibrary/stackedited.livecodescript @@ -0,0 +1,109 @@ +script "TestStackEdited" +/* +Copyright (C) 2016 LiveCode Ltd. + +This file is part of LiveCode. + +LiveCode is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License v3 as published by the Free +Software Foundation. + +LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ + +on __TestEdited pStackName + return revIDEStackIsEdited(pStackName) +end __TestEdited + +on TestStackNewControlEdited + local tStackName, tStackID + create stack + put it into tStackID + put the short name of tStackID into tStackName + set the defaultStack to tStackName + + revIDECreateObject "com.livecode.interface.classic.Button", tStackID, "0,0" + + TestAssert "Stack with new control is marked edited", revIDEStackIsEdited(tStackName) +end TestStackNewControlEdited + +on TestStackPropertyChangedEdited + local tStackName, tStackID + create stack + put it into tStackID + put the short name of tStackID into tStackName + revIDEPropertySet tStackID, "formatForPrinting", not the formatForPrinting of tStackID + + TestAssert "Stack with property change is marked edited", revIDEStackIsEdited(tStackName) +end TestStackPropertyChangedEdited + +on TestStackControlPropertyChangedEdited + local tStackName + create stack + put the short name of it into tStackName + set the defaultStack to tStackName + + local tButtonID + create button + put it into tButtonID + + revIDESetUnedited(tStackName) + + revIDEPropertySet tButtonID, "visible", false + + TestAssert "Stack with control property change is marked edited", revIDEStackIsEdited(tStackName) +end TestStackControlPropertyChangedEdited + +on TestStackNameChangedEdited + local tStackName + create stack + revIDEPropertySet it, "name", "TestStackNewName" + + TestAssert "Stack with name change is marked edited", revIDEStackIsEdited("TestStackNewName") +end TestStackNameChangedEdited + +on TestStackOpenFieldEdited + local tStackName + create stack + put the short name of it into tStackName + set the defaultStack to tStackName + + local tFieldID + create field + put it into tFieldID + revIDESetUnedited tStackName + + dispatch "openField" to tFieldID + + TestAssert "Stack with opened field is marked edited", revIDEStackIsEdited(tStackName) +end TestStackOpenFieldEdited + +on TestStackSavedNotEdited + local tDir + set the itemdelimiter to slash + set the defaultfolder to item 1 to -2 of the filename of me + + put "_TestStackEdited" into tDir + + create folder tDir + + local tStackName, tStackID + create stack + put it into tStackID + put the short name of tStackID into tStackName + + revIDESetEdited tStackName + + set the filename of tStackID to the folder & "/" & tDir & "/stack.livecode" + + revIDESaveStack tStackID + + TestAssert "Saved stack is marked unedited", not revIDEStackIsEdited(tStackName) + + revDeleteFolder tDir +end TestStackSavedNotEdited diff --git a/tests/core/objectprops/objectdefaultprops.livecodescript b/tests/core/objectprops/objectdefaultprops.livecodescript index 60eebaa2d7..40301a7dad 100644 --- a/tests/core/objectprops/objectdefaultprops.livecodescript +++ b/tests/core/objectprops/objectdefaultprops.livecodescript @@ -863,7 +863,7 @@ on TestTableFieldDefaultProps put "true" into tPropsA["dontWrap"] put empty into tPropsA["dropShadow"] put 0 into tPropsA["firstIndent"] - put "false" into tPropsA["fixedLineHeight"] + put "true" into tPropsA["fixedLineHeight"] put empty into tPropsA["focusColor"] put empty into tPropsA["focusPattern"] put empty into tPropsA["foreColor"] @@ -1718,6 +1718,11 @@ end TestImageDefaultProps on TestPlayerDefaultProps + if the platform is "linux" then + TestSkip "player property tests", "Bug 18618" + exit TestPlayerDefaultProps + end if + local tObjectID revIDEActionCreateObject "com.livecode.interface.classic.Player" put the result into tObjectID diff --git a/tests/core/objectprops/objectprops.livecodescript b/tests/core/objectprops/objectprops.livecodescript index 0eb1cc981a..a9bdc461ac 100644 --- a/tests/core/objectprops/objectprops.livecodescript +++ b/tests/core/objectprops/objectprops.livecodescript @@ -54,6 +54,12 @@ on TestObjectTypes put true into tArray["com.livecode.interface.classic.RegularGraphic"] repeat for each key tKey in tArray + if tKey is "com.livecode.interface.classic.Player" and \ + the platform is "linux" then + TestSkip tKey && "object", "Bug 18618" + next repeat + end if + TestDiagnostic tKey revIDEActionCreateObject tKey TestAssert tKey && "object", ideObjectTypeFromObject(the result) is tKey diff --git a/tests/core/scriptstatus.livecodescript b/tests/core/scriptstatus.livecodescript new file mode 100644 index 0000000000..e7588ef1e3 --- /dev/null +++ b/tests/core/scriptstatus.livecodescript @@ -0,0 +1,100 @@ +script "TestIDEScriptStatus" +/* +Copyright (C) 2017 LiveCode Ltd. + +This file is part of LiveCode. + +LiveCode is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License v3 as published by the Free +Software Foundation. + +LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ + +local sTestStack + +on TestSetup + create stack uuid() + put it into sTestStack +end TestSetup + +on TestExplicitVariables + local tStackFiles + put the stackFiles of stack "home" into tStackFiles + split tStackFiles by comma and return + repeat for each element tStackName in tStackFiles + if there is a stack tStackName then + __RecursiveTest the long id of stack tStackName + end if + end repeat +end TestExplicitVariables + +private command __RecursiveTest pObject + if the script of pObject is not empty then + lock messages + local tStatus + put the scriptStatus of pObject into tStatus + switch tStatus + case "uncompiled" + set the script of sTestStack to the script of pObject + if the scriptStatus of sTestStack is "compiled" then + put "compiled" into tStatus + break + end if + case "error" + TestAssert "compiles" && the long name of pObject, false + break + end switch + + if tStatus is "compiled" then + set the explicitVariables to true + set the script of sTestStack to the script of pObject + set the explicitVariables to false + if the scriptStatus of sTestStack is not "compiled" then + TestAssertBroken "explicit variables" && the long name of pObject, false, "Bug 20356" + else + TestAssert "explicit variables" && the long name of pObject, true + end if + end if + unlock messages + end if + switch word 1 of pObject + case "stack" + repeat for each line tStack in the substacks of pObject + __RecursiveTest the long id of stack tStack + end repeat + repeat for each line tID in the cardIDs of pObject + __RecursiveTest the long id of card id tID of pObject + end repeat + repeat for each line tID in the sharedGroupIDs of pObject + __RecursiveTest the long id of control id tID of pObject + end repeat + break + case "card" + repeat for each line tID in the childControlIDs of pObject + if word 1 of the name of control id tID of pObject is "group" and \ + the sharedBehavior of control id tID of pObject then + next repeat + end if + __RecursiveTest the long id of control id tID of pObject + end repeat + break + case "group" + case "background" + case "bkgnd" + repeat for each line tID in the childControlIDs of pObject + __RecursiveTest the long id of control id tID of pObject + end repeat + break + default + end switch +end __RecursiveTest + +on TestTeardown + delete stack sTestStack +end TestTeardown diff --git a/tests/messagebox/errors.livecodescript b/tests/messagebox/errors.livecodescript index 480554e734..44cccc21ba 100644 --- a/tests/messagebox/errors.livecodescript +++ b/tests/messagebox/errors.livecodescript @@ -34,11 +34,70 @@ on TestTeardown end TestTeardown on TestBug17380 - // An error is thrown when running this test due to bug 17465 - /* revIDELaunchResource("sample stacks") MessageBoxIsEmpty TestAssert "message box is empty after opening revOnline stack", the result - */ -end TestBug17380 \ No newline at end of file +end TestBug17380 + +on TestMessageBoxCompileError + local tValidScript, tScript + // Should be "if true then..." + put "if true ten go home" into tScript + + ideExecuteScript tScript, empty, false, tValidScript + TestAssert "execute script with compile error result", line 1 of the result is "189,2,4,ten" + TestAssert "execute script with compile error script invalid", tValidScript is empty +end TestMessageBoxCompileError + +on TestMessageBoxExecutionError + local tValidScript, tScript + put "edit the script of stack nonexistent" into tScript + + ideExecuteScript tScript, empty, false, tValidScript + TestAssert "execute script with script error result", \ + matchText(line 1 of it, "^91,\d+,1$") + TestAssert "execute script with script error script invalid", tValidScript is tScript +end TestMessageBoxExecutionError + +on TestMessageBoxExecuteMultipleWithError + local tValidScript, tScript + put "put foo; throw bar" into tScript + + ideExecuteScript tScript, empty, false, tValidScript + TestAssert "execute multiline script with script error result", msg is "foo" + TestAssert "execute multiline script with compile error script invalid", tValidScript is tScript +end TestMessageBoxExecuteMultipleWithError + +-- Bug 17863 +on TestIntelligenceObjectGetNonExistentFunction + local tStack + create stack + put it into tStack + + local tToExecute, tValidScript + put "get aNonExistentFunction()" into tToExecute + + ideExecuteScript tToExecute, tStack, false, tValidScript + + TestAssert "intelligence object non-existent function result", \ + matchText(line 1 of it, "^219,\d+,\d+,aNonExistentFunction$") + TestAssert "intelligence object non-existent function executed", tValidScript is tToExecute +end TestIntelligenceObjectGetNonExistentFunction + +-- Bug 17241 +on TestIntelligenceObjectPutFunctionWithParamError + local tScript + put "function valueFunction pParam; return pParam; end valueFunction" into tScript + + local tStack + create stack + put it into tStack + set the script of tStack to tScript + + local tValidScript + + ideExecuteScript "put valueFunction(hello world)", tStack, false, tValidScript + TestAssert "intelligence object put function with multi-segment param error", the result is "126,2,19,world" + TestAssert "intelligence object put function with multi-segment param invalid", tValidScript is empty +end TestIntelligenceObjectPutFunctionWithParamError \ No newline at end of file diff --git a/tests/messagebox/execution.livecodescript b/tests/messagebox/execution.livecodescript index 62ef5dd582..37bb2fbbfe 100644 --- a/tests/messagebox/execution.livecodescript +++ b/tests/messagebox/execution.livecodescript @@ -38,18 +38,19 @@ on TestBug16281 create button put the long id of it into tButton - ideExecuteScript "hilite" && tButton, empty, empty, false, tValidScript + ideExecuteScript "hilite" && tButton, empty, false, tValidScript TestAssert "hilite command in msg box", the hilite of tButton end TestBug16281 on TestBug15832 - local tStack + local tStack, tStackName create stack - put the short name of it into tStack + put it into tStack + put the short name of tStack into tStackName -- Create button and field on the stack - set the defaultStack to tStack + set the defaultStack to tStackName create button create field @@ -58,7 +59,7 @@ on TestBug15832 set the defaultStack to the short name of it local tValidScript - ideExecuteScript "put the name of button 1; put the name of control 2;", tStack, empty, false, tValidScript + ideExecuteScript "put the name of button 1; put the name of control 2;", tStack, false, tValidScript TestAssert "; in single line message box", word 1 of msg is "field" end TestBug15832 @@ -66,33 +67,32 @@ end TestBug15832 on TestBug16863 local tStack create stack - put the short name of it into tStack + put it into tStack + set the defaultStack to the short name of it - ## Create a button on the stack - set the defaultStack to tStack create button set the name of it to "test" local tValidScript, tScript put "there is a button" && quote & "test" & quote into tScript - ideExecuteScript tScript, tStack, empty, false, tValidScript + ideExecuteScript tScript, tStack, false, tValidScript TestAssert "boolean expression value with 'put' prepended", msg is "true" TestAssert "boolean expression executed with 'put' prepended", tValidScript is ("put" && tScript) end TestBug16863 on TestGlobalPropertyCompleted local tValidScript - ideExecuteScript "backdrop", empty, empty, false, tValidScript + ideExecuteScript "backdrop", empty, false, tValidScript - TestAssert "global prop value with 'put the' prepended", msg is "none" + TestAssert "global prop value with 'put the' prepended", msg is the backdrop TestAssert "global prop executed with 'put the' prepended", tValidScript is "put the backdrop" put empty into msg - ideExecuteScript "the backdrop", empty, empty, false, tValidScript + ideExecuteScript "the backdrop", empty, false, tValidScript - TestAssert "global prop value with 'put' prepended", msg is "none" + TestAssert "global prop value with 'put' prepended", msg is the backdrop TestAssert "global prop executed with 'put' prepended", tValidScript is "put the backdrop" end TestGlobalPropertyCompleted @@ -106,7 +106,10 @@ on TestIntelligenceObjectMultilineCommand set the script of tStack to tScript local tValidScript - ideExecuteScript "valueCommand; put the result", empty, tStack, false, tValidScript + ideExecuteScript "valueCommand; put the result", tStack, false, tValidScript + + TestDiagnostic "msg" && msg + TestDiagnostic "valid script:" && tValidScript TestAssert "intelligence object multiple command result", msg is "value" TestAssert "intelligence object multiple command executed", tValidScript is "valueCommand; put the result" @@ -122,7 +125,7 @@ on TestIntelligenceObjectMultilineFunction set the script of tStack to tScript local tValidScript - ideExecuteScript "put valueFunction(); put msg", empty, tStack, false, tValidScript + ideExecuteScript "put valueFunction(); put msg", tStack, false, tValidScript TestAssert "intelligence object multiple function result", msg is "value" TestAssert "intelligence object multiple function executed", tValidScript is "put valueFunction(); put msg" @@ -139,14 +142,17 @@ on TestIntelligenceObject set the script of tStack to tScript local tValidScript - ideExecuteScript "valueCommand", empty, tStack, false, tValidScript + ideExecuteScript "valueCommand", tStack, false, tValidScript + + TestDiagnostic "cValue:" && the cValue of tStack + TestDiagnostic "valid script:" && tValidScript TestAssert "intelligence object command result", the cValue of tStack is "value" TestAssert "intelligence object command executed", tValidScript is "valueCommand" put empty into msg - ideExecuteScript "valueFunction()", empty, tStack, false, tValidScript + ideExecuteScript "valueFunction()", tStack, false, tValidScript TestAssert "intelligence object function in msg box", msg is "value" TestAssert "intelligence object function executed", tValidScript is "put valueFunction()" @@ -163,7 +169,7 @@ on TestIntelligenceObjectMultipleCommand set the script of tStack to tScript local tValidScript - ideExecuteScript "firstCommand; secondCommand", empty, tStack, false, tValidScript + ideExecuteScript "firstCommand; secondCommand", tStack, false, tValidScript TestAssert "intelligence object mutiple commands", the cValue of tStack is "value" end TestIntelligenceObjectMultipleCommand @@ -178,7 +184,7 @@ on TestDefaultStackCardScript set the script of card 1 of tStack to tScript local tValidScript - ideExecuteScript "preOpenCard", tStack, empty, false, tValidScript + ideExecuteScript "preOpenCard", tStack, false, tValidScript TestAssert "intelligence object command result", the cValue of tStack is "value" TestAssert "intelligence object command executed", tValidScript is "preOpenCard" @@ -195,7 +201,7 @@ on TestIntelligenceObjectPutFunction set the script of tStack to tScript local tValidScript - ideExecuteScript "put valueFunction()", empty, tStack, false, tValidScript + ideExecuteScript "put valueFunction()", tStack, false, tValidScript TestAssert "intelligence object put function", msg is "value" end TestIntelligenceObjectPutFunction @@ -211,7 +217,7 @@ on TestIntelligenceObjectGetFunction local tValidScript - ideExecuteScript "get valueFunction(); put it", empty, tStack, false, tValidScript + ideExecuteScript "get valueFunction(); put it", tStack, false, tValidScript TestAssert "intelligence object get function result", msg is "value" end TestIntelligenceObjectGetFunction @@ -226,7 +232,7 @@ on TestCustomCommandWithStringLiteral local tValidScript, tToExecute put "valueCommand" && quote & "value" & quote into tToExecute - ideExecuteScript tToExecute, empty, tStack, false, tValidScript + ideExecuteScript tToExecute, tStack, false, tValidScript TestAssert "command with string literal result", the cValue of tStack is "value" TestAssert "command with string literal executed", tValidScript is tToExecute @@ -244,27 +250,10 @@ on TestIntelligenceObjectPutFunctionWithParam local tValidScript - ideExecuteScript "put valueFunction(" & quote & "hello world" & quote & ")", empty, tStack, false, tValidScript + ideExecuteScript "put valueFunction(" & quote & "hello world" & quote & ")", tStack, false, tValidScript TestAssert "intelligence object put function with single segment param with spaces", msg is "hello world" end TestIntelligenceObjectPutFunctionWithParam --- Bug 17241 -on TestIntelligenceObjectPutFunctionWithParamError - local tScript - put "function valueFunction pParam; return pParam; end valueFunction" into tScript - - local tStack - create stack - put it into tStack - set the script of tStack to tScript - - local tValidScript - - ideExecuteScript "put valueFunction(hello world)", empty, tStack, false, tValidScript - TestAssert "intelligence object put function with multi-segment param error", the result contains "error" - TestAssert "intelligence object put function with multi-segment param invalid", tValidScript is empty -end TestIntelligenceObjectPutFunctionWithParamError - on TestIntelligenceObjectPropertyCompleted local tButton, tButtonName create button @@ -272,8 +261,8 @@ on TestIntelligenceObjectPropertyCompleted put the name of tButton into tButtonName local tValidScript - ideExecuteScript "width", empty, tButton, false, tValidScript - TestAssert "intelligence object property autocomplete result", the result is empty + ideExecuteScript "width", tButton, false, tValidScript + TestAssert "intelligence object property autocomplete result", msg is the width of tButton TestAssert "intelligence object property autocomplete executed", tValidScript is "put the width of" && tButtonName end TestIntelligenceObjectPropertyCompleted @@ -292,7 +281,7 @@ on TestIntelligenceObjectFunctionNotFirstLine put return & "put 1 into z" after tToExecute put return & "put incr(z)" after tToExecute - ideExecuteScript tToExecute, empty, tStack, false, tValidScript + ideExecuteScript tToExecute, tStack, false, tValidScript TestAssert "intelligence object command result", msg is 2 TestAssert "intelligence object command executed", tValidScript is tToExecute @@ -310,23 +299,48 @@ on TestIntelligenceObjectCommandWithTwoParams local tToExecute, tValidScript put "testParameters 1, 2" into tToExecute - ideExecuteScript tToExecute, empty, tStack, false, tValidScript + ideExecuteScript tToExecute, tStack, false, tValidScript TestAssert "intelligence object command two params result", msg is 2 TestAssert "intelligence object command two params executed", tValidScript is tToExecute end TestIntelligenceObjectCommandWithTwoParams --- Bug 17863 -on TestIntelligenceObjectGetNonExistantFunction - local tStack +on TestReferenceControlOnActiveStack + local tStack, tField create stack put it into tStack + + set the defaultStack to the short name of tStack + + create field + put it into tField + + -- change the default stack + create stack + set the defaultStack to the short name of it + + local tToExecute, tValidScript + put "put bar into field 1" into tToExecute + ideExecuteScript tToExecute, tStack, false, tValidScript - local tToExecute, tValidScript - put "get aNonExistantFunction()" into tToExecute + TestAssert "intelligence object command two params result", the text of tField is "bar" + TestAssert "intelligence object command two params executed", tValidScript is tToExecute +end TestReferenceControlOnActiveStack + +-- bug 20084 +on TestMutilineWithCommentOnFirstLine + local tStack, tField + create stack + put it into tStack + + set the defaultStack to the short name of tStack + + create field + put it into tField - ideExecuteScript tToExecute, empty, tStack, false, tValidScript + local tToExecute, tValidScript + put "-- foo" & return & "put bar into field 1" into tToExecute + ideExecuteScript tToExecute, tStack, false, tValidScript - TestAssert "intelligence object non-existant function result", the result contains "error" - TestAssert "intelligence object non-existant function executed", tValidScript is empty -end TestIntelligenceObjectGetNonExistantFunction + TestAssert "multiline script with comment on first line executes", the text of tField is "bar" +end TestMutilineWithCommentOnFirstLine diff --git a/tests/projectbrowser/order.livecodescript b/tests/projectbrowser/order.livecodescript index 45f09b86b4..03be8b646f 100644 --- a/tests/projectbrowser/order.livecodescript +++ b/tests/projectbrowser/order.livecodescript @@ -132,7 +132,7 @@ end _TestOrderPref on TestOrder repeat for each item tWhich in kSortPrefs - repeat for each item tType in "name,number" + repeat for each item tType in "name,layer" repeat for each item tOrder in "ascending,descending" _TestOrderPref tWhich, tType, tOrder end repeat diff --git a/tests/scripteditor/_indentation_tests/bug-19951.livecodescript b/tests/scripteditor/_indentation_tests/bug-19951.livecodescript new file mode 100644 index 0000000000..36a0f4a229 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/bug-19951.livecodescript @@ -0,0 +1,33 @@ +repeat \ + forever + -- code +end repeat + +switch \ + tVar + case "foo" + -- code + break + case \ + "foo" + -- code + break + default + -- code + break +end switch + +try + -- code +catch \ + tError + -- code +end try + +if something \ + then + -- code +end if + +put "foo" &\ + "bar" diff --git a/tests/scripteditor/_indentation_tests/bug-21245.livecodescript b/tests/scripteditor/_indentation_tests/bug-21245.livecodescript new file mode 100644 index 0000000000..1af9a68950 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/bug-21245.livecodescript @@ -0,0 +1,10 @@ +command inlineCommentTest \ + pBasePath, /* base path for export folders */ \ + @xRelativePath /* relative path for folder */ + -- code +end inlineCommentTest + +command quoteAfterCommentTest + put "test" -- "extra" \ + put "test" +end quoteAfterCommentTest \ No newline at end of file diff --git a/tests/scripteditor/_indentation_tests/bug-8228.livecodescript b/tests/scripteditor/_indentation_tests/bug-8228.livecodescript new file mode 100644 index 0000000000..8502940332 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/bug-8228.livecodescript @@ -0,0 +1,8 @@ +if (gDatf[tPost,i] <> "") and \ + (((gPoly[tPost] = "") and (gSurf[tPost] = gSurg[tPost,i])) or ((gPoly[tPost] <> "") and (gPoly[tPost] = gPolz[tPost,i]))) and \ + (gFra1[tPost,i] <> "") and (gFra2[tPost,i] <> "") and \ + ((gPos2[tPost,i] <> "") or (quote is in gPos2[tPost,i])) and ((gPos3[tPost,i] <> "") or (quote is in gPos3[tPost,i])) and ((gPos4[tPost,i] <> "") or (quote is in gPos4[tPost,i])) and ((gPos5[tPost,i] <> "") or (quote is in gPos5[tPost,i])) and \ + (abs(gDist[tPost]) - abs(gDisu[tPost,i]) <= 0) and \ -- (abs(abs(gDist[tPost]) - abs(gDisu[tPost,i])) <= 440) + (gBea5[tPost,i] <= 2.0) then + put tab & gDatf[tPost,i] & tab & gPos2[tPost,i] & gPos3[tPost,i] & gPos4[tPost,i] & gPos5[tPost,i] & tab & gSco1[tPost,i] & tab & gSco2[tPost,i] & tab & gSco3[tPost,i] & tab & gOdds[tPost] & return after fld "Indey" +end if diff --git a/tests/scripteditor/_indentation_tests/handlers.livecodescript b/tests/scripteditor/_indentation_tests/handlers.livecodescript new file mode 100644 index 0000000000..3d6a4f8119 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/handlers.livecodescript @@ -0,0 +1,39 @@ +on Foo pParam + -- code +end Foo + +command Foo pParam + -- code +end Foo + +private command Foo pParam + -- code +end Foo + +private on Foo pParam + -- code +end Foo + +before Foo pParam + -- code +end Foo + +after Foo pParam + -- code +end Foo + +function Foo pParam + -- code +end Foo + +private function Foo pParam + -- code +end Foo + +setProp Foo pParam + -- code +end Foo + +getProp Foo pParam + -- code +end Foo diff --git a/tests/scripteditor/_indentation_tests/if.livecodescript b/tests/scripteditor/_indentation_tests/if.livecodescript new file mode 100644 index 0000000000..d7bc724828 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/if.livecodescript @@ -0,0 +1,80 @@ +on foo + if foo() then + -- code + else if bar() then + -- code + else + -- code + end if + -- comment +end foo + +on foo + if foo() + then -- code + else if bar() then + -- code + else + -- code + end if + -- comment +end foo + +on foo + if foo() + then code + else if bar() then + -- code + else code + -- comment +end foo + +on foo + if foo() + then code + else code + -- comment +end foo + +on foo + if foo() then code else code + -- comment +end foo + +on foo + if foo() then + if bar() then code else code + else + code + end if + -- comment +end foo + +on foo + if foo() then + if bar() then code + else + code + end if + end if + -- comment +end foo + +on foo + if foo() + then code else code + -- comment +end foo + +on foo + if foo() + then + code else code + -- comment +end foo + +on foo + if foo() then + code else code + -- comment +end foo diff --git a/tests/scripteditor/_indentation_tests/repeat.livecodescript b/tests/scripteditor/_indentation_tests/repeat.livecodescript new file mode 100644 index 0000000000..595a661f89 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/repeat.livecodescript @@ -0,0 +1,83 @@ +on foo + repeat forever + -- code + end repeat + -- comment +end foo + +on foo + repeat while foo() + -- code + end repeat + -- comment +end foo + +on foo + repeat until foo() + -- code + end repeat + -- comment +end foo + +on foo + repeat 3 + -- code + end repeat + -- comment +end foo + +on foo + repeat for 3 + -- code + end repeat + -- comment +end foo + +on foo + repeat for 3 times + -- code + end repeat + -- comment +end foo + +on foo + repeat 3 times + -- code + end repeat + -- comment +end foo + +on foo + repeat with X = 1 to 5 + -- code + end repeat + -- comment +end foo + +on foo + repeat with X = 1 to 5 step 2 + -- code + end repeat + -- comment +end foo + +on foo + repeat with X = 5 down to 1 + -- code + end repeat + -- comment +end foo + +on foo + repeat with X = 5 down to 1 step 2 + -- code + end repeat + -- comment +end foo + +on foo + repeat for each line tLine in tFoo + -- code + end repeat + -- comment +end foo diff --git a/tests/scripteditor/_indentation_tests/switch.livecodescript b/tests/scripteditor/_indentation_tests/switch.livecodescript new file mode 100644 index 0000000000..0365af24b5 --- /dev/null +++ b/tests/scripteditor/_indentation_tests/switch.livecodescript @@ -0,0 +1,23 @@ +on foo + switch tFoo + case "foo" + -- code + break + default + -- code + break + end switch + -- comment +end foo + +on foo + switch + case tFoo begins with "foo" + -- code + break + default + -- code + break + end switch + -- comment +end foo diff --git a/tests/scripteditor/_indentation_tests/try.livecodescript b/tests/scripteditor/_indentation_tests/try.livecodescript new file mode 100644 index 0000000000..02ae26b56b --- /dev/null +++ b/tests/scripteditor/_indentation_tests/try.livecodescript @@ -0,0 +1,10 @@ +on foo + try + -- code + catch tError + -- code + finally + -- code + end try + -- comment +end foo diff --git a/tests/scripteditor/indentation.livecodescript b/tests/scripteditor/indentation.livecodescript new file mode 100644 index 0000000000..3bea2f3438 --- /dev/null +++ b/tests/scripteditor/indentation.livecodescript @@ -0,0 +1,68 @@ +script "ScriptEditorIndentation" +/* +Copyright (C) 2017 LiveCode Ltd. + +This file is part of LiveCode. + +LiveCode is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License v3 as published by the Free +Software Foundation. + +LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with LiveCode. If not see <http://www.gnu.org/licenses/>. */ + +local sStack + +on TestSetup + local tBehavior + put TestGetIDERepositoryPath() & "/Toolset/palettes/script editor/behaviors/revsecommoneditorbehavior.livecodescript" into tBehavior + put the name of stack tBehavior into sStack +end TestSetup + +on TestIndents + set the itemDelimiter to slash + local tPath + put item 1 to -2 of the effective filename of me & "/_indentation_tests" into tPath + set the itemDelimiter to "." + repeat for each line tFile in files(tPath) + if tFile begins with "." then + next repeat + end if + + local tScript + put textDecode(url ("binfile:" & tPath & "/" & tFile),"UTF8") into tScript + -- normalise the snippet + if the last char of tScript is not return then + put return after tScript + end if + replace tab with " " in tScript + + -- strip leading whitespace + local tUnindented + put replaceText(tScript, "\n +", return) into tUnindented + put replaceText(tUnindented, "^ +", "") into tUnindented + + dispatch "scriptFormatSnippet" to sStack with tUnindented + local tResult + put the result into tResult + if the last char of tResult is not return then + put return after tResult + end if + TestAssert "script snippet indented correctly:" && item 1 of tFile, tResult is tScript + if tResult is not tScript then + repeat with tIndex=1 to the number of lines of tResult + if line tIndex of tResult is not line tIndex of tScript then + put "* " before line tIndex of tResult + else + put " " before line tIndex of tResult + end if + end repeat + TestDiagnostic tResult + end if + end repeat +end TestIndents