Amiga-Development

Please login or register.

Login with username, password and session length
Advanced search  

News:

Created for developers of all Amiga camps

Author Topic: A few GUI questions  (Read 1896 times)

0 Members and 1 Guest are viewing this topic.

Zendarion

  • Newbie
  • *
  • Posts: 7
    • View Profile
A few GUI questions
« on: February 16, 2017, 10:55:53 AM »

Have a few questions

1. When I use addTick(), how can I get the text that describe the tick on the right side instead of left? Just to choose sides?

2. When creating a GUI, to have a fixed size at start, like 640*480, Fullscreen, 1920*1080

3 I can only resize the window horizontal and not vertical. I have seen some example programs you have made and some can do both. How do I do that?

4. I used a button to show a picture but doesnt seem right to use a button and GHOST it for a picture. And can a picture stretch out is the application is resized? Didnt send the picture I use.

5. Is there a way to get a textbox with tiny up and down arrows to increase a numerical value?

6. Is there something like try catch in PortableE?

Code below and the button is just a copy and paste from something else I did and has no function.
--------------------

MODULE 'std/cGui', 'std/cApp', 'std/cPath'
PROC main()
DEF win:PTR TO cGuiWindow, button:PTR TO cGuiButton
DEF item:PTR TO cGuiItem, quit:BOOL
DEF outPut:PTR TO cGuiText, passLength:PTR TO cGuiNumberString
DEF uclTick:PTR TO cGuiTick, lclTick:PTR TO cGuiTick
DEF temp:ARRAY OF CHAR

CreateApp().build()

win := CreateGuiWindow('PassGen v1.0')

win.beginGroupVertical('')
win.addButton('').initPic('pass.jpg').setGhosted(TRUE)


win.beginGroupHorizontal('Select Character Set')
        win.beginGroupVertical()
                uclTick := win.addTick('Uppercase Letters')
                lclTick := win.addTick('Lowercase Letters')
        win.endGroup()

        win.beginGroupVertical()
                uclTick := win.addTick('Uppercase Letters')
                lclTick := win.addTick('Lowercase Letters')
        win.endGroup()
win.endGroup()

        win.beginGroupVertical()
                outPut := win.addText('Your new password').setState('')
                passLength := win.addNumberString('Enter Password Length', 0, 10)
                 button := win.addButton('OK').initPic('tbimages:/ok_g').setGhosted(FALSE)
        win.endGroup()
win.endGroup()
win.build()

quit:=FALSE
REPEAT
        item:=WaitForChangedGuiItem()
        IF item = NIL
                IF win.getCloseRequest() THEN quit := TRUE

        ELSE IF item = button
                IF StrCmp('Hans', temp)
                        outPut.setState('Hej Hans')
                ELSE
                        outPut.setState('Du är inte Hans, arghhh!!!')
                ENDIF
        ENDIF
UNTIL quit
win.close()

ENDPROC
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #1 on: February 16, 2017, 04:31:21 PM »

1. When I use addTick(), how can I get the text that describe the tick on the right side instead of left? Just to choose sides?
To keep things simple for me, I don't directly provided that option... However, you can kludge it by doing something like this:

Code: [Select]
win.beginGroupHorizontal()
win.addTick('')
win.addLabel('My tick box')
win.endGroup()

