PureBasic Docs- Ideas/Help needed for a "We start" chapter!?

Everything else that doesn't fall into one of the other PB categories.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

spikey wrote: I've revised this example as I discovered that the window layout wasn't very good on Ubuntu Linux.
Thanks, spikey. I've updated the example in the manual.


Any further contributions (see missing chapters) are welcome, if anyone is able to and willing to share... :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Multiple Instances of a Single Window

Post by spikey »

If you’ve looked at the help articles for the OpenWindow command or for any of the gadget creation commands (for example ButtonGadget) or if you have experimented with the Visual Designer tool, you may have noticed references to a special constant called #PB_Any. In this article we’re going to look into this a little further to find out why its so important.

So far all of our examples have used a group of constants, an enumeration, to identify a single window and each gadget on that window. This is fine in the simple programs we’ve demonstrated so far but presents a problem in more complex programs – Only one of each of these windows can exist at any one time.

So what happens if a program needs to provide more than one copy of a window? Maybe to have several files open at once or possibly to provide several different views of the same file.

This is where the special #PB_Any constant comes in. When this constant is used as the argument to the functions that support it, a unique reference number is automatically generated and returned as a result of the function.

Providing we keep track of all these references we can use this to our advantage. Organising this is a little more complex than the examples we’ve seen so far – but the increased flexibility that it can provide makes this well worth the effort.

This example program provides a window upon which a regular polygon is drawn in blue on a circumscribing grey circle. A combo box is provided to allow a selection of polygons to be drawn. A menu is provided to allow the creation of new windows or the closing of the current window.

There are several things to notice about this program:-

In the Enumerations section, note that there are only enumerations for the menu items. These will be shared on all the windows – although each window will have its own menu bar.

In the Structures section, note that the POLYGONWINDOW structure contains four integer values and so provides a place to store references for a menu bar, a label, a combo box and an image plot.

In the Variables section note that in addition to the usual variables to receive event details, a map called ActiveWindows is created using the POLYGONWINDOW Structure previously defined.

Look at the CreatePolygonWindow procedure.
When we create the window we capture the result of the OpenWindow function in a variable called ThisWindow. We then convert this to a string value and use this as the key for a new map entry.

When we then create the menu, label, combo and image gadgets on the new window the references returned by these functions are stored in the map too.

Look at the ResizePolygonWindow procedure.
Notice how the value of EvtWindow is passed in from the event loop into this procedure. This value is then used to retrieve child control references from the map and these references are then used to resize the gadgets.

Look at the DestroyPolygonWindow procedure.
Here the child control references are removed from the map when a window is closed.
If the map size reaches zero – there are no more open windows and DestroyPolygonWindow sets an event flag to tell the program to end.

Start the program up.
· Use the New Window menu item to open up two or three new polygon windows.
· Use the combo box in each one to select a different shape – notice that each window works independently of all the others.
· Resize some of the windows – notice that they can all be resized independently of each other and that the polygon resizes with the window too.

Finally, note that a map isn’t the only way to achieve this effect, a LinkedList or an Array could be used to do the job too, if you prefer, although the code to implement these alternatives would need to be slightly different to that presented here because of the differences in the way those collections work.

Code: Select all

; Compiler Directives
EnableExplicit

