| 1 | = Porting wxWidgets wx.NET C# source file to cobra = |
| 2 | |
| 3 | The .NET wrapper library ([http://wxnet.sourceforge.net wx.NET]) for [http://www.wxwidgets.org wxWidgets] is an interesting case for cobra since it is one of the few .NET libraries that |
| 4 | uses a lowercase namespace.[[br]] |
| 5 | Consequently there are some complications with persuading cobra to work with it conveniently. |
| 6 | |
| 7 | see [wiki:C#Diffs Cobra differences fm C#] |
| 8 | |
| 9 | Heres a process for C# generally with some notes re wx.NET generated from converting wx.NET sample file ListView.cs to ListView.cobra |
| 10 | |
| 11 | 1 Take .cs file, rename to .cobra file |
| 12 | |
| 13 | 2. Change multiline comments from multiple // or /* */ bounded to be /# #/ bounded.[[br]] |
| 14 | Change single line comments to use leading '#' |
| 15 | |
| 16 | Remove extraneous separator line comments between method calls |
| 17 | // ------------------------------ |
| 18 | |
| 19 | 3. Remove trailing ';' from each line they occur on |
| 20 | |
| 21 | 4. Fixup blocking and indentation. |
| 22 | |
| 23 | Remove all '{' and '}' indicating start and end blocks from source.[[br]] |
| 24 | Ensure remaining blocks are all correctly (equally) indented and that |
| 25 | indentation uses either all spaces or all Tabs and that the |
| 26 | indents are in multiples of either 4 spaces or 1 tab. |
| 27 | |
| 28 | |
| 29 | 5. Fix 'using' statements |
| 30 | ''''using'''' -> ''''use''''' |
| 31 | Remove any lines for |
| 32 | {{{ |
| 33 | using System |
| 34 | using System.Collections.Generic |
| 35 | using System.IO |
| 36 | using System.Text |
| 37 | }}} |
| 38 | as cobra includes these automagically |
| 39 | |
| 40 | Change any other lines from |
| 41 | ''''using xxxx;'''' to ''''use xxxx'''' |
| 42 | You also need to specify to use the C# wrapper library/namespace for wxWidgets (''''wx''''). |
| 43 | |
| 44 | Before ''''use System.Drawing'''' add a ''''use .. from line'''' for wx.NET |
| 45 | {{{ |
| 46 | use wx from "wx.NET" |
| 47 | use System.Drawing |
| 48 | }}} |
| 49 | or add an explicit compiler directive ref line and a 'use wx' line |
| 50 | {{{ |
| 51 | @ref "wx.NET" |
| 52 | ... |
| 53 | use wx |
| 54 | use System.Drawing |
| 55 | }}} |
| 56 | |
| 57 | 5. Namespace decl |
| 58 | Namespaces in cobra need to start with an upcased letter. |
| 59 | Remove any ''''wx.'''' prefix from namespace line ; |
| 60 | ''''namespace wx.Something'''' to ''''namespace Something'''' |
| 61 | |
| 62 | |
| 63 | 5a. Correct any Enum definitions |
| 64 | After applying the above its basically removing trailing ',' and ensuring indentation |
| 65 | of enum items is the same |
| 66 | e.g. |
| 67 | {{{ |
| 68 | enum Cmd { About, Quit, Dialog } -> |
| 69 | enum Cmd |
| 70 | About |
| 71 | Quit |
| 72 | Dialog |
| 73 | |
| 74 | enum ID_CONTROLS { |
| 75 | ID_RADIO_ORIENT = 5999, |
| 76 | ID_CHK_SHOWIMAGES, |
| 77 | ID_BTN_NEXT_PAGE, |
| 78 | ID_NOTEBOOK |
| 79 | } |
| 80 | -> |
| 81 | enum ID_CONTROLS |
| 82 | ID_RADIO_ORIENT = 5999 |
| 83 | ID_CHK_SHOWIMAGES |
| 84 | ID_BTN_NEXT_PAGE |
| 85 | ID_NOTEBOOK |
| 86 | }}} |
| 87 | |
| 88 | |
| 89 | 6. Fix class declaration syntax |
| 90 | Change lines like ''''class X : Y'''' to ''''class X inherits Y'''' |
| 91 | |
| 92 | |
| 93 | 7. Change any class instance attributes/fields to be prefixed with ''''var'''' |
| 94 | change type and accessmodifier to cobra forms |
| 95 | {{{ |
| 96 | <Type> name = <init> ; |
| 97 | --> |
| 98 | var name as <Type> = <init> |
| 99 | }}} |
| 100 | |
| 101 | 8. Fixup class constructor definitions |
| 102 | For initializer/constructor change lines like |
| 103 | ''''public !ClassName(params,...) : base(baseParams,...)'''' |
| 104 | to |
| 105 | ''''cue init(params, ...) is public''' |
| 106 | '''base.init(baseParams,...)'''' |
| 107 | |
| 108 | within the params list correct type declaration syntax from C# to cobra |
| 109 | ''''[<accessModifier> ...] <Type> name,' |
| 110 | -> |
| 111 | ''''name as <Type> [is <accessModifier>, ...],'''' |
| 112 | |
| 113 | public is default accessmodifier so can leave that off |
| 114 | e.g. |
| 115 | {{{ |
| 116 | public ListViewFrame (string title, Point pos, Size size) : base(title, pos, size) |
| 117 | -> |
| 118 | cue init(title as String, pos as Point, size as Size ) is public |
| 119 | base.init (title, pos, size) |
| 120 | }}} |
| 121 | |
| 122 | 9. Remove any uses of ''''new'''' to construct a class instance, |
| 123 | instead just make a call to the class type passing any initializer args, i.e just remove 'new' |
| 124 | e.g. |
| 125 | {{{ |
| 126 | menuFile = new Menu() -> menuFile = Menu() |
| 127 | new Point(10, 100) -> Point(10, 100) |
| 128 | new Size(650,340) -> Size(650, 340) |
| 129 | }}} |
| 130 | |
| 131 | For classes that construct delegates (take method names) prefix the methodname with |
| 132 | '''ref''', |
| 133 | methodNames must start with a lowercase letter and are prefixed by ''''this.'''' or just ''''.'''' |
| 134 | so change the methodName accordingly |
| 135 | e.g. {{{new EventListener( OnAbout ) -> EventListener( ref .onAbout ) }}} |
| 136 | |
| 137 | |
| 138 | 10. Methods: |
| 139 | Prefix methods with '''def''' |
| 140 | Change methodnames to start with a lowercase letter, |
| 141 | Change param definitions to cobra form. |
| 142 | ''''[<accessModifier> ...] <Type> name,'''' -> ''''name as <Type> [is <accessModifier>, ...],'''' |
| 143 | Cobra methods by default return void and are public so if the C# code specifies ''''public void''' |
| 144 | you can just delete those words. |
| 145 | Also, if a method has no parameters then the empty trailing () can be left off. |
| 146 | |
| 147 | Note builtin types: |
| 148 | C# string -> String |
| 149 | C# object -> Object - Theres a twist though; wx.NET also defines an Object (wx.Object) so |
| 150 | that if you just declare something of Type Object theres a resolution ambiguity |
| 151 | message is 'Ambiguous reference "Object" found in namespaces "System" and "wx"' |
| 152 | so you have to either rely on the dynamic typing or resolve the ambiguity by |
| 153 | specifying the namespace to use |
| 154 | e.g. |
| 155 | {{{ |
| 156 | public void OnAbout( object sender, Event e ) |
| 157 | -> |
| 158 | def onAbout(sender as System.Object, e as Event) |
| 159 | # OR def onAbout(sender, e as Event) # untyped arg defaults to dynamic |
| 160 | |
| 161 | # no param method |
| 162 | public override bool OnInit() |
| 163 | -> |
| 164 | def onInit as bool is override |
| 165 | # or def onInit as bool is public, override # explicit |
| 166 | }}} |
| 167 | |
| 168 | 11. Calls to methods, properties and attributes/fields |
| 169 | Instance method names, properties and fields are called with a prefix of ''''this.'''' or just ''''.'''' |
| 170 | and they all must be named starting with a lowercase letter so these calls and settings |
| 171 | must be modified accordingly. |
| 172 | e.g. |
| 173 | {{{ |
| 174 | menuFile.AppendWL(... -> menuFile.appendWL( ... |
| 175 | CreateStatusBar() -> .createStatusBar # or this.createStatusBar |
| 176 | }}} |
| 177 | Similarly with properties and fields |
| 178 | {{{ |
| 179 | TextCtrl = TextCtrl(this, ... -> .textCtrl = TextCtrl(this, ... |
| 180 | MenuBar = menuBar -> .menuBar = menuBar |
| 181 | Log.SetActiveTarget( textCtrl ) -> Log.setActiveTarget(.textCtrl) # static class |
| 182 | }}} |
| 183 | If a method takes no args then any empty trailing () on a method call can/should be left off. |
| 184 | |
| 185 | 12. Property definition depending on the property use, prefix properties with |
| 186 | get - readable property only |
| 187 | set - setable property only |
| 188 | pro - getable and setable |
| 189 | |
| 190 | Change property names to start with a lowercase letter |
| 191 | |
| 192 | |
| 193 | 13. Local variables declared and assigned on first use can usually be changed to remove |
| 194 | the type definition (type inferred from the assignment) or can continue to be explicitly typed |
| 195 | (if that compiles). |
| 196 | {{{ |
| 197 | ListItem info = new ListItem() |
| 198 | -> |
| 199 | info = ListItem # or info as ListItem = ListItem() |
| 200 | }}} |
| 201 | |
| 202 | Heres a composite example |
| 203 | {{{ |
| 204 | // C# |
| 205 | ListItem itemCol = new ListItem(); |
| 206 | itemCol.Text = "Second Column"; |
| 207 | itemCol.Align = ListCtrl.wxLIST_FORMAT_CENTER; |
| 208 | itemCol.Width = 300; |
| 209 | InsertColumn( 1, itemCol ); |
| 210 | -> |
| 211 | # Cobra |
| 212 | itemCol = ListItem() |
| 213 | itemCol.text = "Second Column" |
| 214 | itemCol.align = ListCtrl.wxLIST_FORMAT_CENTER |
| 215 | itemCol.width = 300 |
| 216 | .insertColumn(1, itemCol) |
| 217 | }}} |
| 218 | |
| 219 | |
| 220 | 12. Fixup 'For' loops |
| 221 | {{{ |
| 222 | for ( <Type> name = start ; name < stop; ++name ) |
| 223 | -> |
| 224 | for name as Type in start : stop : 1 # explicit or equally use shortcuts: |
| 225 | for name in start : stop : 1 |
| 226 | for name in start : stop # if step is one (1) |
| 227 | for name in stop # if start is zero (0) and step is one (1) |
| 228 | # same as for name in 0 : stop : 1 |
| 229 | }}} |
| 230 | |
| 231 | e.g |
| 232 | {{{ |
| 233 | for ( int i = 0; i < 200; ++i ) -> for i in 0 : 200 |
| 234 | }}} |
| 235 | |
| 236 | 13. Casting |
| 237 | Casts of form '(Type)name' become 'name to Type' |
| 238 | e.g. |
| 239 | {{{ |
| 240 | mf.AppendWL( (int)Cmd.About,... |
| 241 | -> |
| 242 | mf.appendWL(Cmd.About to int,... |
| 243 | }}} |
| 244 | |
| 245 | Casts of form 'a as Type' can also become 'name to Type' or 'name to? Type' |
| 246 | e.g |
| 247 | {{{ |
| 248 | ListEvent le = e as ListEvent; |
| 249 | -> |
| 250 | le = e to ListEvent |
| 251 | }}} |
| 252 | |
| 253 | 14. String catenated with an expression (converted to string) |
| 254 | Put the expression (cobra converted) in the string inside [] |
| 255 | e.g. |
| 256 | {{{ |
| 257 | "Value 1st field of selected item: " + le.Text |
| 258 | -> |
| 259 | "Value 1st field of selected item: [le.text]" |
| 260 | }}} |
| 261 | |
| 262 | 15. Adding eventHandlers |
| 263 | Cobra uses the *listen* statement to register eventhandlers where C# uses an override on |
| 264 | the += operator. WxWidgets wraps method calls in an EventHandler class instance. |
| 265 | Otherwise normal cobra mapping for method names and reference to methods (vs method calls) |
| 266 | apply; Methodnames in Cobra must start with lower case and calls to this instance names |
| 267 | are prefixed with ''''this.'''' or (easier) ''''.'''' |
| 268 | When translating from a 'use'd library namespace, calls to |
| 269 | Capcased methodnames are referenced in cobra with the first '''char''' lowercased, |
| 270 | Upcased methodnames are referenced with the first '''word''' lowercased |
| 271 | so |
| 272 | {{{ |
| 273 | EVENT += EventListener( MethodName ) in C# becomes |
| 274 | listen .EVENT, EventListener( ref .methodName ) |
| 275 | |
| 276 | EVENT += EventListener( EH_METHOD_NAME ) in C# becomes |
| 277 | listen .EVENT, EventListener( ref .eh_METHOD_NAME ) |
| 278 | }}} |
| 279 | e.g. |
| 280 | {{{ |
| 281 | ColumnClick += EventListener( OnColumnClick ) |
| 282 | ItemSelect += EventListener( OnItemSelect ) |
| 283 | ColumnRightClick += EventListener( OnColumnRightClick ) |
| 284 | -> |
| 285 | listen .columnClick, EventListener(ref .onColumnClick) |
| 286 | listen .itemSelect, EventListener(ref .onItemSelect ) |
| 287 | listen .columnRightClick, EventListener(ref .onColumnRightClick) |
| 288 | }}} |
| 289 | |
| 290 | !WxWidets menu action handlers can be done in C# using call to EVT_MENU. |
| 291 | {{{EVT_MENU((int)MENU_ENUM_VALUE, new EventListener(MethodName)); }}} |
| 292 | the equivalent in cobra becomes |
| 293 | {{{.evt_MENU(MENU_ENUM_VALUE to int, new EventListener(ref .methodName))}}} |
| 294 | |
| 295 | e.g. |
| 296 | {{{ |
| 297 | EVT_MENU((int)Cmd.Quit, new EventListener(OnQuit)); |
| 298 | EVT_MENU((int)Cmd.Dialog, new EventListener(OnDialog)); |
| 299 | EVT_MENU((int)Cmd.About, new EventListener(OnAbout)); |
| 300 | }}} |
| 301 | -> |
| 302 | {{{ |
| 303 | .evt_MENU(Cmd.Quit to int, EventListener(ref .onQuit)) |
| 304 | .evt_MENU(Cmd.Dialog to int, EventListener(ref .onDialog)) |
| 305 | .evt_MENU(Cmd.About to int, EventListener(ref .onAbout)) |
| 306 | }}} |
| 307 | |
| 308 | 16. Main method |
| 309 | public void is default, static is an accessmodifier becomes ''''shared'''' in cobra, |
| 310 | C# attributes (!MetaInformation) are denoted with ''''has'''' |
| 311 | e.g. |
| 312 | {{{ |
| 313 | [STAThread] |
| 314 | static public void main() |
| 315 | -> |
| 316 | def main is shared has STAThread |
| 317 | }}} |
| 318 | |
| 319 | 17. Lowercased namespace names (as in wx.NET) used to disambiguate or otherwise explicitly |
| 320 | specify the namespace on types (inherits ..., as ....) as opposed to methods or constants |
| 321 | can (may/will) generate compile errors of the form |
| 322 | ''''error: Cannot find type for "wx.TYPE".''''[[br]] |
| 323 | e.g. error: Cannot find type for "wx.Frame". |
| 324 | If such occurs the only recourse is to remove the explicit typing and rely on default handling |
| 325 | e.g. |
| 326 | {{{ |
| 327 | use wx from "wx.NET" |
| 328 | namespace SampleMinimal |
| 329 | class MyFrame inherits wx.Frame |
| 330 | # file.cobra(3): error: Cannot find type for "wx.Frame". |
| 331 | #Change to |
| 332 | use wx from "wx.NET" |
| 333 | namespace SampleMinimal |
| 334 | class MyFrame inherits Frame |
| 335 | }}} |
| 336 | |
| 337 | {{{ def onAbout(sender as System.Object, e as wx.Event ) }}} |
| 338 | # Change to |
| 339 | {{{ def onAbout(sender as System.Object, e as Event ) }}} |
| 340 | |
| 341 | {{{ |
| 342 | fileMenu as wx.Menu = wx.Menu() |
| 343 | # Change to |
| 344 | fileMenu = Menu() |
| 345 | }}} |
| 346 | Eventually it would be preferable if cobra became a little more flexible in these cases.. |
| 347 | |
| 348 | |
| 349 | Other weirdnesses |
| 350 | As of this doc date (Oct 2009) the wx.NET version and cobra seem to not be able to find |
| 351 | some properties, specifically[[br]] |
| 352 | Frame.Icon, .icon property -> no workaround [[br]] |
| 353 | Frame.!StatusBar, .statusBar text property -> use method .setStatusBar(text) instead[[br]] |