This additional coding complexity can be hidden behind a procedure quite easily:
Code: [Select]
PROC addTickLabel(win:PTR TO cGuiWindow, label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiTick
win.beginGroupHorizontal()
item := win.addTick('')
win.addLabel(label)
win.endGroup()
ENDPROC
(Note: This compiles, but I have not actually tested it in a program, so let me know if you have any problems.)

You can use it like this:
Code: [Select]
addTickLabel(win, 'My tick box')

Quote
2. When creating a GUI, to have a fixed size at start, like 640*480, Fullscreen, 1920*1080
Assuming that your GUI is normally resizable, then replace this:
Code: [Select]
win.build()
With this:
Code: [Select]
win.build(/*keepWindowClosed*/ TRUE)
win.changeSize(640, 480)
win.open()

If you want it to be Fullscreen, then you need to make the window the same size as the screen.  The simplest & most portable way to do this currently needs the 'std/cGfxSimple' module, then you can use this code:
Code: [Select]
win.build(/*keepWindowClosed*/ TRUE)
win.changeSize(InfoScreenWidth(), InfoScreenHeight())
win.open()
Please note that your program also needs the following line of code at the start of your main() procedure:
Code: [Select]
IsDesktopApp() ->you only need to do this once
The down side of this is that the cGfx module is quite big, so your program will have a bigger executable & take longer to compile, which is perhaps a bit overkill to use just a couple of simple procedures.  So a lighter-weight solution, which will only ever work on Amiga-like systems, is something like this:
Code: [Select]
MODULE 'target/intuition'

PROC infoScreenWidth() RETURNS width
DEF scr:PTR TO screen
scr := LockPubScreen(NILA)
width := scr.width
UnlockPubScreen(NILA, scr)
ENDPROC

PROC infoScreenHeight() RETURNS height
DEF scr:PTR TO screen
scr := LockPubScreen(NILA)
height := scr.height
UnlockPubScreen(NILA, scr)
ENDPROC

This creates two procedures, that start with a lowercase letter, but otherwise will hopefully give the same result as in my earlier example.  (In theory there might be cases where it gives the wrong screen size, but for most practical situations (where all the Amiga's screens are the same size) it should work.)

A separate possible problem is that you might find CurrentTime() (from the 'std/pTime' module) no-longer seems to work (compilation error).  If that happens, it's because it's being over-ridden by the CurrentTime() procedure in the 'target/Intuition' module.  The only solution to this would be to put the infoScreenWidth()/infoScreenHeight() code into it's own module (which doesn't use 'std/pTime'), then you can refer to that module (instead of 'target/intuition'), so there would be no possibility of any clash.


Quote
3 I can only resize the window horizontal and not vertical. I have seen some example programs you have made and some can do both. How do I do that?
That's because none of the GUI items in your window (that take-up the full width) are vertically resizable themselves.

TextBoxes, StringBoxes & Lists are definitely vertically resizable (I can't remember any more off the top of my head).  The other kinds of GUI items have a fixed height due to only containing one line of text.  Horizontal groups are only vertically resizable if ALL of the items they contain are vertically resizable.  Vertical groups are vertically resizable if ANY of their items are vertically resizable.


Quote
4. I used a button to show a picture but doesnt seem right to use a button and GHOST it for a picture. And can a picture stretch out is the application is resized? Didnt send the picture I use.
The GUI doesn't (yet!) directly support this, however I used it's advanced "cGuiNativeHost" feature to implement this for eGame (and so may eventually get added to the GUI system itself).  I will provide the code in a separate post later...

Quote
5. Is there a way to get a textbox with tiny up and down arrows to increase a numerical value?
Not really.  Maybe a Slider would suit your purpose?

(In theory the NumberString item COULD support up/down arrows, but it's not implemented at the moment.   If I saw/found some MUI code for how to do this, then I might add it to NumberString, or I could write some user code to add it using cGuiNativeHost.)
« Last Edit: March 01, 2017, 11:38:50 PM by ChrisH »
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #2 on: February 16, 2017, 05:56:17 PM »

Quote
6. Is there something like try catch in PortableE?
Yes, but it's usage is a bit different to how you may be used to seeing in Java or C++.  It's not quite as flexible, but I find it FAR less verbose, and it works very well for it's intended usage.

There is only ONE "try catch" per procedure, so the expectation is that you will mainly use this just to clean-up anything & everything that might happen in your procedure, so that you don't leak memory or leave files/windows/screens open (since AmigaOS won't automatically close them for you, although in general PortablE does *try* to do so).

Code: [Select]
PROC main()
Print('1\n')
example()
Print('4\n')
FINALLY
PrintException()
ENDPROC

PROC example()
Print('2\n')
Throw("bug", 'A fake bug was detected')
Print('3\n')
FINALLY
Print('3.5\n')
ENDPROC

This should output:
Quote
1
2
3.5
EXCEPTION: " bug"; A fake bug was detected.

This also demonstrates that at the end of a FINALLY section, the exception is automatically rethrown (unlike happens in AmigaE).  I found that this was essential to making big programs work reliably, as otherwise you can easily not see an exception (i.e. an error) because you'd have forgotten to rethrow it in one of the nested procedure calls.

Note that the FINALLY section of code is executed even if there is no exception!  So if you commented-out the Throw() line, then you would get the following output instead:
Quote
1
2
3
3.5
4

So how do you make some code only execute when there is an exception?  Like this:
Code: [Select]
PROC example()
Print('2\n')
Throw("bug", 'A fake bug was detected')
Print('3\n')
FINALLY
IF exception
Print('3.5\n')
ENDIF
ENDPROC

This will behave the same in the original example, but if you comment-out the Throw() line, then you will never see '3.5' get printed.

Note that the special "exception" variable contains the value "bug" in this example, so you can check for specific exceptions like so:
Code: [Select]
PROC example()
Print('2\n')
Throw("bug", 'A fake bug was detected')
Print('3\n')
FINALLY
IF exception = "bug"
Print('3.5\n')
ENDIF
ENDPROC

And how do you prevent an exception being rethrown?  By setting "exception" to 0, but take GREAT care before deciding to do this (I've only done it a handful of times in tens of thousands of lines of code) :
Code: [Select]
PROC example()
Print('2\n')
Throw("bug", 'A fake bug was detected')
Print('3\n')
FINALLY
IF exception = "bug"
Print('3.5\n')
exception := 0
ENDIF
ENDPROC

So you would get the following output:
Quote
1
2
3.5
4

By the way, while the "exception" variable contains the first parameter given to Throw(), the "exceptionInfo" variable contains the second parameter (which is a string).  The idea here is that "exceptionInfo" can contain helpful human-readable text, which can provide more information on explaining why the exception was thrown.

Now that you understand how it works, here is a simple example of how you would typically use it:
Code: [Select]
PROC main()
hello('Chris')
FINALLY
PrintException()
ENDPROC

PROC hello(name:ARRAY OF CHAR)
DEF string:STRING
string := StrJoin('Hello ', name, '.\n')
Print(string)
FINALLY
END string
ENDPROC

The hello() procedure allocates a new e-string when it calls StrJoin(), so it needs to ensure that memory is automatically disposed of when the procedure finishes.  It does this by putting "END string" in the FINALLY section.  Thus the string is automatically destroyed when the procedure finishes, but the string is ALSO destroyed if an exception is thrown by some code somewhere in it (except this is such a simple example that it would never happen).

What happens when an exception is thrown BEFORE the e-string is allocated?  In that case "END string" will safely do nothing.  So you can happily END more than one variable in a FINALLY section, without a problem.  Similarly, if you called CreateGuiWindow(), then you really ought to call DestroyGuiWindow() in the FINALLY section (although PortablE will try to do this for you when your program finishes).


PortablE will automatically throw a "MEM" exception if allocating memory fails due to running out of memory.  This can happen inside many built-in & standard procedures/methods, as well as your own if you use NEW or similar to allocate memory.

PortablE's standard procedures (and even a few built-in ones) will throw an "EPU" exception (Error from Procedure Use), if a nonsensical parameter is supplied to a procedure call (such as -1 for the number of times it should do something, or NILA for a string that is required).  Similarly a standard method will throw an "EMU" exception (Error from Method Use).

And in hopefully rare instances, standard procedures/methods can also throw a "BUG" exception, if an internal assertion/check fails.

PortablE's standard modules occasionally use other exceptions too, and these are documented (such as cPath throwing "FULL" if the disk is full).

In PortablE the "exception" variable has the type QUAD, which represents the type needed to hold the value of 4 characters in a single value (typically 32-bits).  So you can have "abcd" but NOT "abcde".  You can also use plain numbers for "exception".

I refer you to the original AmigaE documentation for additional information on the choice of exception values:
http://cshandley.co.uk/amigae/ch_13d.html

But take special note that:
Quote
The general tendency is:
* all uppercase for general system exceptions,
* mixed case for exceptions used by >1 app, but not general enough.
* all lowercase for exceptions raised within your own multi-module application

- all others (including all negative IDs) remain reserved.

In other words, do not use exception values which contain more than one upper-case letter.  And NEVER EVER use negative exception values.


Please also read the next part, entitled The philosophy of exceptions in PortablE.
« Last Edit: February 17, 2017, 11:32:11 AM by ChrisH »
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
The philosophy of exceptions in PortablE
« Reply #3 on: February 16, 2017, 06:35:12 PM »

The philosophy of exceptions in PortablE
You should now understand how exceptions behave, and hopefully even have some idea how you are supposed to use them.  While you are free to use the exceptions system in any way you feel like, I do have some advice on how to make best use of exceptions.  By following this advice, not only will you avoid fighting the exception system (by using it for things it was not intended for), but you will hopefully also write better programs (more reliable & simpler to understand).

In general, you should only use exceptions for handling rare situations, where either your program isn't working as intended, or it runs into a situation that it cannot handle.  e.g. Bugs in your code (say a variable contains a value that should not be possible).  e.g. Events outside of your control (such as running out of memory, or failing to open a file that your program absolutely NEEDS to carry on).

In those kinds of situations, your only real solution is for your program to quit as cleanly as possible.  And since AmigaOS won't clean-up after you (as it lacks resource tracking), you need to do it yourself.  So you let the exception propagate all the way down to the main() procedure, and then report the exception to the user before your program quits.  That is why the example main() procedure has PrintException() in the FINALLY section.  Pretty much all my own programs do this.


If your procedure wishes to indicate that a not-uncommon situation has occurred, then you should just return a special return value.  For instance, if you have a procedure that requests the user to choose a file, returning the path of that file as a string, then if the user cancels the requester, your procedure could return NILA (or NILS as appropriate)... or perhaps an empty string.  Then when you call that procedure, you need to check if it returns NILA (or an empty string).  All of the procedures & methods provided by PortablE's Standard Functionality work like this, so use them as examples of "best practice".


There are of course situations where your program might be able to recover from an uncommon (but not completely unexpected) situation.  It is then up to you to choose whether you throw an exception or return a special value.  Both options will have their pros & cons, and you will have to weigh them before making a decision.

My general advice would be that you should not throw an exception if you expect it to be immediately caught (and handled) by the calling procedure.  Special return values would make more sense in those situations.  Rather, only throw an exception if it needs to be handled by some (probably distant) grandparent procedure, where returning special values all the way back to it would be difficult, messy or even impossible.

Such situations only tend to occur in big programs.  For example, maybe the user tries to load a huge file, and it causes your program to run out of memory (or fails to load the file in the first place).  Rather than having your program completely quit, with a cryptic error message, you could clean-up whatever the user did already have loaded, show a friendly error window saying it failed to load the file for some reason (maybe showing "exceptionInfo" as a hint to why it happened), and then allow them to start again & try opening another file (without having to restart your program).

Another example is that you are writing a file to disk.  PortablE will throw a "FULL" exception if the disk is full, such that it cannot finish writing to the file.  Small programs can reasonably just quit with an error message, but larger programs may wish to handle such situations, perhaps deleting the incomplete file & then take some other action (maybe ask the user for an alternative volume to write the file to?).
« Last Edit: February 16, 2017, 07:15:10 PM by ChrisH »
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #4 on: February 16, 2017, 08:01:41 PM »

Quote
4. I used a button to show a picture but doesnt seem right to use a button and GHOST it for a picture. And can a picture stretch out is the application is resized? Didnt send the picture I use.
PortablE's GUI system doesn't directly support this (yet!), however I used it's advanced "cGuiNativeHost" feature to implement this for eGame (and so it may eventually get added to the GUI system itself).  While I'm not completely happy with this code, it seems to work pretty well in practice, so here it is:

Code: [Select]
OPT POINTER, PREPROCESS
MODULE 'std/cGui', 'std/cPath_shared'
MODULE 'CSH/pAmigaGraphics', 'CSH/pAmigaDatatypes', 'CSH/pAmigaIcon', 'CSH/pAmigaMui'

PROC main()
DEF win:PTR TO cGuiWindow, guiPic:PTR TO cGuiNativePicture, guiToggle:PTR TO cGuiButton
DEF quit:BOOL, item:PTR TO cGuiItem

CreateApp('example').build()

->create the GUI
win := CreateGuiWindow('NativePicture demo')
win.beginGroupVertical()
guiPic := addNativePicture(win, 'tbimages:/ok')
guiToggle := win.addButton('Toggle pic')
win.endGroup()
win.build()

->handle GUI events
quit := FALSE
REPEAT
item := WaitForChangedGuiItem()
SELECT item
CASE NIL
IF win.getCloseRequest() THEN quit := TRUE

CASE guiToggle
IF StrCmp( 'tbimages:/ok', guiPic.getState()) = FALSE
guiPic.setState('tbimages:/ok')
ELSE
guiPic.setState('tbimages:/cancel')
ENDIF
ENDSELECT
UNTIL quit

win.close()
FINALLY
PrintException()
ENDPROC

/*****************************/

->NOTE: You don't need to supply the path of a picture (give NILA instead), but in that case you MUST give values for "width" & "height".
->NOTE: This can load Amiga icons, which are detected by their '.info' extension.
PROC addNativePicture(win:PTR TO cGuiWindow, path:ARRAY OF CHAR, width=0, height=0) RETURNS item:PTR TO cGuiNativePicture
DEF newItem:OWNS PTR TO cGuiNativePicture
IF win.infoCurrentBuildGroup() = NIL THEN Throw("EPU", 'addNativePicture(); must be done inside a group')
IF (width=0) <> (height=0) THEN Throw("EPU", 'addNativePicture(); width or height was 0 (you must supply both)')
IF (width=0) AND (path=NILA) THEN Throw("EPU", 'addNativePicture(); path=NILA and width/height=0 (you must supply at least one)')

NEW newItem.new(win, width, height)
item := newItem
win.addNative(PASS newItem)
IF path
IF item.setState(path) = FALSE
IF width=0 THEN Throw("ERR", 'addNativePicture(); failed to load picture, and width/height=0')
ENDIF
ENDIF
ENDPROC


CLASS cGuiNativePicture OF cGuiNativeHost
win:PTR TO cGuiWindow
bitmap:PTR TO bitmap
path:OWNS STRING
width
height
ENDCLASS

PRIVATE
PROC new(win:PTR TO cGuiWindow, width, height) OF cGuiNativePicture
self.win := win
self.bitmap := NIL
self.path := NILS
self.width := width
self.height := height

self.initShared() ->this is required
ENDPROC
PUBLIC

PROC end() OF cGuiNativePicture
DEF object:PTIO

IF self.bitmap
IF object := self.infoObject()
set(object, MUIA_Bitmap_Bitmap, NIL)
ENDIF
freeBitMap(self.bitmap)
ENDIF
END self.path

SUPER self.end()
ENDPROC

PROC build() OF cGuiNativePicture RETURNS muiItems:OWNS LIST, object:PTIO, label:PTIO
IF self.height = 0 THEN Throw("EMU", 'cGuiNativePicture.build(); width/height=0 and no picture was loaded yet')

muiItems := NEW [Child, object := BitmapObject,
GroupFrame, ->MUIA_Background,MUII_WindowBack,
MUIA_Bitmap_Width, self.width,
MUIA_Bitmap_Height,self.height,
MUIA_FixWidth, self.width,
MUIA_FixHeight,self.height,
IF self.bitmap THEN MUIA_Bitmap_Bitmap ELSE TAG_IGNORE,self.bitmap,
MUIA_Bitmap_UseFriend, MUI_TRUE,
->MUIA_Bitmap_SourceColors,palette,
End]
label := NIL
ENDPROC

->PROC setupNotify(watchObject:PTIO, actionHook:PTR TO hook, param:ILIST) OF cGuiNativePicture

PROC infoIsFixedWidth() OF cGuiNativePicture RETURNS isFixedWidth :BOOL IS TRUE

PROC infoIsFixedHeight() OF cGuiNativePicture RETURNS isFixedHeight:BOOL IS TRUE

PROC infoUseInCycleChain() OF cGuiNativePicture RETURNS useInCycleChain:BOOL IS FALSE

PROC getState() OF cGuiNativePicture RETURNS path:ARRAY OF CHAR IS self.path

PROC setState(path:ARRAY OF CHAR) OF cGuiNativePicture RETURNS success:BOOL
DEF hostPath:OWNS STRING, scr:PTR TO screen, pubScr:PTR TO screen, scrDepth, datatypeObject:PTIO, bitmapheader:PTR TO bitmapheader
DEF origBitmap:PTR TO bitmap, origWidth, origHeight, maskBitmap:PTR TO bitmap
DEF fixedBitmap:PTR TO bitmap, fixedWidth, fixedHeight, fixedRP:rastport
DEF scale:BOOL, smooth:BOOL, scaledWidth, scaledHeight, ratioWidth:FLOAT, ratioHeight:FLOAT, ratioInteger, x, y
DEF object:PTIO

success := FALSE

->get screen
scr := self.win.queryExtra("SCRN")::screen
IF scr = NIL
pubScr := LockPubScreen(NILA)
scr := pubScr
ENDIF

scrDepth := getBitMapDepth(scr.rastport.bitmap)

->attempt to load picture/icon
hostPath := ExportPath(path)
IF StrCmpNoCase(hostPath, '.info', ALL, EstrLen(hostPath)-STRLEN) = FALSE
->(not an icon) so load picture
datatypeObject, origBitmap, bitmapheader := loadPicture(hostPath, scr)
IF datatypeObject = NIL THEN RETURN

origWidth := bitmapheader.width
origHeight := bitmapheader.height
ELSE
->load icon
SetStr(hostPath, EstrLen(hostPath) - StrLen('.info')) ->strip trailing .info
origBitmap, origWidth, maskBitmap := loadIcon(hostPath, scr, /*allowDefaultIcon*/ TRUE)
IF origBitmap = NIL THEN RETURN

origHeight := GetBitMapAttr(origBitmap, BMA_HEIGHT)
IF (origWidth <= 2) AND (origHeight <= 2) THEN RETURN ->ignore dummy icons, as might be present for NewIcons, etc
ENDIF
END hostPath

->use size of picture as our size
IF self.height = 0
self.width := origWidth
self.height := origHeight
ENDIF

->copy image, scaling it if too large
fixedWidth := self.width
fixedHeight := self.height
fixedBitmap := allocBitMap(fixedWidth, fixedHeight, scrDepth /*was: getBitMapDepth(origBitmap)*/, BMF_DISPLAYABLE /*#*/OR BMF_CLEAR/*#*/, scr.rastport.bitmap /*was: origBitmap*/)

InitRastPort(fixedRP)
fixedRP.bitmap := fixedBitmap
SetRast(fixedRP, 0)

IF (origWidth <= fixedWidth) AND (origHeight <= fixedHeight)
->check if it can be enlarged by an integer amount
ratioInteger := Min(fixedWidth/origWidth, fixedHeight/origHeight)
IF ratioInteger > 2 THEN ratioInteger := 2
IF scale := ratioInteger >= 2
scaledWidth := origWidth * ratioInteger
scaledHeight := origHeight * ratioInteger
smooth := FALSE
ENDIF
/*
ratioWidth := 1.0 * fixedWidth / origWidth
ratioHeight := 1.0 * fixedHeight / origHeight
/*
IF ratioWidth < ratioHeight
scaledWidth := Min(origWidth * ratioHeight !!VALUE, fixedWidth )
scaledHeight := fixedHeight
ELSE
scaledWidth := fixedWidth
scaledHeight := Min(origHeight * ratioWidth !!VALUE, fixedHeight)
ENDIF
*/
smooth := TRUE
scale := TRUE
*/
ELSE
->preserve aspect ratio
ratioWidth := 1.0 * origWidth / fixedWidth
ratioHeight := 1.0 * origHeight / fixedHeight
IF ratioWidth > ratioHeight
scaledWidth := fixedWidth
scaledHeight := Min(origHeight / ratioWidth !!VALUE, fixedHeight)
ELSE
scaledWidth := Min(origWidth / ratioHeight !!VALUE, fixedWidth )
scaledHeight := fixedHeight
ENDIF
smooth := TRUE
scale := TRUE
ENDIF

IF scale = FALSE
->copy bitmap, keeping it centered
x := (fixedWidth - origWidth ) / 2
y := (fixedHeight - origHeight) / 2
BltBitMap(origBitmap,0,0, fixedBitmap,x,y, origWidth,origHeight, $c0,$ff,NILA)
ELSE
->scale bitmap, keeping it centered
x := (fixedWidth - scaledWidth ) / 2
y := (fixedHeight - scaledHeight) / 2
bitMapScale(origBitmap,0,0,origWidth,origHeight, fixedBitmap,x,y,scaledWidth,scaledHeight, scrDepth, smooth)
ENDIF

->use & store new picture
IF object := self.infoObject()
set(object, MUIA_Bitmap_Bitmap, fixedBitmap)

#ifdef pe_TargetOS_AROS
->work-around Zune not refreshing the shown bitmap
set(object, MUIA_ShowMe, MUI_FALSE)
set(object, MUIA_ShowMe, MUI_TRUE)
#endif
ENDIF

IF self.bitmap THEN freeBitMap(self.bitmap)
self.bitmap := fixedBitmap ; fixedBitmap := NIL

END self.path
self.path := StrJoin(path)

success := TRUE
FINALLY
IF datatypeObject
DisposeDTObject(datatypeObject)

ELSE IF origBitmap
freeBitMap( origBitmap)
ENDIF
IF fixedBitmap THEN freeBitMap(fixedBitmap)
IF maskBitmap THEN freeMaskBitMap( maskBitmap)
IF pubScr THEN UnlockPubScreen(NILA, pubScr)

END hostPath
ENDPROC

You use the addNativePicture() procedure to EITHER (a) add a picture, or (b) an fixed-size area, to the GUI.  If you add a picture, then that normally defines the size of the area, but you can specify a different size of you wish (using width & height).  A slightly neat feature is that you can change the picture while the GUI is open :)  .  Another feature is that you can load Amiga icons.

NOTE: For the code above to be copied & pasted correctly, I had to remove multiple spaces used for padding, but it won't look so nice.  I have therefore attached the original code below.
« Last Edit: February 18, 2017, 02:35:01 PM by ChrisH »
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #5 on: February 17, 2017, 06:46:51 PM »

Please note that I have greatly improved addNativePicture() :  It can now get it's size from the initial picture, so you don't have to give a size.  And it automatically detects Amiga icons by the fact they end with '.info' .
Logged

Zendarion

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: A few GUI questions
« Reply #6 on: February 18, 2017, 02:13:28 PM »

Thanks for the reply. A lot to explore and alot to learn.

I copied the code from question 4, about using pictures and it processes the code without problem until the .cpp file is about to be compiled. It says test.cpp:16773: error: stray '\240' in program

The 16773 number is just one of many. I have the latest SDK and PortablE and have compiled other stuff so it works. I have installed PortablE manually though just because the installer doesnt install, it says:

Copying executables...
EXCEPTION: "EPU"; EString; SetStr(); newLen<0.

Nothing else happens here, it just stops.

Have installed using the installer before on my Sam460ex with success. Now I have an awesome X5000 and a RadeonHD 7xxx series. Thats the only difference

Any ideas? Anyway, thanks for the respone and I am sure I will have more questions in the future.
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #7 on: February 18, 2017, 02:46:45 PM »

I copied the code from question 4, about using pictures and it processes the code without problem until the .cpp file is about to be compiled. It says test.cpp:16773: error: stray '\240' in program
Aarrgh, this happens for me too.  It seems that when the forum software sees multiple spaces, it converts some of them into non-ASCII characters (with a decimal value of 160, a hex value of A0, and an octal value of 240).  PortablE quite happily ignores these wierd characters, and passes them through into the C++ code, but GCC doesn't like them, hence the wierd error message.

I have occasionally seen this problem at random.  I should probably make PortablE convert such wierd characters into normal white space.

Anyway, I have fixed the post, so you should now be able to copy & paste the code without a problem.  Or download it as an attachment.

Quote
I have installed PortablE manually though just because the installer doesnt install, it says:

Copying executables...
EXCEPTION: "EPU"; EString; SetStr(); newLen<0.
Thanks for (eventually...) reporting this bug.  From looking at my code, it is most likely caused by the path for storing the executables (given by the user) not having any (sub)folders.  e.g. "C:" (which is unfortunately the default).  The work-around would be to give it a path that does have a folder in it, e.g. "Sys:C" .  I will fix this bug for the next release...
« Last Edit: February 18, 2017, 02:57:43 PM by ChrisH »
Logged

Zendarion

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: A few GUI questions
« Reply #8 on: February 19, 2017, 02:37:05 AM »

One more question in this thread. Probably a simple one and it is how I use UpperStr(). I have read the manual but cant get it to work
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #9 on: February 19, 2017, 11:03:17 AM »

One more question in this thread. Probably a simple one and it is how I use UpperStr(). I have read the manual but cant get it to work
Here is an example program:
Code: [Select]
PROC main()
DEF str:STRING

str := NEW 'Example String'
Print('before = "\s"\n', str)

UpperStr(str)
Print('after = "\s"\n', str)
FINALLY
PrintException()

END str
ENDPROC

And what it outputs:
Quote
before = "Example String"
after = "EXAMPLE STRING"

i.e. It modifies the string that you give it.  (The string pointer it returns is exactly the same pointer as the one you gave it, so using the return value is entirely optional.)

You must ONLY let it modify memory that you allocated yourself (which is typically a STRING).  i.e. Do NOT just give in an 'immediate string', because this is supposed to be constant/read-only (and will actually be prevented by some OSes, by crashing your program).
Logged

Zendarion

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: A few GUI questions
« Reply #10 on: February 19, 2017, 06:25:56 PM »

Works perfect. Guess I had one question still, came from a C# environment so somethings are new in a way.

This time it is about using a Rnd()

Was no problem with a shell program but when using it in a GUI I cant get an output in a win.addText.

Is it something about casting?
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #11 on: February 19, 2017, 06:39:09 PM »

This time it is about using a Rnd()
Was no problem with a shell program but when using it in a GUI I cant get an output in a win.addText.
addText() expects to be given a string, so first you will need to convert your random number to a string.

You cannot just cast the number to a string, because you would be trying to tell PortablE to treat the number AS A MEMORY POINTER to a string!  So you'd end-up with a pointer to a random memory location, which almost certainly would NOT contain a string.

Instead you need to tell PortablE to write the number into an existing e-string, in a similar fashion to how you can print numbers to the Shell.  Hopefully the following example will provide enough of a hint:
Code: [Select]
PROC main()
DEF num, str[100]:STRING

num := Rnd(1000)
StringF(str, '\d', num) ->convert number to a string

Print('"\s"\n', str)
FINALLY
PrintException()
ENDPROC
Logged

ChrisH

  • Moderator
  • Newbie
  • *****
  • Posts: 32
    • View Profile
Re: A few GUI questions
« Reply #12 on: March 01, 2017, 10:53:10 PM »

The code I originally provided for infoScreenWidth()/infoScreenHeight() did not work!  So I have now replaced it with some code that does definitely work...
« Last Edit: March 03, 2017, 10:21:26 AM by ChrisH »
Logged