; Constants
CompilerIf Defined(Blue, #PB_Constant) = #False
  #Blue = 16711680
  #Gray = 8421504
  #White = 16777215
CompilerEndIf

;- Enumerations
; The menu commands will be the same on all the windows.
Enumeration
  #mnuNew
  #mnuClose
EndEnumeration

;- Structures
; This structure will hold references to the unique elements of a window.
Structure POLYGONWINDOW
  Menu.i
  LabelSides.i
  ComboSides.i
  ImagePlot.i
EndStructure

;- Variables

; This map uses the previously defined structure to hold references for all the open windows.
NewMap ActiveWindows.POLYGONWINDOW()

; Event variables.
Define.i Evt, EvtWindow, EvtGadget, EvtType, EvtMenu, EvtQuit
Define.s EvtWindowKey

; Implementation.
Procedure.i CreatePolygonWindow()
  
  ; Creates a new window and gadgets, adding it and its child gadgets to the tracking map.
  
  Shared ActiveWindows()
  Protected.i ThisWindow
  Protected.s ThisKey
  
  ThisWindow = OpenWindow(#PB_Any, 50, 50, 300, 300, "Polygon", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)  
  
  WindowBounds(ThisWindow, 250, 250, #PB_Ignore, #PB_Ignore)
  
  If ThisWindow
    
    ; Maps take a string value as key so convert the integer ThisWindow to a string.
    ThisKey = StrU(ThisWindow)
    
    ; Add a map element to hold the new gadget references.
    AddMapElement(ActiveWindows(), ThisKey)
    
    ; Create the menu bar.
    ActiveWindows(ThisKey)\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    MenuTitle("Window")
    MenuItem(#mnuNew, "New Window")
    MenuItem(#mnuClose, "Close Window")
    
    ; Create the child gadgets and store their references in the map.
    With ActiveWindows()
      
      ; A label for the combo.
      \LabelSides = TextGadget(#PB_Any, 5, 5, 150, 20, "Number of Sides:")
      
      ; The Sides combo.
      \ComboSides = ComboBoxGadget(#PB_Any, 160, 5, 100, 25)
      AddGadgetItem(\ComboSides, 0, "Triangle")
      AddGadgetItem(\ComboSides, 1, "Diamond")
      AddGadgetItem(\ComboSides, 2, "Pentagon")
      AddGadgetItem(\ComboSides, 3, "Hexagon")
      AddGadgetItem(\ComboSides, 4, "Heptagon")
      AddGadgetItem(\ComboSides, 5, "Octagon")
      AddGadgetItem(\ComboSides, 6, "Nonagon")
      AddGadgetItem(\ComboSides, 7, "Decagon")
      
      ; Select Triangle.
      SetGadgetState(\ComboSides, 0)
      
      ; The visual image gadget on the window.
      \ImagePlot = ImageGadget(#PB_Any, 5, 35, 290, 240, 0, #PB_Image_Border)
      
    EndWith
    
  EndIf
  
  ; Return the reference to the new window.
  ProcedureReturn ThisWindow
  
EndProcedure

Procedure DestroyPolygonWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, close the window and set the quit flag, if appropriate.
  
  Shared EvtQuit, ActiveWindows()
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EvtQuit = #True
  EndIf
  
EndProcedure

Procedure.i ResizePolygonWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  ; In practice only the ImageGadget needs to be resized in this example.
  
  Shared ActiveWindows()
  Protected.i ThisImage
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain references to the affected gadgets from the map.
  ThisKey = StrU(Window)
  ThisImage = ActiveWindows(ThisKey)\ImagePlot
  
  ; Resize gadgets.
  W = WindowWidth(Window) - 15
  H = WindowHeight(Window) - 70
  ResizeGadget(ThisImage, #PB_Ignore, #PB_Ignore, W, H)
  
EndProcedure

Procedure PlotPolygon(Window.i)
  
  ; Draw the polygon image and transfer to the on screen gadget.
  
  Shared ActiveWindows()
  Protected.f Radius, OriginX, OriginY, StartX, StartY, EndX, EndY
  Protected.i Sides, Vertex, Width, Height, ThisCombo, ThisImage, ThisPlot
  Protected.s ThisKey
  
  ; Obtain references to the affected gadgets from the map.
  ThisKey = StrU(Window)
  ThisCombo = ActiveWindows(ThisKey)\ComboSides
  ThisImage = ActiveWindows(ThisKey)\ImagePlot
  
  ; Calculate dimensions and origin.
  Sides = GetGadgetState(ThisCombo) + 3
  Width = GadgetWidth(ThisImage) - 4
  Height = GadgetHeight(ThisImage) - 4
  OriginX = Width/2
  OriginY = Height/2
  If Width < Height
    Radius = OriginX - 50
  Else
    Radius = OriginY - 50
  EndIf
  
  ; Create a new image.
  ThisPlot = CreateImage(#PB_Any, Width, Height)
  StartDrawing(ImageOutput(ThisPlot))
  
  ; Draw a white background.
  Box(0, 0, Width, Height, #White)
  
  ; Draw a gray circumscribing circle.
  Circle(OriginX, OriginY, Radius, #Gray)
  
  ; Draw the polygon.
  For Vertex = 0 To Sides
    
    ; Calculate side start point.
    StartX =  OriginX + (Radius * Cos(2 * #PI * Vertex/Sides))
    StartY = OriginY + (Radius * Sin(2 * #PI * Vertex/Sides)) 
    
    ; and end point.
    EndX = OriginX + (Radius * Cos(2 * #PI * (Vertex + 1)/Sides))
    EndY = OriginY + (Radius * Sin(2 * #PI * (Vertex + 1)/Sides))
    
    ; Draw the side in blue.
    LineXY(StartX, StartY, EndX, EndY, #Blue)
    
  Next Vertex
  
  ; Fill the polygon in blue
  FillArea(OriginX, OriginY, #Blue, #Blue)
  
  StopDrawing()
  
  ; Transfer the image contents to the visible gadget.
  SetGadgetState(ThisImage, ImageID(ThisPlot))
  
  ; Destroy the temporary image.
  FreeImage(ThisPlot)
  
EndProcedure

;- Main

; Create the first window.
EvtWindow = CreatePolygonWindow()
ResizePolygonWindow(EvtWindow)
PlotPolygon(EvtWindow)

;- Event loop
Repeat
  
  Evt = WaitWindowEvent()
  EvtWindow = EventWindow()
  EvtWindowKey = StrU(EvtWindow)
  EvtGadget = EventGadget()
  EvtType = EventType()
  EvtMenu = EventMenu()
  
  Select Evt
      
    Case #PB_Event_Gadget
      ; A gadget event has occurred.
      If EvtGadget = ActiveWindows(EvtWindowKey)\LabelSides
        ; Do nothing.
        
      ElseIf EvtGadget = ActiveWindows(EvtWindowKey)\ComboSides
        ; If the combo box changes, redraw the image.
        PlotPolygon(EvtWindow)
        
        ; Update the windows title to reflect the new shape.
        SetWindowTitle(EvtWindow, GetGadgetText(ActiveWindows(EvtWindowKey)\ComboSides))
        
      ElseIf EvtGadget = ActiveWindows(EvtWindowKey)\ImagePlot
        ; Do nothing.
        
      EndIf
      
    Case #PB_Event_Menu
      ; A menu event has occurred.
      If EvtMenu = #mnuNew
        EvtWindow = CreatePolygonWindow()
        ResizePolygonWindow(EvtWindow)
        PlotPolygon(EvtWindow)
        
      ElseIf EvtMenu = #mnuClose
        DestroyPolygonWindow(EvtWindow)
        
      EndIf
      
    Case #PB_Event_Repaint
      ; A window's content has been invalidated.
      PlotPolygon(EvtWindow)
      
    Case #PB_Event_SizeWindow
      ; A window has been resized.
      ResizePolygonWindow(EvtWindow)
      PlotPolygon(EvtWindow)
      
    Case #PB_Event_CloseWindow
      ; A window has been closed.
      DestroyPolygonWindow(EvtWindow)
      
  EndSelect
  
Until EvtQuit = #True
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Multiple Instances of Multiple Windows

Post by spikey »

In the previous article we examined one way in which a program can support multiple instances of a single type of window. In this one we are going to extend this concept further – developing a program that can support multiple instances of several different types of window, in this case three:-

The Button window – contains a list view and two buttons labelled Add and Remove. When the Add button is clicked a random integer is added to the list view, when the remove button is clicked the currently highlighted entry in the list view is removed.

The Date window – contains a list view and two buttons in the same way as the Button window but also contains a calendar gadget too, the window layout is altered to accommodate this additional control. When the Add button is clicked it is the currently selected date that is added to the list view.

The Track window – contains two track bars, with a value between 0 and 100, and a string gadget. When the track bars are moved the string gadget is updated with the value of the second track bar subtracted from the first.

Each window contains a menu bar with items to create a new instance of any of the three supported window types or to close the current window.

Things to notice about this program are:

In the Structures section 4 structures are defined. The first, BASEWINDOW, defines a WindowClass value and a Menu value – these values are common to each window type.

The remaining structures extend the BASEWINDOW structure with values for each of the unique controls that they require and which are not provided for by the BASEWINDOW structure.

In the Variables section note that again a map called ActiveWindows is created, however this time it is of integer type, it doesn’t use any of the defined structures. There is a good reason for this, we need to store three different structure types to make this program work – and we can’t do this in a single map.

Also notice that *EvtGadgets is defined using the BASEWINDOW structure.

Now look at the CreateButtonWindow procedure. As before we use #PB_Any to create the window and all the gadgets.

However this time the results are not stored directly in the ActiveWindows map. Instead we use the AllocateMemory function to allocate memory for a BUTTONWINDOW structure, we then store a pointer to this memory allocation in the ActiveWindows map. This is how we get around the problem of not being able to store all three of the different structures in the same map.

We also set the WindowClass value in the structure to #WindowClassButton to indicate which type of window, and therefore which type of structure, has been created – we will need to know this later on.

There are two more CreateWindow procedures this time – one for each class of the other window types. They work in a similar way to that described, differing only where the window’s gadgets are different and setting a different value in WindowClass.

Similarly we provide DestroyWindow and ResizeWindow procedures to take care of these functions.

We also provide a new procedure – EventsButtonWindow. This procedure knows what to do when any of the gadgets on the window are activated by the user. Similar procedures are provided for the other window types too.

In all these procedures we use the ActiveWindows map to retrieve the pointer to the memory allocation. We can then use this pointer to retrieve the references to the actual controls that we need to work with in each of these procedures:-
*ThisData = ActiveWindows(ThisKey)
*ThisData\ListView …

Each procedure only knows how to handle one type of window – so before we start work we check the WindowClass value to make sure that a window of the correct type has been supplied as the argument something like this:-
If *ThisData\WindowClass <> #WindowClassButton

The event loop is a bit different too. For each event type there is a determination like this:-
; Use *EvtGadgets\WindowClass to call the correct resize window procedure.
Select *EvtGadgets\WindowClass …

Although the memory allocations actually made by the CreateWindow procedures will be of the BUTTONWINDOW, DATEWINDOW or TRACKWINDOW type we can use *EvtGadgets this way because it is defined as the BASEWINDOW type and BASEWINDOW is the ancestor structure to the other structures.

Providing we don’t attempt to change any of the stored values using *EvtGadgets – and we’ve no reason to do so – all should be well.

Finally, we despatch the recorded event values in EvtWindow, EvtGadget, EvtType straight through to the event procedures and let them worry about getting the jobs done.

Code: Select all

;- Constants
#DateFormat = "%dd/%mm/%yyyy"

;- Enumerations
Enumeration 
  #WindowClassButton = 1
  #WindowClassDate
  #WindowClassTrack
EndEnumeration

; The menu commands will be the same on all the windows.
Enumeration
  #mnuNewButton
  #mnuNewDate
  #mnuNewTrack
  #mnuClose
EndEnumeration

;- Structures
Structure BASEWINDOW
  WindowClass.i 
  Menu.i  
EndStructure

Structure BUTTONWINDOW Extends BASEWINDOW
  ListView.i
  AddButton.i
  RemoveButton.i  
EndStructure

Structure DATEWINDOW Extends BASEWINDOW
  Calendar.i
  AddButton.i
  RemoveButton.i
  ListView.i
EndStructure

Structure TRACKWINDOW Extends BASEWINDOW
  TrackBar1.i
  TrackBar2.i
  Label.i
  Difference.i
EndStructure

;- Variables
; This map will track all the active windows as before, however as the structure for each window class
; differs we will be storing pointers to structures in the map not the gadget references directly.
NewMap ActiveWindows.i()

; These values will be used to give new windows a unique label.
Define.i Buttons, Dates, Tracks

; Event variables.
; Notice the type of *EvtGadgets.
Define.i Evt, EvtWindow, EvtGadget, EvtType, EvtMenu, EvtQuit
Define.s EvtWindowKey
Define *EvtGadgets.BASEWINDOW  

;- Button Window
Procedure.i CreateButtonWindow()
  
  ; Creates a new Button window and gadgets, adds it to the tracking map, 
  ; allocates memory for gadget references and stores these in the map.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i ThisWindow
  Protected.s ThisKey, ThisTitle
  
  ; Set the window caption.
  Buttons + 1
  ThisTitle = "Button Window " + StrU(Buttons)
  
  ; Open the window.
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 225, 300, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
  
  ; Set minimum window dimensions.
  WindowBounds(ThisWindow, 220, 100, #PB_Ignore, #PB_Ignore)
  
  ; Check that the OpenWindow command worked.
  If ThisWindow
    
    ; Convert the window reference to a string to use as the map key value.
    ThisKey = StrU(ThisWindow)
    
    ; Allocate memory to store the gadget references in.
    *ThisData = AllocateMemory(SizeOf(BUTTONWINDOW))
    
    ; Store the window reference and memory pointer values in the map.
    ActiveWindows(ThisKey) = *ThisData
    
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassButton
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\ListView = ListViewGadget(#PB_Any, 10, 10, 200, 225)
    *ThisData\AddButton = ButtonGadget(#PB_Any, 15, 245, 90, 30, "Add")
    *ThisData\RemoveButton = ButtonGadget(#PB_Any, 115, 245, 90, 30, "Remove")
    
  EndIf
  
  ; Return the reference to the new window.
  ProcedureReturn ThisWindow
  
EndProcedure

Procedure.i DestroyButtonWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EvtQuit, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EvtQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeButtonWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf
  
  ; Resize list view.
  W = WindowWidth(Window) - 25
  H = WindowHeight(Window) - 85
  ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
  
  ; Recentre buttons.
  X = WindowWidth(Window)/2 - 95
  Y = WindowHeight(Window) - 65
  ResizeGadget(*ThisData\AddButton, X, Y, #PB_Ignore, #PB_Ignore)
  
  X = WindowWidth(Window)/2 + 5
  ResizeGadget(*ThisData\RemoveButton, X, Y, #PB_Ignore, #PB_Ignore)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsButtonWindow(Window, Gadget, Type)
  
  ; Handle events for a button window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i NewValue, Index
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf

  Select Gadget
      
    Case *ThisData\AddButton
      NewValue = Random(2147483647)
      AddGadgetItem(*ThisData\ListView, -1, StrU(NewValue))
      
    Case *ThisData\RemoveButton
      Index = GetGadgetState(*ThisData\ListView)
      If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
        RemoveGadgetItem(*ThisData\ListView, Index)
      EndIf
      
    Case *ThisData\ListView
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Date Window
Procedure.i CreateDateWindow()
  
  ; Creates a new Date window and gadgets, adds it to the tracking map, 
  ; allocates memory for gadget references and stores these.
  
  Shared Dates, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i ThisWindow
  Protected.s ThisKey, ThisTitle
  
  Dates + 1
  ThisTitle = "Date Window " + StrU(Dates)
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 310, 420, ThisTitle , #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
  
  ; Set minimum window dimensions.
  WindowBounds(ThisWindow, 310, 245, #PB_Ignore, #PB_Ignore)
    
  ; Allocate memory to store the gadget references in.
  If ThisWindow
    ThisKey = StrU(ThisWindow)
    *ThisData = AllocateMemory(SizeOf(DATEWINDOW))
    ActiveWindows(ThisKey) = *ThisData
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassDate
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\Calendar = CalendarGadget(#PB_Any, 10, 10, 182, 162)
    *ThisData\AddButton = ButtonGadget(#PB_Any, 210, 10, 90, 30, "Add")
    *ThisData\RemoveButton = ButtonGadget(#PB_Any, 210, 45, 90, 30, "Remove")
    *ThisData\ListView = ListViewGadget(#PB_Any, 10, 187, 290, 200)
    
  EndIf
  
  ; Return the reference to the new window.
  ProcedureReturn ThisWindow
  
EndProcedure

Procedure.i DestroyDateWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EvtQuit, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EvtQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeDateWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  ; Resize list view.
  W = WindowWidth(Window) - 20
  H = WindowHeight(Window) - 220
  ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsDateWindow(Window, Gadget, Type)
  
  ; Handle events for a Date window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i NewValue, Index
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  Select Gadget
      
    Case *ThisData\AddButton
      NewValue = GetGadgetState(*ThisData\Calendar)
      AddGadgetItem(*ThisData\ListView, -1, FormatDate(#DateFormat, NewValue))
      
    Case *ThisData\RemoveButton
      Index = GetGadgetState(*ThisData\ListView)
      If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
        RemoveGadgetItem(*ThisData\ListView, Index)
      EndIf
      
    Case *ThisData\Calendar, *ThisData\ListView
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Track Window
Procedure.i CreateTrackWindow()
  
  ; Creates a new Track window and gadgets, adds it to the tracking map, 
  ; allocates memory for gadget references and stores these.
  
  Shared Tracks, ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i ThisWindow, ThisSum
  Protected.s ThisKey, ThisTitle
  
  Tracks + 1
  ThisTitle = "Track Bar Window " + StrU(Tracks)
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 398, 130, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
  
  ; Set minimum window dimensions.
  WindowBounds(ThisWindow, 135, 130, #PB_Ignore, 130)
  
  ; Allocate memory to store the gadget references in.
  If ThisWindow
    ThisKey = StrU(ThisWindow)
    *ThisData = AllocateMemory(SizeOf(TRACKWINDOW))
    ActiveWindows(ThisKey) = *ThisData
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassTrack
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\TrackBar1 = TrackBarGadget(#PB_Any, 10, 10, 375, 25, 0, 100, #PB_TrackBar_Ticks)
    *ThisData\TrackBar2 = TrackBarGadget(#PB_Any, 10, 40, 375, 25, 0, 100, #PB_TrackBar_Ticks)
    *ThisData\Label = TextGadget(#PB_Any, 10, 75, 80, 25, "Difference:")
    *ThisData\Difference = StringGadget(#PB_Any, 90, 75, 290, 25, "0", #PB_String_ReadOnly)
    
  EndIf
  
  ; Return the reference to the new window.
  ProcedureReturn ThisWindow
  
EndProcedure

Procedure.i DestroyTrackWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EvtQuit, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EvtQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeTrackWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  ; Resize track bars.
  W = WindowWidth(Window) - 20
  ResizeGadget(*ThisData\TrackBar1, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  ResizeGadget(*ThisData\TrackBar2, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  
  ; Resize string.
  W = WindowWidth(Window) - 110
  ResizeGadget(*ThisData\Difference, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsTrackWindow(Window, Gadget, Type)
  
  ; Handle events for a Track window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i NewValue
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  Select Gadget
      
    Case *ThisData\TrackBar1, *ThisData\TrackBar2
      NewValue = GetGadgetState(*ThisData\TrackBar1) - GetGadgetState(*ThisData\TrackBar2)
      SetGadgetText(*ThisData\Difference, Str(NewValue))
      
    Case *ThisData\Label, *ThisData\Difference
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Main

; Create the first window.
EvtWindow = CreateButtonWindow()
ResizeButtonWindow(EvtWindow)

;- Event loop
Repeat
  
  Evt = WaitWindowEvent()
  EvtWindow = EventWindow()
  EvtWindowKey = StrU(EvtWindow)
  EvtGadget = EventGadget()
  EvtType = EventType()
  EvtMenu = EventMenu()
  *EvtGadgets = ActiveWindows(EvtWindowKey)
  
  Select Evt
      
    Case #PB_Event_Gadget
      
      ; Use *EvtGadgets\WindowClass to despatch events to the correct event procedure.
      Select *EvtGadgets\WindowClass
          
        Case #WindowClassButton
          EventsButtonWindow(EvtWindow, EvtGadget, EvtType)
          
        Case #WindowClassDate
          EventsDateWindow(EvtWindow, EvtGadget, EvtType)
          
        Case #WindowClassTrack
          EventsTrackWindow(EvtWindow, EvtGadget, EvtType)
          
        Default
          ; Do nothing
          
      EndSelect
      
    Case #PB_Event_Menu
      
      Select EvtMenu
          
        Case #mnuNewButton
          EvtWindow = CreateButtonWindow()
          ResizeButtonWindow(EvtWindow)
          
        Case #mnuNewDate
          EvtWindow = CreateDateWindow()
          ResizeDateWindow(EvtWindow)
          
        Case #mnuNewTrack
          EvtWindow = CreateTrackWindow()
          ResizeTrackWindow(EvtWindow)
          
        Case #mnuClose
          
          ; Use *EvtGadgets\WindowClass to call the correct destroy window procedure.    
          Select *EvtGadgets\WindowClass
              
            Case #WindowClassButton
              DestroyButtonWindow(EvtWindow)
              
            Case #WindowClassDate
              DestroyDateWindow(EvtWindow)
              
            Case #WindowClassTrack
              DestroyTrackWindow(EvtWindow)
              
            Default
              ; Do nothing
              
          EndSelect
          
      EndSelect
      
    Case #PB_Event_CloseWindow
      
      ; Use *EvtGadgets\WindowClass to call the correct destroy window procedure.
      Select *EvtGadgets\WindowClass
          
        Case #WindowClassButton
          DestroyButtonWindow(EvtWindow)
          
        Case #WindowClassDate
          DestroyDateWindow(EvtWindow)
          
        Case #WindowClassTrack
          DestroyTrackWindow(EvtWindow)
          
        Default
          ; Do nothing
          
      EndSelect
      
    Case #PB_Event_SizeWindow     
      
      ; Use *EvtGadgets\WindowClass to call the correct resize window procedure.
      Select *EvtGadgets\WindowClass
          
        Case #WindowClassButton
          ResizeButtonWindow(EvtWindow)
          
        Case #WindowClassDate
          ResizeDateWindow(EvtWindow)
          
        Case #WindowClassTrack
          ResizeTrackWindow(EvtWindow)
          
        Default
          ; Do nothing
          
      EndSelect
      
  EndSelect
  
Until EvtQuit = #True
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

Hi spikey,

thanks a lot for your further contributions. :D
It's really a lot of text and code.... :wink:

I finished implementing the first new posting of 31th January 2013 into the 'Beginners' chapter of the PB manual. Need to do it for the other one too...

What I noticed, when testing the code on my MacBook, OS X 10.5.8:

- First example crashes with an IMA at WaitWindowEvent(), when I had several windows opened and then close the last one via the menu item 'Close window'. Also not the actual window is closed, but the previously opened window instead (maybe this is a OS X-specific issue, as there is only one menu-bar for all windows of a program).

- Similar problem with the second example when several windows are opened (IMA at WaitWindowEvent(), sometimes also a 'Pointer is null' on line 624 ( Select *EvtGadgets\WindowClass).
Furthermore I noticed a problem with the DateGadget: after moving from Feb'2013 to July'2013 and selecting 24th July 2013 as data in the gadget, it will output 23th July 2013 after clicking on 'Add'...

Don't know if this issues can be confirmed on Windows too!?


PS: about the 'String handling' chapter - would be good, if you can contribute it until tomorrow as the final release of PB5.10 is close... 8)
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

String Manipulation article

Post by spikey »

Code: Select all

Define.s String1, String2, String3

String1 = "The quick brown fox jumps over the lazy dog."

; Left returns a number of characters from the left hand end of a string.
; Mid returns a number of characters from the given start location in the middle of a string.
; Right returns a number of characters from the right hand end of a string.
; Space returns the specified number of space characters as a string.
; Shows "The brown dog."
Debug "* Left, Mid and Right"
String2 = Left(String1, 3) + Space(1) + Mid(String1, 11, 5) + Space(1) + Right(String1, 4)
Debug String2

; CountString returns the number of instances of the second string in the first string, it is case sensitive.
; Shows 1.
Debug "* CountString"
Debug CountString(String1, "the")

; However the LCase (and UCase) functions can be used to switch a string to all lower (or upper) case
; Shows 2
Debug "* CountString and LCase"
String2 = LCase(String1)
Debug CountString(String2, "the")

; FindString can be used to find the location of one string within another.
; Shows 17.
Debug "* FindString"
Debug FindString(String1, "fox")

; RemoveString can be used to remove one string from within another.
; Shows The quick fox jumps over the lazy dog.
Debug "* RemoveString"
String2 = RemoveString(String1, " brown")
Debug String2

; ReplaceString can be used to change the occurence of a substring within another string.
; Shows The quick brown fox jumps over the sleeping dog.
Debug "* ReplaceString"
String2 = ReplaceString(String1, "lazy", "sleeping")
Debug String2

; StringByteLength returns the length of a string in bytes in the specified format, or the current default
; if one is not specified (excluding the terminating null).
Debug "* StringByteLength"
; Shows 44.
Debug StringByteLength(String1, #PB_Ascii)
; Shows 88.
Debug StringByteLength(String1, #PB_Unicode)

; StringField can be used to obtain an indexed substring from a target string. 
; Useful for converting strings to lists for example.
; StringField will work with space as a delimiter too 
; but hopefully this example makes the functions behaviour more apparent.
; Shows jumps.
Debug "* StringField"
String2 = ReplaceString(String1, " ", "\")
Debug String2
String3 = StringField(String2, 5, "\")
Debug String3

; Trim removes white space characters from the start and end of a given string.
; Similarly, LTrim acts on the left hand end (start) of a string and RTrim the right hand end.
Debug "* Trim, LTrim and RTrim"
String2 = Space(10) + String1 + Space(8)
Debug #DQUOTE$ + String2 + #DQUOTE$
String3 = Trim(String2)
Debug #DQUOTE$ + String3 + #DQUOTE$
String3 = LTrim(String2)
Debug #DQUOTE$ + String3 + #DQUOTE$
String3 = RTrim(String2)
Debug #DQUOTE$ + String3 + #DQUOTE$

; LSet sets a string to be a specific length from the left hand end, padding with spaces, 
; or other specified character, as necessary.
; If the string is already longer than the specified length it will be truncated.
Debug "*LSet"
Debug LSet("Abc", 10, "*")
Debug LSet("Abcd", 10, "*")
Debug LSet("Abcde", 10, "*")

; Similarly RSet pads a string from its right hand end.
Debug "* RSet"
Debug RSet("1.23", 10, "0")
Debug RSet("10.23", 10, "0")
Debug RSet("100.23", 10, "0")

; Str converts a signed quad value to a string, similarly StrF converts floats, 
; StrD converts doubles and StrU converts unsigned values, these two function have an optional 
; parameter to specify the number of decimal places to show.
Debug "* Str, StrF and StrD"
Debug Str(100)
Debug StrF(1.234, 3)
Debug StrD(123456.789, 3)

; Val will convert a string value into its numeric (quad) equivalent.
; ValD and ValF perform the same function for floats and doubles.
Debug "* Val"
Debug Val("123")

; Bin will convert a numeric value into its binary equivalent.
; Hex will convert one into its hexadecimal equivalent.
Debug "* Bin and Hex"
Debug Bin(19)
Debug Hex(19)

User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by spikey »

Andre wrote: - First example crashes with an IMA at WaitWindowEvent(), when I had several windows opened and then close the last one via the menu item 'Close window'. Also not the actual window is closed, but the previously opened window instead (maybe this is a OS X-specific issue, as there is only one menu-bar for all windows of a program).

- Similar problem with the second example when several windows are opened (IMA at WaitWindowEvent(), sometimes also a 'Pointer is null' on line 624 ( Select *EvtGadgets\WindowClass).
Furthermore I noticed a problem with the DateGadget: after moving from Feb'2013 to July'2013 and selecting 24th July 2013 as data in the gadget, it will output 23th July 2013 after clicking on 'Add'...

Don't know if this issues can be confirmed on Windows too!?
Hmm - no can't replicate the IMA or date problem on Windows XP, 7 or Ubuntu...
I can't think of any reason why it should IMA at WaitWindowEvent off the top of my head and I don't have access to any Mac OS machines so I can't test for myself :(

Mea culpa on the null pointer however - there are several points where a theoretical null pointer could arise, I wasn't expecting them to go beyond theoretical though so I left some traps out to keep the example code a bit shorter - I'll put some more in... :lol:
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

spikey wrote: Hmm - no can't replicate the IMA or date problem on Windows XP, 7 or Ubuntu...
I can't think of any reason why it should IMA at WaitWindowEvent off the top of my head and I don't have access to any Mac OS machines so I can't test for myself :(

Mea culpa on the null pointer however - there are several points where a theoretical null pointer could arise, I wasn't expecting them to go beyond theoretical though so I left some traps out to keep the example code a bit shorter - I'll put some more in... :lol:
Thanks in advance.
You are absolutely right, when you think about descriptions and code examples as short as possible! :D

Just to let you know, what I've changed in your first code example (e.g. more "speaking" variable names), here is the updated code. You should use it as "base" for further updates.... Maybe also the "CompilerIf Defined...." at the color constants is not needed, as I read several times on the forum?

Code: Select all

  ; Compiler Directives
  EnableExplicit
  
  ; Constants
  CompilerIf Defined(Blue, #PB_Constant) = #False
    #Blue = 16711680
    #Gray = 8421504
    #White = 16777215
  CompilerEndIf
  
  ;- Enumerations
  ; The menu commands will be the same on all the windows.
  Enumeration
    #MenuNew
    #MenuClose
  EndEnumeration
  
  ;- Structures
  ; This structure will hold references to the unique elements of a window.
  Structure POLYGONWINDOW
    Menu.i
    LabelSides.i
    ComboSides.i
    ImagePlot.i
  EndStructure
  
  ;- Variables
  
  ; This map uses the previously defined structure to hold references for all the open windows.
  NewMap ActiveWindows.POLYGONWINDOW()
  
  ; Event variables.
  Define.i Event, EventWindow, EventGadget, EventType, EventMenu, EventQuit
  Define.s EventWindowKey
  
  ; Implementation.
  Procedure.i CreatePolygonWindow()
    ; Creates a new window and gadgets, adding it and its child gadgets to the tracking map.
    Shared ActiveWindows()
    Protected.i ThisWindow
    Protected.s ThisKey
    
    ThisWindow = OpenWindow(#PB_Any, 50, 50, 300, 300, "Polygon", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)  
    
    WindowBounds(ThisWindow, 250, 250, #PB_Ignore, #PB_Ignore)
    
    If ThisWindow
      ; Maps take a string value as key so convert the integer ThisWindow to a string.
      ThisKey = StrU(ThisWindow)
      
      ; Add a map element to hold the new gadget references.
      AddMapElement(ActiveWindows(), ThisKey)
      
      ; Create the menu bar.
      ActiveWindows(ThisKey)\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
      MenuTitle("Window")
      MenuItem(#MenuNew, "New Window")
      MenuItem(#MenuClose, "Close Window")
      
      ; Create the child gadgets and store their references in the map.
      With ActiveWindows()
        ; A label for the combo.
        \LabelSides = TextGadget(#PB_Any, 5, 5, 150, 20, "Number of Sides:")
        
        ; The Sides combo.
        \ComboSides = ComboBoxGadget(#PB_Any, 160, 5, 100, 25)
        AddGadgetItem(\ComboSides, 0, "Triangle")
        AddGadgetItem(\ComboSides, 1, "Diamond")
        AddGadgetItem(\ComboSides, 2, "Pentagon")
        AddGadgetItem(\ComboSides, 3, "Hexagon")
        AddGadgetItem(\ComboSides, 4, "Heptagon")
        AddGadgetItem(\ComboSides, 5, "Octagon")
        AddGadgetItem(\ComboSides, 6, "Nonagon")
        AddGadgetItem(\ComboSides, 7, "Decagon")
        
        ; Select Triangle.
        SetGadgetState(\ComboSides, 0)
        
        ; The visual image gadget on the window.
        \ImagePlot = ImageGadget(#PB_Any, 5, 35, 290, 240, 0, #PB_Image_Border)
      EndWith
    EndIf
    
    ; Return the reference to the new window.
    ProcedureReturn ThisWindow
  EndProcedure
  
  Procedure DestroyPolygonWindow(Window.i)
    ; Remove Window from the ActiveWindows map, close the window and set the quit flag, if appropriate.
    Shared EventQuit, ActiveWindows()
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Delete the map entry.
    DeleteMapElement(ActiveWindows(), ThisKey)
    
    ; Close the window.
    CloseWindow(Window)
    
    ; Check if there are still open windows.
    If MapSize(ActiveWindows()) = 0
      EventQuit = #True
    EndIf
  EndProcedure
  
  Procedure.i ResizePolygonWindow(Window.i)
    ; Resize the child gadgets on Window.
    ; In practice only the ImageGadget needs to be resized in this example.
    Shared ActiveWindows()
    Protected.i ThisImage
    Protected.i X, Y, W, H
    Protected.s ThisKey
    
    ; Obtain references to the affected gadgets from the map.
    ThisKey = StrU(Window)
    ThisImage = ActiveWindows(ThisKey)\ImagePlot
    
    ; Resize gadgets.
    W = WindowWidth(Window) - 15
    H = WindowHeight(Window) - 70
    ResizeGadget(ThisImage, #PB_Ignore, #PB_Ignore, W, H)
  EndProcedure
  
  Procedure PlotPolygon(Window.i)
    ; Draw the polygon image and transfer it to the image gadget.
    Shared ActiveWindows()
    Protected.f Radius, OriginX, OriginY, StartX, StartY, EndX, EndY
    Protected.i Sides, Vertex, Width, Height, ThisCombo, ThisImage, ThisPlot
    Protected.s ThisKey
    
    ; Obtain references to the affected gadgets from the map.
    ThisKey = StrU(Window)
    ThisCombo = ActiveWindows(ThisKey)\ComboSides
    ThisImage = ActiveWindows(ThisKey)\ImagePlot
    
    ; Calculate dimensions and origin.
    Sides = GetGadgetState(ThisCombo) + 3
    Width = GadgetWidth(ThisImage) - 4
    Height = GadgetHeight(ThisImage) - 4
    OriginX = Width/2
    OriginY = Height/2
    If Width < Height
      Radius = OriginX - 50
    Else
      Radius = OriginY - 50
    EndIf
    
    ; Create a new image.
    ThisPlot = CreateImage(#PB_Any, Width, Height)
    StartDrawing(ImageOutput(ThisPlot))
    
    ; Draw a white background.
    Box(0, 0, Width, Height, #White)
    
    ; Draw a gray circumscribing circle.
    Circle(OriginX, OriginY, Radius, #Gray)
    
    ; Draw the polygon.
    For Vertex = 0 To Sides
      
      ; Calculate side start point.
      StartX =  OriginX + (Radius * Cos(2 * #PI * Vertex/Sides))
      StartY = OriginY + (Radius * Sin(2 * #PI * Vertex/Sides)) 
      
      ; and end point.
      EndX = OriginX + (Radius * Cos(2 * #PI * (Vertex + 1)/Sides))
      EndY = OriginY + (Radius * Sin(2 * #PI * (Vertex + 1)/Sides))
      
      ; Draw the side in blue.
      LineXY(StartX, StartY, EndX, EndY, #Blue)
      
    Next Vertex
    
    ; Fill the polygon in blue
    FillArea(OriginX, OriginY, #Blue, #Blue)
    
    StopDrawing()
    
    ; Transfer the image contents to the visible gadget.
    SetGadgetState(ThisImage, ImageID(ThisPlot))
    
    ; Destroy the temporary image.
    FreeImage(ThisPlot)
  EndProcedure
  
  ;- Main
  
  ; Create the first window.
  EventWindow = CreatePolygonWindow()
  ResizePolygonWindow(EventWindow)
  PlotPolygon(EventWindow)
  
  ;- Event loop
  Repeat
    Event = WaitWindowEvent()
    EventWindow = EventWindow()
    EventWindowKey = StrU(EventWindow)
    EventGadget = EventGadget()
    EventType = EventType()
    EventMenu = EventMenu()
    
    Select Event
      Case #PB_Event_Gadget
        ; A gadget event has occurred.
        If EventGadget = ActiveWindows(EventWindowKey)\LabelSides
          ; Do nothing.
          
        ElseIf EventGadget = ActiveWindows(EventWindowKey)\ComboSides
          ; If the combo box changes, redraw the image.
          PlotPolygon(EventWindow)
          
          ; Update the windows title to reflect the new shape.
          SetWindowTitle(EventWindow, GetGadgetText(ActiveWindows(EventWindowKey)\ComboSides))
          
        ElseIf EventGadget = ActiveWindows(EventWindowKey)\ImagePlot
          ; Do nothing.
          
        EndIf
        
      Case #PB_Event_Menu
        ; A menu event has occurred.
        If EventMenu = #MenuNew
          EventWindow = CreatePolygonWindow()
          ResizePolygonWindow(EventWindow)
          PlotPolygon(EventWindow)
          
        ElseIf EventMenu = #MenuClose
          DestroyPolygonWindow(EventWindow)
          
        EndIf
        
      Case #PB_Event_Repaint
        ; A window's content has been invalidated.
        PlotPolygon(EventWindow)
        
      Case #PB_Event_SizeWindow
        ; A window has been resized.
        ResizePolygonWindow(EventWindow)
        PlotPolygon(EventWindow)
        
      Case #PB_Event_CloseWindow
        ; A window has been closed.
        DestroyPolygonWindow(EventWindow)
        
    EndSelect
    
  Until EventQuit = #True
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by ts-soft »

I think the Case #PB_Event_Gadget part can be shortened to:

Code: Select all

        If EventGadget = ActiveWindows(EventWindowKey)\ComboSides
          ; Update the windows title to reflect the new shape.
          SetWindowTitle(EventWindow, GetGadgetText(ActiveWindows(EventWindowKey)\ComboSides))
        EndIf
the rest should be useless :wink:

Greetings - Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Multiple Instances of Multiple Windows - code version 2

Post by spikey »

Code: Select all

;- Constants
#DateFormat = "%dd/%mm/%yyyy"

;- Enumerations
Enumeration 
  #WindowClassButton = 1
  #WindowClassDate
  #WindowClassTrack
EndEnumeration

; The menu commands will be the same on all the windows.
Enumeration
  #mnuNewButton
  #mnuNewDate
  #mnuNewTrack
  #mnuClose
EndEnumeration

;- Structures
Structure BASEWINDOW
  WindowClass.i 
  Menu.i  
EndStructure

Structure BUTTONWINDOW Extends BASEWINDOW
  ListView.i
  AddButton.i
  RemoveButton.i  
EndStructure

Structure DATEWINDOW Extends BASEWINDOW
  Calendar.i
  AddButton.i
  RemoveButton.i
  ListView.i
EndStructure

Structure TRACKWINDOW Extends BASEWINDOW
  TrackBar1.i
  TrackBar2.i
  Label.i
  Difference.i
EndStructure

;- Variables
; This map will track all the active windows as before, however as the structure for each window class
; differs we will be storing pointers to structures in the map not the gadget references directly.
NewMap ActiveWindows.i()

; These values will be used to give new windows a unique label.
Define.i Buttons, Dates, Tracks

; Event variables.
; Notice the type of *EventGadgets.
Define.i Event, EventWindow, EventGadget, EventType, EventMenu, EventQuit
Define.s EventWindowKey
Define *EventGadgets.BASEWINDOW  

;- Button Window
Procedure.i CreateButtonWindow()
  
  ; Creates a new Button window and adds it to the tracking map, 
  ; allocates memory for gadget references, creates the gadgets 
  ; and stores these references in the memory Structure.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i ThisWindow
  Protected.s ThisKey, ThisTitle
  
  ; Set the window caption.
  Buttons + 1
  ThisTitle = "Button Window " + StrU(Buttons)
  
  ; Open the window.
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 225, 300, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
  
  ; Check that the OpenWindow command worked.
  If ThisWindow
    
    ; Set minimum window dimensions.
    WindowBounds(ThisWindow, 220, 100, #PB_Ignore, #PB_Ignore)
    
    ; Convert the window reference to a string to use as the map key value.
    ThisKey = StrU(ThisWindow)
    
    ; Allocate memory to store the gadget references in.
    *ThisData = AllocateMemory(SizeOf(BUTTONWINDOW))
    
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Store the window reference and memory pointer values in the map.
    ActiveWindows(ThisKey) = *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassButton
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\ListView = ListViewGadget(#PB_Any, 10, 10, 200, 225)
    *ThisData\AddButton = ButtonGadget(#PB_Any, 15, 245, 90, 30, "Add")
    *ThisData\RemoveButton = ButtonGadget(#PB_Any, 115, 245, 90, 30, "Remove")
    
  Else
    ; Memory allocation failed.
    CloseWindow(ThisWindow)
    
  EndIf
  
  ; Set the return value.
  If ThisWindow > 0 And *ThisData > 0
    ; Return the reference to the new window.
    ProcedureReturn ThisWindow
    
  Else
    ; Return 0
    ProcedureReturn 0
    
  EndIf
  
EndProcedure

Procedure.i DestroyButtonWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EventQuit, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EventQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeButtonWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf
  
  ; Resize list view.
  W = WindowWidth(Window) - 25
  H = WindowHeight(Window) - 85
  ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
  
  ; Recentre buttons.
  X = WindowWidth(Window)/2 - 95
  Y = WindowHeight(Window) - 65
  ResizeGadget(*ThisData\AddButton, X, Y, #PB_Ignore, #PB_Ignore)
  
  X = WindowWidth(Window)/2 + 5
  ResizeGadget(*ThisData\RemoveButton, X, Y, #PB_Ignore, #PB_Ignore)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsButtonWindow(Window, Gadget, Type)
  
  ; Handle events for a button window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.BUTTONWINDOW
  Protected.i NewValue, Index
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassButton
    ProcedureReturn #False
  EndIf
  
  Select Gadget
      
    Case *ThisData\AddButton
      NewValue = Random(2147483647)
      AddGadgetItem(*ThisData\ListView, -1, StrU(NewValue))
      
    Case *ThisData\RemoveButton
      Index = GetGadgetState(*ThisData\ListView)
      If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
        RemoveGadgetItem(*ThisData\ListView, Index)
      EndIf
      
    Case *ThisData\ListView
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Date Window
Procedure.i CreateDateWindow()
  
  ; Creates a new Date window and adds it to the tracking map, 
  ; allocates memory for gadget references, creates the gadgets 
  ; and stores these references in the memory Structure.
  
  Shared Dates, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i ThisWindow
  Protected.s ThisKey, ThisTitle
  
  Dates + 1
  ThisTitle = "Date Window " + StrU(Dates)
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 310, 420, ThisTitle , #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
  ; Check that the OpenWindow command worked.
  If ThisWindow
    
    ; Set minimum window dimensions.
    WindowBounds(ThisWindow, 310, 245, #PB_Ignore, #PB_Ignore)
    
    ; Convert the window reference to a string to use as the map key value.
    ThisKey = StrU(ThisWindow)
    
    ; Allocate memory to store the gadget references in.
    *ThisData = AllocateMemory(SizeOf(DATEWINDOW))
    
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Store the window reference and memory pointer values in the map.
    ActiveWindows(ThisKey) = *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassDate
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\Calendar = CalendarGadget(#PB_Any, 10, 10, 182, 162)
    *ThisData\AddButton = ButtonGadget(#PB_Any, 210, 10, 90, 30, "Add")
    *ThisData\RemoveButton = ButtonGadget(#PB_Any, 210, 45, 90, 30, "Remove")
    *ThisData\ListView = ListViewGadget(#PB_Any, 10, 187, 290, 200)
    
  Else
    ; Memory allocation failed.
    CloseWindow(ThisWindow)
    
  EndIf
  
  ; Set the return value.
  If ThisWindow > 0 And *ThisData > 0 
    ; Return the reference to the new window.
    ProcedureReturn ThisWindow
    
  Else
    ; Return 0
    ProcedureReturn 0
    
  EndIf
  
EndProcedure

Procedure.i DestroyDateWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EventQuit, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EventQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeDateWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  ; Resize list view.
  W = WindowWidth(Window) - 20
  H = WindowHeight(Window) - 220
  ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsDateWindow(Window, Gadget, Type)
  
  ; Handle events for a Date window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.i NewValue, Index
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassDate
    ProcedureReturn #False
  EndIf
  
  Select Gadget
      
    Case *ThisData\AddButton
      NewValue = GetGadgetState(*ThisData\Calendar)
      AddGadgetItem(*ThisData\ListView, -1, FormatDate(#DateFormat, NewValue))
      
    Case *ThisData\RemoveButton
      Index = GetGadgetState(*ThisData\ListView)
      If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
        RemoveGadgetItem(*ThisData\ListView, Index)
      EndIf
      
    Case *ThisData\Calendar, *ThisData\ListView
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Track Window
Procedure.i CreateTrackWindow()
  
  ; Creates a new Track window and adds it to the tracking map, 
  ; allocates memory for gadget references, creates the gadgets 
  ; and stores these references in the memory Structure.
  
  Shared Tracks, ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i ThisWindow, ThisSum
  Protected.s ThisKey, ThisTitle
  
  Tracks + 1
  ThisTitle = "Track Bar Window " + StrU(Tracks)
  ThisWindow = OpenWindow(#PB_Any, 30, 30, 398, 130, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
  
  ; Check that the OpenWindow command worked.
  If ThisWindow
    
    ; Set minimum window dimensions.
    WindowBounds(ThisWindow, 135, 130, #PB_Ignore, 130)
    
    ; Convert the window reference to a string to use as the map key value.
    ThisKey = StrU(ThisWindow)
    
    ; Allocate memory to store the gadget references in.
    *ThisData = AllocateMemory(SizeOf(TRACKWINDOW))
    
  EndIf
  
  ; Check that the memory allocation worked.
  If *ThisData
    
    ; Store the window reference and memory pointer values in the map.
    ActiveWindows(ThisKey) = *ThisData
    
    ; Set the window class.
    *ThisData\WindowClass = #WindowClassTrack
    
    ; Create the menu bar.
    *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
    
    ; If the menu creation worked, create the menu items.
    If *ThisData\Menu
      MenuTitle("Window")
      MenuItem(#mnuNewButton, "New Button Window")
      MenuItem(#mnuNewDate, "New Date Window")
      MenuItem(#mnuNewTrack, "New Track Window")
      MenuItem(#mnuClose, "Close Window")
    EndIf
    
    ; Create the window gadgets.
    *ThisData\TrackBar1 = TrackBarGadget(#PB_Any, 10, 10, 375, 25, 0, 100, #PB_TrackBar_Ticks)
    *ThisData\TrackBar2 = TrackBarGadget(#PB_Any, 10, 40, 375, 25, 0, 100, #PB_TrackBar_Ticks)
    *ThisData\Label = TextGadget(#PB_Any, 10, 75, 80, 25, "Difference:")
    *ThisData\Difference = StringGadget(#PB_Any, 90, 75, 290, 25, "0", #PB_String_ReadOnly)
    
  Else
    ; Memory allocation failed.
    CloseWindow(ThisWindow)
    
  EndIf
  
  ; Set the return value.
  If ThisWindow > 0 And *ThisData > 0
    ; Return the reference to the new window.
    ProcedureReturn ThisWindow
    
  Else
    ; Return 0
    ProcedureReturn 0
    
  EndIf
  
EndProcedure

Procedure.i DestroyTrackWindow(Window.i)
  
  ; Remove Window from the ActiveWindows map, release the allocated memory,
  ; close the window and set the quit flag, if appropriate.
  
  Shared EventQuit, ActiveWindows()
  Protected *ThisData.DATEWINDOW
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  ; Release the memory allocation.
  FreeMemory(*ThisData)
  
  ; Delete the map entry.
  DeleteMapElement(ActiveWindows(), ThisKey)
  
  ; Close the window.
  CloseWindow(Window)
  
  ; Check if there are still open windows.
  If MapSize(ActiveWindows()) = 0
    EventQuit = #True
  EndIf
  
  ; Set the successful return value.
  ProcedureReturn #True
  
EndProcedure

Procedure.i ResizeTrackWindow(Window.i)
  
  ; Resize the child gadgets on Window.
  
  Shared ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i X, Y, W, H
  Protected.s ThisKey
  
  ; Obtain the reference structure pointer.
  ThisKey = StrU(Window)
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  ; Resize track bars.
  W = WindowWidth(Window) - 20
  ResizeGadget(*ThisData\TrackBar1, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  ResizeGadget(*ThisData\TrackBar2, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  
  ; Resize string.
  W = WindowWidth(Window) - 110
  ResizeGadget(*ThisData\Difference, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
  
  ProcedureReturn #True
  
EndProcedure

Procedure.i EventsTrackWindow(Window, Gadget, Type)
  
  ; Handle events for a Track window.
  
  Shared Buttons, ActiveWindows()
  Protected *ThisData.TRACKWINDOW
  Protected.i NewValue
  Protected.s ThisKey
  
  ; Convert the integer Window to a string.
  ThisKey = StrU(Window)
  
  ; Obtain the reference structure pointer.
  *ThisData = ActiveWindows(ThisKey)
  
  ; Check that a valid pointer was obtained, if not stop.
  If *ThisData = 0
    ProcedureReturn #False
  EndIf
  
  ; Check that it is the correct window type, if not stop.
  If *ThisData\WindowClass <> #WindowClassTrack
    ProcedureReturn #False
  EndIf
  
  Select Gadget
      
    Case *ThisData\TrackBar1, *ThisData\TrackBar2
      NewValue = GetGadgetState(*ThisData\TrackBar1) - GetGadgetState(*ThisData\TrackBar2)
      SetGadgetText(*ThisData\Difference, Str(NewValue))
      
    Case *ThisData\Label, *ThisData\Difference
      ; Do nothing.
      
  EndSelect
  
EndProcedure

;- Main

; Create the first window.
EventWindow = CreateButtonWindow()
ResizeButtonWindow(EventWindow)

;- Event loop
Repeat
  
  Event = WaitWindowEvent()
  EventWindow = EventWindow()
  EventWindowKey = StrU(EventWindow)
  EventGadget = EventGadget()
  EventType = EventType()
  EventMenu = EventMenu()
  *EventGadgets = ActiveWindows(EventWindowKey)
  
  Select Event
      
    Case #PB_Event_Gadget
      
      ; Check that a valid pointer was obtained.
      If *EventGadgets > 0
        
        ; Use *EventGadgets\WindowClass to despatch events to the correct event procedure.
        Select *EventGadgets\WindowClass
            
          Case #WindowClassButton
            EventsButtonWindow(EventWindow, EventGadget, EventType)
            
          Case #WindowClassDate
            EventsDateWindow(EventWindow, EventGadget, EventType)
            
          Case #WindowClassTrack
            EventsTrackWindow(EventWindow, EventGadget, EventType)
            
          Default
            ; Do nothing
            
        EndSelect
        
      EndIf
      
    Case #PB_Event_Menu
      
      Select EventMenu
          
        Case #mnuNewButton
          EventWindow = CreateButtonWindow()
          If EventWindow > 0
            ResizeButtonWindow(EventWindow)
          EndIf
        
        Case #mnuNewDate
          EventWindow = CreateDateWindow()
          If EventWindow > 0
            ResizeDateWindow(EventWindow)
          EndIf
        
        Case #mnuNewTrack
          EventWindow = CreateTrackWindow()
          If EventWindow > 0
            ResizeTrackWindow(EventWindow)
          EndIf
          
        Case #mnuClose
          
          ; Check that a valid pointer was obtained.
          If *EventGadgets > 0
            
            ; Use *EventGadgets\WindowClass to call the correct destroy window procedure.    
            Select *EventGadgets\WindowClass
                
              Case #WindowClassButton
                DestroyButtonWindow(EventWindow)
                
              Case #WindowClassDate
                DestroyDateWindow(EventWindow)
                
              Case #WindowClassTrack
                DestroyTrackWindow(EventWindow)
                
              Default
                ; Do nothing
                
            EndSelect
            
          EndIf
          
      EndSelect
      
    Case #PB_Event_CloseWindow
      
      ; Check that a valid pointer was obtained.
      If *EventGadgets > 0
        
        ; Use *EventGadgets\WindowClass to call the correct destroy window procedure.
        Select *EventGadgets\WindowClass
            
          Case #WindowClassButton
            DestroyButtonWindow(EventWindow)
            
          Case #WindowClassDate
            DestroyDateWindow(EventWindow)
            
          Case #WindowClassTrack
            DestroyTrackWindow(EventWindow)
            
          Default
            ; Do nothing
            
        EndSelect
        
      EndIf
      
    Case #PB_Event_SizeWindow     
      
      If *EventGadgets > 0
        
        ; Use *EventGadgets\WindowClass to call the correct resize window procedure.
        Select *EventGadgets\WindowClass
            
          Case #WindowClassButton
            ResizeButtonWindow(EventWindow)
            
          Case #WindowClassDate
            ResizeDateWindow(EventWindow)
            
          Case #WindowClassTrack
            ResizeTrackWindow(EventWindow)
            
          Default
            ; Do nothing
            
        EndSelect
        
      EndIf
      
  EndSelect
  
Until EventQuit = #True
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

@spikey: thank you for the update of this code example. :D
The problem with the false Date value is gone, and I didn't notice any "Pointer is null" errors anymore. Unfortunately the IMA at WaitWindowEvent() still occurs, if I have several windows opened (it doesn't matter, which type...) and are closing them by the menu item "Close window". Maybe a MacOS-specific problem (because of it's "one menu bar only") or a PB-bug. I already asked Fred, if he can take a look at your code examples.
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

And here is the slightly reworked code example (some constant/variable names extended to "speaking names", less blank lines to shorten the code). For including in the PB help I've also adapted the description text to reflect the changed names...

I will make a bug-report in the MacOS section, as I don't see any error in the code too. The IMA always occur at the 2nd closed window using the 'Close Window' menu item.

Code: Select all

  ;- Constants
  #DateFormat = "%dd/%mm/%yyyy"
  
  ;- Enumerations
  Enumeration 
    #WindowClassButton = 1
    #WindowClassDate
    #WindowClassTrack
  EndEnumeration
  
  ; The menu commands will be the same on all the windows.
  Enumeration
    #MenuNewButton
    #MenuNewDate
    #MenuNewTrack
    #MenuClose
  EndEnumeration
  
  ;- Structures
  Structure BASEWINDOW
    WindowClass.i 
    Menu.i  
  EndStructure
  
  Structure BUTTONWINDOW Extends BASEWINDOW
    ListView.i
    AddButton.i
    RemoveButton.i  
  EndStructure
  
  Structure DATEWINDOW Extends BASEWINDOW
    Calendar.i
    AddButton.i
    RemoveButton.i
    ListView.i
  EndStructure
  
  Structure TRACKWINDOW Extends BASEWINDOW
    TrackBar1.i
    TrackBar2.i
    Label.i
    Difference.i
  EndStructure
  
  ;- Variables
  ; This map will track all the active windows as before, however as the structure for each window class
  ; differs we will be storing pointers to structures in the map not the gadget references directly.
  NewMap ActiveWindows.i()
  
  ; These values will be used to give new windows a unique label.
  Define.i Buttons, Dates, Tracks
  
  ; Event variables.
  ; Notice the type of *EventGadgets.
  Define.i Event, EventWindow, EventGadget, EventType, EventMenu, EventQuit
  Define.s EventWindowKey
  Define *EventGadgets.BASEWINDOW  
  
  ;- Button Window
  Procedure.i CreateButtonWindow()
    ; Creates a new Button window and adds it to the tracking map, 
    ; allocates memory for gadget references, creates the gadgets 
    ; and stores these references in the memory Structure.
    Shared Buttons, ActiveWindows()
    Protected *ThisData.BUTTONWINDOW
    Protected.i ThisWindow
    Protected.s ThisKey, ThisTitle
    
    ; Set the window caption.
    Buttons + 1
    ThisTitle = "Button Window " + StrU(Buttons)
    
    ; Open the window.
    ThisWindow = OpenWindow(#PB_Any, 30, 30, 225, 300, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
    ; Check that the OpenWindow command worked.
    If ThisWindow
      ; Set minimum window dimensions.
      WindowBounds(ThisWindow, 220, 100, #PB_Ignore, #PB_Ignore)
      
      ; Convert the window reference to a string to use as the map key value.
      ThisKey = StrU(ThisWindow)
      
      ; Allocate memory to store the gadget references in.
      *ThisData = AllocateMemory(SizeOf(BUTTONWINDOW))
    EndIf
    
    ; Check that the memory allocation worked.
    If *ThisData
      ; Store the window reference and memory pointer values in the map.
      ActiveWindows(ThisKey) = *ThisData
      
      ; Set the window class.
      *ThisData\WindowClass = #WindowClassButton
      
      ; Create the menu bar.
      *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
      
      ; If the menu creation worked, create the menu items.
      If *ThisData\Menu
        MenuTitle("Window")
        MenuItem(#MenuNewButton, "New Button Window")
        MenuItem(#MenuNewDate, "New Date Window")
        MenuItem(#MenuNewTrack, "New Track Window")
        MenuItem(#MenuClose, "Close Window")
      EndIf
      
      ; Create the window gadgets.
      *ThisData\ListView = ListViewGadget(#PB_Any, 10, 10, 200, 225)
      *ThisData\AddButton = ButtonGadget(#PB_Any, 15, 245, 90, 30, "Add")
      *ThisData\RemoveButton = ButtonGadget(#PB_Any, 115, 245, 90, 30, "Remove")
    Else
      ; Memory allocation failed.
      CloseWindow(ThisWindow)
    EndIf
    
    ; Set the return value.
    If ThisWindow > 0 And *ThisData > 0
      ; Return the reference to the new window.
      ProcedureReturn ThisWindow
    Else
      ; Return 0
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure.i DestroyButtonWindow(Window.i)
    ; Remove Window from the ActiveWindows map, release the allocated memory,
    ; close the window and set the quit flag, if appropriate.
    Shared EventQuit, ActiveWindows()
    Protected *ThisData.BUTTONWINDOW
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassButton
      ProcedureReturn #False
    EndIf
    
    ; Release the memory allocation.
    FreeMemory(*ThisData)
    
    ; Delete the map entry.
    DeleteMapElement(ActiveWindows(), ThisKey)
    
    ; Close the window.
    CloseWindow(Window)
    
    ; Check if there are still open windows.
    If MapSize(ActiveWindows()) = 0
      EventQuit = #True
    EndIf
    
    ; Set the successful return value.
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i ResizeButtonWindow(Window.i)
    ; Resize the child gadgets on Window.
    Shared ActiveWindows()
    Protected *ThisData.BUTTONWINDOW
    Protected.i X, Y, W, H
    Protected.s ThisKey
    
    ; Obtain the reference structure pointer.
    ThisKey = StrU(Window)
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassButton
      ProcedureReturn #False
    EndIf
    
    ; Resize list view.
    W = WindowWidth(Window) - 25
    H = WindowHeight(Window) - 85
    ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
    
    ; Recentre buttons.
    X = WindowWidth(Window)/2 - 95
    Y = WindowHeight(Window) - 65
    ResizeGadget(*ThisData\AddButton, X, Y, #PB_Ignore, #PB_Ignore)
    
    X = WindowWidth(Window)/2 + 5
    ResizeGadget(*ThisData\RemoveButton, X, Y, #PB_Ignore, #PB_Ignore)
    
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i EventsButtonWindow(Window, Gadget, Type)
    ; Handle events for a button window.
    Shared Buttons, ActiveWindows()
    Protected *ThisData.BUTTONWINDOW
    Protected.i NewValue, Index
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassButton
      ProcedureReturn #False
    EndIf
    
    Select Gadget
      Case *ThisData\AddButton
        NewValue = Random(2147483647)
        AddGadgetItem(*ThisData\ListView, -1, StrU(NewValue))
        
      Case *ThisData\RemoveButton
        Index = GetGadgetState(*ThisData\ListView)
        If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
          RemoveGadgetItem(*ThisData\ListView, Index)
        EndIf
        
      Case *ThisData\ListView
        ; Do nothing.
    EndSelect
  EndProcedure
  
  ;- Date Window
  Procedure.i CreateDateWindow()
    ; Creates a new Date window and adds it to the tracking map, 
    ; allocates memory for gadget references, creates the gadgets 
    ; and stores these references in the memory Structure.
    Shared Dates, ActiveWindows()
    Protected *ThisData.DATEWINDOW
    Protected.i ThisWindow
    Protected.s ThisKey, ThisTitle
    
    Dates + 1
    ThisTitle = "Date Window " + StrU(Dates)
    ThisWindow = OpenWindow(#PB_Any, 30, 30, 310, 420, ThisTitle , #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
    ; Check that the OpenWindow command worked.
    If ThisWindow
      ; Set minimum window dimensions.
      WindowBounds(ThisWindow, 310, 245, #PB_Ignore, #PB_Ignore)
      
      ; Convert the window reference to a string to use as the map key value.
      ThisKey = StrU(ThisWindow)
      
      ; Allocate memory to store the gadget references in.
      *ThisData = AllocateMemory(SizeOf(DATEWINDOW))
    EndIf
    
    ; Check that the memory allocation worked.
    If *ThisData
      ; Store the window reference and memory pointer values in the map.
      ActiveWindows(ThisKey) = *ThisData
      
      ; Set the window class.
      *ThisData\WindowClass = #WindowClassDate
      
      ; Create the menu bar.
      *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
      
      ; If the menu creation worked, create the menu items.
      If *ThisData\Menu
        MenuTitle("Window")
        MenuItem(#MenuNewButton, "New Button Window")
        MenuItem(#MenuNewDate, "New Date Window")
        MenuItem(#MenuNewTrack, "New Track Window")
        MenuItem(#MenuClose, "Close Window")
      EndIf
      
      ; Create the window gadgets.
      *ThisData\Calendar = CalendarGadget(#PB_Any, 10, 10, 182, 162)
      *ThisData\AddButton = ButtonGadget(#PB_Any, 210, 10, 90, 30, "Add")
      *ThisData\RemoveButton = ButtonGadget(#PB_Any, 210, 45, 90, 30, "Remove")
      *ThisData\ListView = ListViewGadget(#PB_Any, 10, 187, 290, 200)
    Else
      ; Memory allocation failed.
      CloseWindow(ThisWindow)
    EndIf
    
    ; Set the return value.
    If ThisWindow > 0 And *ThisData > 0 
      ; Return the reference to the new window.
      ProcedureReturn ThisWindow
    Else
      ; Return 0
      ProcedureReturn 0
    EndIf
    
  EndProcedure
  
  Procedure.i DestroyDateWindow(Window.i)
    ; Remove Window from the ActiveWindows map, release the allocated memory,
    ; close the window and set the quit flag, if appropriate.
    Shared EventQuit, ActiveWindows()
    Protected *ThisData.DATEWINDOW
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
    If *ThisData\WindowClass <> #WindowClassDate
      ProcedureReturn #False
    EndIf
    
    ; Release the memory allocation.
    FreeMemory(*ThisData)
    
    ; Delete the map entry.
    DeleteMapElement(ActiveWindows(), ThisKey)
    
    ; Close the window.
    CloseWindow(Window)
    
    ; Check if there are still open windows.
    If MapSize(ActiveWindows()) = 0
      EventQuit = #True
    EndIf
    
    ; Set the successful return value.
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i ResizeDateWindow(Window.i)
    ; Resize the child gadgets on Window.
    Shared ActiveWindows()
    Protected *ThisData.DATEWINDOW
    Protected.i X, Y, W, H
    Protected.s ThisKey
    
    ; Obtain the reference structure pointer.
    ThisKey = StrU(Window)
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassDate
      ProcedureReturn #False
    EndIf
    
    ; Resize list view.
    W = WindowWidth(Window) - 20
    H = WindowHeight(Window) - 220
    ResizeGadget(*ThisData\ListView, #PB_Ignore, #PB_Ignore, W, H)
    
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i EventsDateWindow(Window, Gadget, Type)
    ; Handle events for a Date window.
    Shared Buttons, ActiveWindows()
    Protected *ThisData.DATEWINDOW
    Protected.i NewValue, Index
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassDate
      ProcedureReturn #False
    EndIf
    
    Select Gadget
      Case *ThisData\AddButton
        NewValue = GetGadgetState(*ThisData\Calendar)
        AddGadgetItem(*ThisData\ListView, -1, FormatDate(#DateFormat, NewValue))
        
      Case *ThisData\RemoveButton
        Index = GetGadgetState(*ThisData\ListView)
        If Index >= 0 And Index <= CountGadgetItems(*ThisData\ListView)
          RemoveGadgetItem(*ThisData\ListView, Index)
        EndIf
        
      Case *ThisData\Calendar, *ThisData\ListView
        ; Do nothing.
    EndSelect
  EndProcedure
  
  ;- Track Window
  Procedure.i CreateTrackWindow()
    ; Creates a new Track window and adds it to the tracking map, 
    ; allocates memory for gadget references, creates the gadgets 
    ; and stores these references in the memory Structure.
    Shared Tracks, ActiveWindows()
    Protected *ThisData.TRACKWINDOW
    Protected.i ThisWindow, ThisSum
    Protected.s ThisKey, ThisTitle
    
    Tracks + 1
    ThisTitle = "Track Bar Window " + StrU(Tracks)
    ThisWindow = OpenWindow(#PB_Any, 30, 30, 398, 130, ThisTitle, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
    ; Check that the OpenWindow command worked.
    If ThisWindow
      ; Set minimum window dimensions.
      WindowBounds(ThisWindow, 135, 130, #PB_Ignore, 130)
      
      ; Convert the window reference to a string to use as the map key value.
      ThisKey = StrU(ThisWindow)
      
      ; Allocate memory to store the gadget references in.
      *ThisData = AllocateMemory(SizeOf(TRACKWINDOW))
    EndIf
    
    ; Check that the memory allocation worked.
    If *ThisData
      ; Store the window reference and memory pointer values in the map.
      ActiveWindows(ThisKey) = *ThisData
      
      ; Set the window class.
      *ThisData\WindowClass = #WindowClassTrack
      
      ; Create the menu bar.
      *ThisData\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow))
      
      ; If the menu creation worked, create the menu items.
      If *ThisData\Menu
        MenuTitle("Window")
        MenuItem(#MenuNewButton, "New Button Window")
        MenuItem(#MenuNewDate, "New Date Window")
        MenuItem(#MenuNewTrack, "New Track Window")
        MenuItem(#MenuClose, "Close Window")
      EndIf
      
      ; Create the window gadgets.
      *ThisData\TrackBar1 = TrackBarGadget(#PB_Any, 10, 10, 375, 25, 0, 100, #PB_TrackBar_Ticks)
      *ThisData\TrackBar2 = TrackBarGadget(#PB_Any, 10, 40, 375, 25, 0, 100, #PB_TrackBar_Ticks)
      *ThisData\Label = TextGadget(#PB_Any, 10, 75, 80, 25, "Difference:")
      *ThisData\Difference = StringGadget(#PB_Any, 90, 75, 290, 25, "0", #PB_String_ReadOnly)
    Else
      ; Memory allocation failed.
      CloseWindow(ThisWindow)
    EndIf
    
    ; Set the return value.
    If ThisWindow > 0 And *ThisData > 0
      ; Return the reference to the new window.
      ProcedureReturn ThisWindow
    Else
      ; Return 0
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure.i DestroyTrackWindow(Window.i)
    ; Remove Window from the ActiveWindows map, release the allocated memory,
    ; close the window and set the quit flag, if appropriate.
    Shared EventQuit, ActiveWindows()
    Protected *ThisData.DATEWINDOW
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop as this procedure can't destroy this window.
    If *ThisData\WindowClass <> #WindowClassTrack
      ProcedureReturn #False
    EndIf
    
    ; Release the memory allocation.
    FreeMemory(*ThisData)
    
    ; Delete the map entry.
    DeleteMapElement(ActiveWindows(), ThisKey)
    
    ; Close the window.
    CloseWindow(Window)
    
    ; Check if there are still open windows.
    If MapSize(ActiveWindows()) = 0
      EventQuit = #True
    EndIf
    
    ; Set the successful return value.
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i ResizeTrackWindow(Window.i)
    ; Resize the child gadgets on Window.
    Shared ActiveWindows()
    Protected *ThisData.TRACKWINDOW
    Protected.i X, Y, W, H
    Protected.s ThisKey
    
    ; Obtain the reference structure pointer.
    ThisKey = StrU(Window)
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassTrack
      ProcedureReturn #False
    EndIf
    
    ; Resize track bars.
    W = WindowWidth(Window) - 20
    ResizeGadget(*ThisData\TrackBar1, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
    ResizeGadget(*ThisData\TrackBar2, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
    
    ; Resize string.
    W = WindowWidth(Window) - 110
    ResizeGadget(*ThisData\Difference, #PB_Ignore, #PB_Ignore, W, #PB_Ignore)
    
    ProcedureReturn #True
  EndProcedure
  
  Procedure.i EventsTrackWindow(Window, Gadget, Type)
    ; Handle events for a Track window.
    Shared Buttons, ActiveWindows()
    Protected *ThisData.TRACKWINDOW
    Protected.i NewValue
    Protected.s ThisKey
    
    ; Convert the integer Window to a string.
    ThisKey = StrU(Window)
    
    ; Obtain the reference structure pointer.
    *ThisData = ActiveWindows(ThisKey)
    
    ; Check that a valid pointer was obtained, if not stop.
    If *ThisData = 0
      ProcedureReturn #False
    EndIf
    
    ; Check that it is the correct window type, if not stop.
    If *ThisData\WindowClass <> #WindowClassTrack
      ProcedureReturn #False
    EndIf
    
    Select Gadget
      Case *ThisData\TrackBar1, *ThisData\TrackBar2
        NewValue = GetGadgetState(*ThisData\TrackBar1) - GetGadgetState(*ThisData\TrackBar2)
        SetGadgetText(*ThisData\Difference, Str(NewValue))
        
      Case *ThisData\Label, *ThisData\Difference
        ; Do nothing.
    EndSelect
  EndProcedure
  
  ;- Main
  
  ; Create the first window.
  EventWindow = CreateButtonWindow()
  ResizeButtonWindow(EventWindow)
  
  ;- Event loop
  Repeat
    Event = WaitWindowEvent()
    EventWindow = EventWindow()
    EventWindowKey = StrU(EventWindow)
    EventGadget = EventGadget()
    EventType = EventType()
    EventMenu = EventMenu()
    *EventGadgets = ActiveWindows(EventWindowKey)
    
    Select Event
      Case #PB_Event_Gadget
        ; Check that a valid pointer was obtained.
        If *EventGadgets > 0
          ; Use *EventGadgets\WindowClass to despatch events to the correct event procedure.
          Select *EventGadgets\WindowClass
            Case #WindowClassButton
              EventsButtonWindow(EventWindow, EventGadget, EventType)
              
            Case #WindowClassDate
              EventsDateWindow(EventWindow, EventGadget, EventType)
              
            Case #WindowClassTrack
              EventsTrackWindow(EventWindow, EventGadget, EventType)
              
            Default
              ; Do nothing
          EndSelect
        EndIf
        
      Case #PB_Event_Menu
        Select EventMenu
          Case #MenuNewButton
            EventWindow = CreateButtonWindow()
            If EventWindow > 0
              ResizeButtonWindow(EventWindow)
            EndIf
            
          Case #MenuNewDate
            EventWindow = CreateDateWindow()
            If EventWindow > 0
              ResizeDateWindow(EventWindow)
            EndIf
            
          Case #MenuNewTrack
            EventWindow = CreateTrackWindow()
            If EventWindow > 0
              ResizeTrackWindow(EventWindow)
            EndIf
            
          Case #MenuClose
            ; Check that a valid pointer was obtained.
            If *EventGadgets > 0
              ; Use *EventGadgets\WindowClass to call the correct destroy window procedure.    
              Select *EventGadgets\WindowClass
                Case #WindowClassButton
                  DestroyButtonWindow(EventWindow)
                  
                Case #WindowClassDate
                  DestroyDateWindow(EventWindow)
                  
                Case #WindowClassTrack
                  DestroyTrackWindow(EventWindow)
                  
                Default
                  ; Do nothing
              EndSelect
            EndIf
        EndSelect
        
      Case #PB_Event_CloseWindow
        ; Check that a valid pointer was obtained.
        If *EventGadgets > 0
          ; Use *EventGadgets\WindowClass to call the correct destroy window procedure.
          Select *EventGadgets\WindowClass
            Case #WindowClassButton
              DestroyButtonWindow(EventWindow)
              
            Case #WindowClassDate
              DestroyDateWindow(EventWindow)
              
            Case #WindowClassTrack
              DestroyTrackWindow(EventWindow)
              
            Default
              ; Do nothing
          EndSelect
        EndIf
        
      Case #PB_Event_SizeWindow     
        If *EventGadgets > 0
          ; Use *EventGadgets\WindowClass to call the correct resize window procedure.
          Select *EventGadgets\WindowClass
            Case #WindowClassButton
              ResizeButtonWindow(EventWindow)
              
            Case #WindowClassDate
              ResizeDateWindow(EventWindow)
              
            Case #WindowClassTrack
              ResizeTrackWindow(EventWindow)
              
            Default
              ; Do nothing
          EndSelect
        EndIf
        
    EndSelect
    
  Until EventQuit = #True
  
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

Looking at several questions on the PB forums I got a new idea for this chapter:
For newbies it would be good to have a proper description and example how to deal with several procedure return values (e.g. using a pointer to a structured variable), because sooner or later they will come with this question...

Any ideas? Thanks in advance! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
USCode
Addict
Addict
Posts: 912
Joined: Wed Mar 24, 2004 11:04 pm
Location: Seattle, USA

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by USCode »

Andre wrote:Looking at several questions on the PB forums I got a new idea for this chapter:
For newbies it would be good to have a proper description and example how to deal with several procedure return values (e.g. using a pointer to a structured variable), because sooner or later they will come with this question...
Have you guys seen Go's syntax for multiple return values? http://tour.golang.org/#9
Given the current syntax, I don't think this would be do-able with PB though.

Code: Select all

package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Ludo »

@Andre - feel free to use if of any use.
http://www.purebasic.fr/english/viewtop ... =7&t=61599

Ludo
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Vera »

Hello André and all doc-supporters :-)

I have opened a thread on the french forum asking to tune in and help making this a 3 languaged guide:
° PureBasic "UserGuide" ~ édition française

Everyone from this forum who would like to help too, but is no member on the french forum. Please let me know on here which chapter you'd like to translate and I would add you to the list [yet to be started] on the french thread showing which chapters are in progress / finished / free to choose for translation.

Thank you ~ Vera
Post Reply