[Making] User pointers for better control of objects

General discussion on Visual TFT Software.
Author
Message
Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

[Making] User pointers for better control of objects

#1 Post by Megahurts » 06 Jul 2014 13:22

Hi All of you V-T.U.s,*
*{Visual-TFT Users}

How are you all doing this fine day? Good I hope, and wishing you all have a great weekend holiday and come back safely.

I'll be taking a trip next weekend to a family reunion event, so today is a good day to share something with you all.
Sorry, but it is only a Puzzle/Problem, and one that if solved, has great potential for making our projects Rock and Roll.

This may not be what you might expect sorry, but I hope you all find it interesting and hopefully inspiration will strike you like a lightning bolt,
but without the smoke and sparks and smell, OK? ;^)
(Never good getting any of those indicators)

The puzzle/problem is with those darn variable pointers and proper usage.
In this case, the proper usage is dictated by utilizing a scheme that a user can easily implement with V-TFT objects properties and
not break or corrupt the data structure that is being used by the V-TFT object drawing/handling routines.
(not so easy to do, I've tried and had no luck so far, but I don't possess the knowledge and experience with pointers some of you have.)

I am trying to set up some pointers for some V-TFT objects properties and having no luck getting it to work correctly yet or not cause compiler build errors.
The concept is to change a few object properties/structures data holders so they can be set as a group to use the same
data of a single variable, instead of each property in the objects data structure having its own variable to hold a property's setting.

If this is possible, we can have many objects AND many of their properties tied together as a group and all be subject
to the data value of a single variable. This will reduce code size a lot and provide easier, simpler control over many objects
that we can not do at present. (much of the code that would be reduced/eliminated will be the user code needed to assign different
data values to the properties on a one by one basis as is done now, see the example code of this below that shows potential diferences.)

I hope someone can 'point' me (/Us) in the right direction please? :lol:

Results wanted (trying to do) for this pointer usage:
I have on the bottom of a TFT screen a set of 5 menu buttons (spaced side by side along bottom edge), that can be replaced by another one of
3 other sets* of buttons of same size and position for 4 sets* total. *(also called a 'group' : of some same characteristic(s) or traits)
Another screen button cycles the sets when pressed. See image below for example of menu sets displayed and button to cycle them.(highlighted with red boxes)
cnc stepper menus.jpg
cnc stepper menus.jpg (222.68 KiB) Viewed 11845 times
The sets of buttons are stacked directly atop of the first set and each Menu set on a different Layer in V-TFT, but only the first set has their
'Visibility', 'Active' and 'Press Color Enabled' properties set to 'True'(1), the other 3 Menu sets
same properties are set to 'False'(0), so not visible and won't react to a press on the screen at their locations.

When the button that cycles the menu sets is pressed (clicked), its event handler routine updates a tracking variables
value for which set is active (0,1,2,3).

Then that tracking variable is subjected to a 'select case' operation to use which case = True(1) code that will change 4 different flag variables data values so new active set flag = True (1) and the last menu sets flag variable = False (0).
These flag variables declarations are User Code and I placed them in the Udriver module - near top of file: (one for each button set)

Code: Select all

' User Code Object Group Control Flag Variables. 
dim MENU1_ENABLED as ^byte   ' pointee variable to have group-1 objects controlled properties use
    MENU2_ENABLED as ^byte   ' pointee variable to have group-2 objects controlled properties use
    MENU3_ENABLED as ^byte   ' pointee variable to have group-3 objects controlled properties use
    MENU4_ENABLED as ^byte   ' pointee variable to have group-4 objects controlled properties use
One of the variables will always be a 1 value (True) and the other three (3) variables a 0 value (False).
The now active set of buttons are then redrawn over the last set and ready to be pressed for their function/action the user programmed for them.
(I do not know if or think the right declaration(s) practice is being done to establish a "Pointee"* for the pointers,
or if a new type definition of a pointer for these variables is required in order for the objects properties/parameters to still
be accepted/usable by the V-TFT core code?) *{Pointee – the variable or memory location a pointer points to.}

The affected 'Elements' to correctly modify/manage by doing this (? I'm not sure if all or some or missing are right/needed/listed):

For an example to help show what I am trying to do, I'll list just the minimum amount of code from the project for the objects necessary.

First though, I am making these changes to the code V-TFT generates in a projects 'driver' and 'objects' files that are copies of the originals
and renamed (ie..~xxx_driver.xxxx -> ~xxx_Udriver.xxxx), and originals have all code commented out (for testing before removing from the projects files list).

The remaining V-TFT project files have their 'Includes' edited to use the copied files I am modifying.
(this is also a test of best way to enhance users control of V-TFT objects and preserve the user edited V-TFT code it will overwrite if edited in V-TFT again)

The Menu Buttons used in the sets are dynamic-memory-allocated same type square Buttons.
Here is code listing of the Button objects structure declarations from the projects 'Uobjects' file/module.
There has been 5 common property elements data types changed by me to a pointer type of original data type.
They are shown marked with a comment at right of structure element/member declaration.
3 members (object properties) are used in a group of same function of flag logic needs to be used/set identical by all menu buttons in a group:
Visibility, Active and ColorOnPress_enabled - are all set 0 or 1 at all times for the usage
characteristic I intend to use here. (these 3 properties are the necessary ones to control an object being visible and active to TP activity over them)

Other 2 members, Transparency and Gradient_Enabled are used by only some of the buttons in the menu sets.

Code: Select all

structure TButton
  dim OwnerScreenID        as word
  dim Order                as byte
  dim Left_                as word
  dim Top                  as word
  dim Width                as word
  dim Height               as word
  dim Pen_Width            as byte
  dim Pen_Color            as word
  dim Visible              as ^byte      ' modified by me: added pointer carat to type declared (Used by button set management code)
  dim Active               as ^byte      ' modified by me: added pointer carat to type declared (Used by button set management code)
  dim Transparent          as ^byte      ' modified by me: added pointer carat to type declared (not used by button set management code)
  dim Caption              as ^char
  dim TextAlign            as byte
  dim Fontname             as ^ const far byte
  dim Font_Color           as word
  dim Gradient             as ^byte      ' modified by me: added pointer carat to type declared (not used by button set management code)
  dim Gradient_Orientation as byte
  dim Gradient_Start_Color as word
  dim Gradient_End_Color   as word
  dim Color                as word
  dim PressColEnabled      as ^byte      ' modified by me: added pointer carat to type declared (Used by button set management code)
  dim Press_Color          as word
  dim OnUpPtr              as ^TOnEventPtr
  dim OnDownPtr            as ^TOnEventPtr
  dim OnClickPtr           as ^TOnEventPtr
  dim OnPressPtr           as ^TOnEventPtr
end structure
The elements marked as used by menu mgr., all need to have their values set to same value (either 0 or 1) in order to have
the grouped set be Disabled (not visible, no TP events triggered) or Enabled (visible,active to touch) correctly,
then current active/Enabled set redrawn on screen.
(I'm pretty sure that the modifications to data members is not the right way it needs to be done....HELP!)
The object elements (properties) unused by menu mgr. function are to be individually manipulated by each buttons event handler routine, if those properties are used at all.
Only a few buttons in menu sets will use those properties for changing button appearance to indicate assigned functions current state.

The problem(s) I have with this part of trying to set this up:
1. This modification of an elements type declaration here will now be applied to ALL Button Objects used in the project.
I'm not sure we would want that and doing what I did has caused conflict in the V-TFT core driver code for those objects.
2971 373 Pointers can be compared to compatible pointers or zero value PIC33EP_CNC_Stepper_Udriver.mbas
(I am not sure what I changed is actual problem, but how the code syntax/pointer-usage in other modules is done or the wrong pointer method/way for this data sharing structure modification or the (full) pointer implementation structure not fully established yet ?)
Looking for the best/simpler/better implementation solution possible.

So, to control all wanted properties by having those properties 'grouped' (for controlling multiple object properties with 1 variable, instead of setting multiple values one by one) together in each object to use same value in another variable (or memory location) and all 5 buttons of a set (grouped again by set, so = 15 properties {3x5} pointing to same 'pointee') all use that same 'pointee' value, and each set has its own 'pointee' that controls all buttons in the set,
Is this change to the objects type structure required?

2. I think this now requires modifying the objects elements assignment code in "InitializeObjects()" routine in 'driver' module also (or not?), but I don't know if every object of same button type used in project now also requires changes to its affected property elements in the initialization routine and every instance that a modified properties
data element is to be assigned a data value.

3. I really need a proper example (please) of how to point a few of an objects property structured data members to the same defined data value holder, and example of setting up that value holder (properly as a 'pointee') and accessing it for read/write (directly(?) by user code to modify value, and object(s) properties seeing value properly with V-TFT core driver code being able to use the value assigned (where stored?).

Here is example of a menu button entry and assignments from the "InitializeObjects()" routine in modified "Udriver" module:

Code: Select all

  Scrn1Btn_Menu1_DRILL_.OwnerScreenID       = 32768
  Scrn1Btn_Menu1_DRILL_.Order               = 1
  Scrn1Btn_Menu1_DRILL_.Left_               = 214
  Scrn1Btn_Menu1_DRILL_.Top                 = 222
  Scrn1Btn_Menu1_DRILL_.Width               = 51
  Scrn1Btn_Menu1_DRILL_.Height              = 17
  Scrn1Btn_Menu1_DRILL_.Pen_Width           = 1
  Scrn1Btn_Menu1_DRILL_.Pen_Color           = 0xFFFF
  Scrn1Btn_Menu1_DRILL_^.Visible            = MENU1_ENABLED      ' modified by me: added pointer carat to type declared (used by button set management code)
  Scrn1Btn_Menu1_DRILL_^.Active             = MENU1_ENABLED      ' modified by me: added pointer carat to type declared (used by button set management code)
  Scrn1Btn_Menu1_DRILL_^.Transparent        = 1      ' modified by me: added pointer carat to type declared (not used by button set management code or know if needed to be done in any case?)
  Scrn1Btn_Menu1_DRILL_.Caption             = @Scrn1Btn_Menu1_DRILL__Caption
  Scrn1Btn_Menu1_DRILL__Caption             = "DRILL"
  Scrn1Btn_Menu1_DRILL_.TextAlign           = _taCenter
  Scrn1Btn_Menu1_DRILL_.FontName            = @Tahoma13x13_Bold
  Scrn1Btn_Menu1_DRILL_^.PressColEnabled    = MENU1_ENABLED      ' modified by me: added pointer carat to type declared (used by button set management code)
  Scrn1Btn_Menu1_DRILL_.Font_Color          = 0xFFFF
  Scrn1Btn_Menu1_DRILL_^.Gradient           = 1      ' modified by me: added pointer carat to type declared (used by buttons event handler code)
  Scrn1Btn_Menu1_DRILL_.Gradient_Orientation = 0
  Scrn1Btn_Menu1_DRILL_.Gradient_Start_Color = 0x8410
  Scrn1Btn_Menu1_DRILL_.Gradient_End_Color  = 0x39E7
  Scrn1Btn_Menu1_DRILL_.Color               = 0xF800
  Scrn1Btn_Menu1_DRILL_.Press_Color         = 0xC618
  Scrn1Btn_Menu1_DRILL_.OnUpPtr             = 0
  Scrn1Btn_Menu1_DRILL_.OnDownPtr           = 0
  Scrn1Btn_Menu1_DRILL_.OnClickPtr          = @Scrn1Btn_Menu1_DRILL_OnClick
  Scrn1Btn_Menu1_DRILL_.OnPressPtr          = 0
These modifications did not work, caused compiler error(s). Maybe the "@" operator should have been used? And how?

With my rudimentary skills on pointers and no examples in compiler documentation on using pointers in structures like the ones
V-TFT objects are made as, I am unable to get a working configuration solution.

I think this is a possible method to implement and it can reduce the size of users code required to manipulate multiple objects
properties by a large factor (the more objects in a group, the more code space saved by # of properties in a object grouped x # of objects in a group together).

The way I am trying to do this can also be applied to objects that a user has set up to be pop-up input dialogs or messages
that are to be used on a single screen (pop-up windows on a screen would now be very easy to implement),
making the control and management of them much easier and efficient with smaller code footprint needed.

aCkO has already shown us (in his tutorial for reusing objects on different screens), that the current screen-object structure uses
more memory than required because of the structures V-TFT is programmed to create and I have hopes this method can save us even more if put to use. (imagine if both of these were to be implemented in V-TFT :shock: )

The current method of coding requirements to change the set of menu buttons in my project is shown in this code listing below. I will show one (1) Menu sets minimum required properties changing code entries for an object of that set and one objects properties
of the last Menu group, so multiply these code lines by the number of buttons and Menu sets to get idea of the amount of
code needed to implement this simple set swapping technique as we have to do it now.

Code: Select all

'---------- Start of Screen1 Menu Navigation Button handling
sub procedure Scrn1Btn_MenuCHANGE_OnClick()
' changes Active, Visible, Press color properties of 4 menu button sets (5 buttons each)

 if (MENU_PAGE = 3) then  ' cycle to next menu or roll over to first menu
    MENU_PAGE = 0
   else
    inc(MENU_PAGE)
 end if
 
 select case MENU_PAGE    ' change properties and redraw current active set
   case 0                 ' Menu 1 set active
     Scrn1Btn_Menu1_DRILL_.Visible         = 1 ' 3 property entries for a button to be made active
     Scrn1Btn_Menu1_DRILL_.Active          = 1
     Scrn1Btn_Menu1_DRILL_.PressColEnabled = 1
   ' 4 more required for the set of buttons to make the set active
   '
   '
   '
   '
     Scrn1Btn_Menu4_SETUP_.Visible         = 0 ' 3 property entries for a button to be made inactive
     Scrn1Btn_Menu4_SETUP_.Active          = 0
     Scrn1Btn_Menu4_SETUP_.PressColEnabled = 0
   ' and 4 more required for the set of buttons to make the set inactive
   '
   '
   '
   '
    ' 5 drawbutton routine calls to draw set 1 on display so they are visible now

   case 1                 ' Menu 2 set active
   ' and now repeat the same amount of code here to switch menu set 2 to active and menu set 1 to inactive
   '
   '
   '
   '
   '
   '
   '...
   
   case 2                 ' Menu 3 set active
   ' and now repeat the same amount of code here to switch menu set 3 to active and menu set 2 to inactive
   '
   '
   '
   '
   '
   '
   '...   
   
   case 3                 ' Menu 4 set active
   ' and now repeat the same amount of code here to switch menu set 4 to active and menu set 3 to inactive
   '
   '
   '
   '
   '
   '
   '...   
   

 end select
end sub
'---------- End of Screen1 Menu Navigation Button handling
And now here would be the exact entire coding required to do the same thing if objects and properties could be tied or grouped as I have expressed.

Code: Select all

'---------- Start of Screen1 Menu Navigation Button handling
sub procedure Scrn1Btn_MenuCHANGE_OnClick()
' changes Active, Visible, Press color properties of 4 menu button sets (5 buttons each)

 if (MENU_PAGE = 3) then  ' cycle to next menu or roll over to first menu
    MENU_PAGE = 0
   else
    inc(MENU_PAGE)
 end if
 
 select case MENU_PAGE    ' change properties and redraw current active set
   case 0                 ' Menu 1 set active
     MENU1_ENABLED^ = 1   ' enables all 5 buttons in the set
     MENU4_ENABLED^ = 0   ' disables all 5 buttons in the set
     
    ' 5 drawbutton routine calls to draw Menu set 1 buttons on display so they are visible and usable now

   case 1                 ' Menu 2 set active
     MENU2_ENABLED^ = 1
     MENU1_ENABLED^ = 0
     
    ' 5 drawbutton routine calls to draw Menu set 2 buttons on display so they are visible and usable now  
   
   case 2                 ' Menu 3 set active
     MENU3_ENABLED^ = 1
     MENU2_ENABLED^ = 0
     
    ' 5 drawbutton routine calls to draw Menu set 3 buttons on display so they are visible and usable now
   
   case 3                 ' Menu 4 set active
     MENU4_ENABLED^ = 1
     MENU3_ENABLED^ = 0
     
    ' 5 drawbutton routine calls to draw Menu set 4 buttons on display so they are visible and usable now   

 end select
end sub
'---------- End of Screen1 Menu Navigation Button handling
That is a big difference between code requirements I think you will agree on yes?
The program execution time for this routine will be significantly lower also, and that is usually a very good thing too.

So, YES, this is also a V-TFT Wish list change request: Add controls to V-TFT to allow users to group an objects selected properties
*(of same data type value controlled) together (point to a single variable) and group selected objects so the output code has “User Code” control over the pointers structure and referencing allowing changes to suit users needs/design requirements.
(I may not have phrased that (or anything about pointers in the posting) correctly in regards to correct pointer terminology
sorry, as I have stated – NOT an expert or skilled with their usage at all, if any of the above did not make any sense to
anyone, please ask and I will try to provide better explanation(s) to clarify it.)

If what I do understand about pointer-usages is correct, this is entirely possible within the compilers, but I make no claims
that it can be done with current V-TFT object data structures and related object handling code as it exists now.
An expert in this area needs to consider and explore this concept, and hopefully provide an affirmative reply (or let it be known
that it can not be done with these data structures, currently?).

My fear for this idea to easily be implemented currently by users editing an objects properties structure(s), is that the current
object data structure after modification will not allow the object(s) to be processed correctly or at all by the current V-TFT
core routines, without doing modifications to every V-TFT routines code entry for that object types properties affected.

The one thing I do not want done is to create a system that requires even more code to implement the feature, or require the user to edit hundreds of routine entries that use the modified structures data element(s).

But I do think that if V-TFT were to be changed so users could optionally tie any of an objects same-type properties to a single state holder variable and set up multiple instances of properties that are tied to a single holder variable (different variable for each set of tied properties, user supplies the identifier name, V-TFT puts it properly declared in generated code)
and be able to assign this configuration to as many objects (with the same properties shared) as user desires,
it would be a very powerful and versatile upgrade to the things possible with using V-TFT.

Many, many things could be made possible for users to take advantage of if this were implemented in V-TFT.
I'm sure there are more than I have thought of so far, but at a minimum, what it can provide to us users is greatly desirable for better, easier control of many objects and with reduced code footprint needed.

I may not be online until next week sometime, so please consider this concept and post any questions, suggestions or remarks or usable solution code examples you have so we can expand the capabilities possible with our treasures of HW and SW tools.

As my knowledge and skills with proper pointer usage has proven to be extremely dangerous to a working V-TFT programs life, I will not be doing any more experiments with the code until I receive some guidance as to proper usage methods needed for these object structures.

Regards all, peace-out, Robert.
Last edited by Megahurts on 29 Jul 2014 04:47, edited 1 time in total.
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: [?]Using pointers for object properties for better contr

#2 Post by aCkO » 06 Jul 2014 20:52

Hi Robert,

While this approach might look promising at first sight, it would inevitably create more problems than it would solve. I will first try to point out the downsides and then suggest possible solution(s).

From OOP perspective, your analysis violates the concept of encapsulation because you are using the property outside of object definition. This will have negative impact on the code structure and readability. However, much bigger problem (as you already noticed) is the fact that the object definition itself will change and that would require major rewrite of the driver. If you want to use VTFT comfortably, I wouldn't recommend going that path.

The interesting subject in your post that can lead you to a much better solution, is the grouping of objects. While VTFT doesn't have container objects like its big PC brothers (VB, Delphi and others), they can easily be emulated in code. In fact, the approach that can be used effectively for that purpose is the same one I suggested in my tutorial about reusable objects. The great thing about grouping is that it doesn't require changes to the driver file.

For example, let's say we want to manipulate 5 buttons simultaneously. The easiest way to do this is to declare an array of pointers to them:

Code: Select all

const Group1 as TButtonPtr[5] = (@Button1, @Button2, @Button3, @Button4, @Button5)
In this case pointers act like "handles" to button objects and by using them in an array we have the benefit of accessing pointed objects iteratively, i.e. we can use loops for setting object properties instead of doing that individually object-by-object (the unfolded way). Not only we will save some ROM, but our fingers will be grateful to us for typing much less code :)

Here's how we can change the Visible property of all the members in the above group:

Code: Select all

sub procedure ShowGroup(dim byref p as TButtonPtr[5], dim IsVisible as byte)
   dim i as byte
   
   for i = 0 to 4
      p[i]^.Visible = IsVisible
   next i

end sub
Usage:

Code: Select all

ShowGroup(Group1, 1)   ' Show buttons
ShowGroup(Group1, 0)   ' Hide buttons
However, in your particular case where you have multiple sets/groups of buttons on a single screen, I would use just one set (5 buttons) and a state machine for changing captions, colors and other properties. State flag should be the currently active menu and click events should test the state flag in select/case block and perform actions accordingly. You will have only 5 event handlers and only 5 objects in RAM, i.e. you will save (5 * (N - 1) * sizeof(TButton)) bytes of RAM, where N is the total number of groups/sets you are currently using.

Regards

Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Making better state control of buttons w/pointers

#3 Post by Megahurts » 11 Jul 2014 11:32

Thanks Aleksandar,

Not the answer I was hoping for, but it was expected. I was just wishing I was missing something that would have made it possible.

The state machine method was the original and back up method if this didn't work out. But I decided to try a little different approach
than the way you described. (and so far it compiles OK, so is promising to be a method worth trying/using for state control of multiple function buttons)

I did use your 'grouping' of the buttons as another pointer/handle with indexing, as follows:

Code: Select all

const MENU_BTNS    as TButtonPtr[5] =
 (@Scrn1Btn_MenuButton1_, @Scrn1Btn_MenuButton2_, @Scrn1Btn_MenuButton3_,
  @Scrn1Btn_MenuButton4_, @Scrn1Btn_MenuButton5_)
And a Constant multidimensional 6 character string array for the Menu Sets Button function Labels:

Code: Select all

' Constants for screen1 Menu sets names of function buttons at bottom of screen
const MENU_SET_TXT as Str6[4][5] = (
     ("SMODE","SHAPE","ALOCK","HOME","DRILL"),    ' Menu Set 1 - index 0 :0,1,2,3,4
     ("LIMITS","OFFSET","MEASUR","",""),          ' Menu Set 2 - index 1 :0,1,2
     ("EDIT","PREV","PLAY","NEXT","RECORD"),      ' Menu Set 3 - index 2 :0,1,2,3,4
     ("SETUP","SHUTDN","TOOL","SAVREC","LOAD"))   ' Menu Set 4 - index 3 :0,1,2,3,4
yes, set 2 is a little different from the others, it has only the 3 leftmost buttons as normal, but where buttons 4 & 5 would be,
there is a single wide button displaying the results from the 3 functions this set does have, which require displaying of distances
between two or more points on any axis selected. This different set layout is managed by the Menu Set selection Button Handler routine.
It is also where I took a different state machine method tactic I have been thinking on since I made the Tutorial Manual;

Instead of having a routine the buttons all call when clicked, (a button state conditional testing manager routine), that then
determines the function the button is representing by the Menu's State currently and calling another routine to do the function tasks or the function task code is part of this state conditional manager routine (making it a large critical functioning state manager routine also!),-

I have this change Menu Button's handler routine do some Button properties changes to show next Menu functions AND
change the Menu Buttons onevent pointer to the routine that handles the function assigned to the current Menu Set Button's.
This saves the need for programming a complex state testing routine and removes the need for another 1 or more calls to be pushed
on to the MCU stack, before any more the function(s) may need to use of the stack also.
Above the routine for change menu button handling, there is a "user code" routine that is made for doing a common task on the Menu Buttons - redraws all 5 buttons after covering them with a solid black box to erase them totally from the screen.
Here is its code and the different routines to handle the different functions in the Menu:

Code: Select all

'_____________________________________________________
' routine to redraw the 5 screen1 function menu buttons after set change
sub procedure DrawMenu()
dim BP as byte
  DrawCBox(@Scrn1Box_BackFILLMenu)   ' totaly erase menu buttons from display
'  for BP = 0 to 4
'    DrawButton(MENU_BTNS[BP])   ' redraw Menu Buttons with current properties settings. ? Is pointer correct dereferencing
'  next BP
' Or this code does it also:
  DrawButton(@Scrn1Btn_MenuButton1_) ' redraw Menu Button 1 with current properties settings
  DrawButton(@Scrn1Btn_MenuButton2_) ' redraw Menu Button 2 with current properties settings
  DrawButton(@Scrn1Btn_MenuButton3_) ' redraw Menu Button 3 with current properties settings
  DrawButton(@Scrn1Btn_MenuButton4_) ' redraw Menu Button 4 with current properties settings
  DrawButton(@Scrn1Btn_MenuButton5_) ' redraw Menu Button 5 with current properties settings
  DrawButton(@Scrn1BtnInd_MENU2_Results_)' redraw results button indicator if set visible *edited to add - forgot to include 1st time
  DrawButton(@Scrn1Btn_MenuCHANGE_)  ' redraw Menu change button with new caption
end sub
'_____________________________________________________



'----------------- End of User code ------------------'

' Event Handlers

'---------- Start of Screen1 Menu Navigation Button handling
sub procedure Scrn1Btn_MenuCHANGE_OnClick()
' cycles to next menu set of buttons on each press (click),
' changes the Caption Label for each button in the menu set
' changes each buttons ".OnClickPtr" reference to use a routine for current function


 if (MENU_PAGE = 3) then  ' cycle to next menu or roll over to first menu
    MENU_PAGE = 0
   else
    inc(MENU_PAGE)
 end if
 
' change the 5 Menu Buttons Captions text to current menu set function labels
  Scrn1Btn_MenuButton1__Caption = MENU_SET_TXT[MENU_PAGE][0]
  Scrn1Btn_MenuButton2__Caption = MENU_SET_TXT[MENU_PAGE][1]
  Scrn1Btn_MenuButton3__Caption = MENU_SET_TXT[MENU_PAGE][2]
  Scrn1Btn_MenuButton4__Caption = MENU_SET_TXT[MENU_PAGE][3]
  Scrn1Btn_MenuButton5__Caption = MENU_SET_TXT[MENU_PAGE][4]

 
 select case MENU_PAGE    ' change Menu Buttons to active set and set pointers to active handlers
   case 0                 ' Menu 1 set active
     Scrn1Btn_MenuCHANGE__Caption     = "MENU 1"
     Scrn1Btn_MenuButton1_.OnClickPtr = @Scrn1Btn_Menu1_SMODE_OnClick
     Scrn1Btn_MenuButton2_.OnClickPtr = @Scrn1Btn_Menu1_SHAPE_OnClick
     Scrn1Btn_MenuButton3_.OnClickPtr = @Scrn1Btn_Menu1_ALOCK_OnClick
     Scrn1Btn_MenuButton4_.OnClickPtr = @Scrn1Btn_Menu1_HOME_OnClick
     Scrn1Btn_MenuButton5_.OnClickPtr = @Scrn1Btn_Menu1_DRILL_OnClick
     
     if (ALOCK_ENABLE = 1) then
       Scrn1Btn_MenuButton3_.Gradient   = 0   ' ALOCK is enabled, so button is solid red
      else
       Scrn1Btn_MenuButton3_.Gradient   = 1   ' ALOCK is disabled, so button is gradient colors
     end if
     
   case 1                 ' Menu 2 set active
     Scrn1Btn_MenuCHANGE__Caption     = "MENU 2"
     Scrn1Btn_MenuButton1_.OnClickPtr = @Scrn1Btn_Menu2_LIMITS_OnClick
     Scrn1Btn_MenuButton2_.OnClickPtr = @Scrn1Btn_Menu2_OFFSET_OnClick
     Scrn1Btn_MenuButton3_.OnClickPtr = @Scrn1Btn_Menu2_MEASUR_OnClick
     Scrn1Btn_MenuButton4_.OnClickPtr = 0      ' clear function pointer - inactive button this menu set
     Scrn1Btn_MenuButton5_.OnClickPtr = 0      ' clear function pointer - inactive button this menu set

     Scrn1Btn_MenuButton3_.Gradient     = 1 ' set gradient for button 3 to enabled *edited to add - forgot to include 1st time
     Scrn1Btn_MenuButton4_.Visible         = 0 ' Hide Button 4
     Scrn1Btn_MenuButton4_.Active          = 0 ' disable Button 4
     Scrn1Btn_MenuButton4_.PressColEnabled = 0 ' disable Button 4 press color
     Scrn1Btn_MenuButton5_.Visible         = 0 ' Hide Button 5
     Scrn1Btn_MenuButton5_.Active          = 0 ' disable Button 5
     Scrn1Btn_MenuButton5_.PressColEnabled = 0 ' disable Button 5 press color
     
                                               ' this button replaces buttons 4&5 this menu set (double wide for display out)
     Scrn1BtnInd_MENU2_Results_.Visible    = 1 ' make visible measurements output display button
     Scrn1BtnInd_MENU2_Results_.Active     = 1 ' enable display button for touch to clear
  
   
   case 2                 ' Menu 3 set active
     Scrn1Btn_MenuCHANGE__Caption     = "MENU 3"
     Scrn1Btn_MenuButton1_.OnClickPtr = @Scrn1Btn_Menu3_EDIT_OnClick
     Scrn1Btn_MenuButton2_.OnClickPtr = @Scrn1Btn_Menu3_PREV_OnClick
     Scrn1Btn_MenuButton3_.OnClickPtr = @Scrn1Btn_Menu3_PLAY_OnClick
     Scrn1Btn_MenuButton4_.OnClickPtr = @Scrn1Btn_Menu3_NEXT_OnClick
     Scrn1Btn_MenuButton5_.OnClickPtr = @Scrn1Btn_Menu3_RECORD_OnClick

     Scrn1Btn_MenuButton4_.Visible         = 1 ' enable and make visible buttons 4&5 again
     Scrn1Btn_MenuButton4_.Active          = 1 ' "                                       "
     Scrn1Btn_MenuButton4_.PressColEnabled = 1 ' "                                       "
     Scrn1Btn_MenuButton5_.Visible         = 1 ' "                                       "
     Scrn1Btn_MenuButton5_.Active          = 1 ' "                                       "
     Scrn1Btn_MenuButton5_.PressColEnabled = 1 ' "                                       "
     
     Scrn1BtnInd_MENU2_Results_.Visible    = 0 ' hide measurements output display button
     Scrn1BtnInd_MENU2_Results_.Active     = 0 ' disable display button for touch to clear
   
   case 3                 ' Menu 4 set active
     Scrn1Btn_MenuCHANGE__Caption     = "MENU 4"  ' change menu button caption to current set.
     Scrn1Btn_MenuButton1_.OnClickPtr = @Scrn1Btn_Menu4_SETUP_OnClick
     Scrn1Btn_MenuButton2_.OnClickPtr = @Scrn1Btn_Menu4_SHUTDN_OnClick
     Scrn1Btn_MenuButton3_.OnClickPtr = @Scrn1Btn_Menu4_TOOL_OnClick
     Scrn1Btn_MenuButton4_.OnClickPtr = @Scrn1Btn_Menu4_SAVREC_OnClick
     Scrn1Btn_MenuButton5_.OnClickPtr = @Scrn1Btn_Menu4_LOAD_OnClick

   

 end select
 
 DrawMenu()                           ' blanks and redraws menu buttons with
                                      ' current properties settings
end sub
'---------- End of Screen1 Menu Navigation Button handling
'
'---------- Start of  S C R E E N 1  M E N U-1  Buttons handling
'Button 1"SMODE" 2"SHAPE" 3"ALOCK" 4"HOME" 5"DRILL"
sub procedure Scrn1Btn_Menu1_SMODE_OnClick()       ' Button 1

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu1_SHAPE_OnClick()       ' Button 2

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu1_ALOCK_OnClick()       ' Button 3

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu1_HOME_OnClick()        ' Button 4

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu1_DRILL_OnClick()       ' Button 5

end sub
'---------- End of Screen1 Menu-1 Buttons handling
'
'---------- Start of  S C R E E N 1  M E N U-2  Buttons handling
'Button 1"LIMITS" 2"OFFSET" 3"MEASUR" 4"Results"
sub procedure Scrn1Btn_Menu2_LIMITS_OnClick()       ' Button 1

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_MENU2_OFFSET_OnClick()       ' Button 2

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu2_MEASUR_OnClick()       ' Button 3

end sub
'-----------------------------------------------------
sub procedure Scrn1BtnInd_MENU2_Results_OnClick()   ' Button 4

end sub
'---------- End of Screen1 Menu-2 Buttons handling
'
'---------- Start of  S C R E E N 1  M E N U-3  Buttons handling
'Button 1"EDIT" 2"PREV" 3"PLAY" 4"NEXT" 5"RECORD"
sub procedure Scrn1Btn_Menu3_EDIT_OnClick()    ' Button 1

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu3_PREV_OnClick()    ' Button 2

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu3_PLAY_OnClick()    ' Button 3

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu3_NEXT_OnClick()    ' Button 4

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu3_RECORD_OnClick()  ' Button 5

end sub
'---------- End of Screen1 Menu-3 Buttons handling
'
'---------- Start of  S C R E E N 1  M E N U-4  Buttons handling
'Button 1"SETUP" 2"SHUTDN" 3"TOOL" 4"SAVREC" 5"LOAD"
sub procedure Scrn1Btn_Menu4_SETUP_OnClick()  ' Button 1

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu4_SHUTDN_OnClick() ' Button 2

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu4_TOOL_OnClick()  ' Button 3

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu4_SAVREC_OnClick() ' Button 4

end sub
'-----------------------------------------------------
sub procedure Scrn1Btn_Menu4_LOAD_OnClick()   ' Button 5

end sub
'---------- End of Screen1 Menu-4 Buttons handling
Now every Menu Function has its own routine to handle the tasks needed and all are still familiar layout as normal V-TFT object event handlers are,
without the need for a 'State Machine' manager routine in between TP activity and task code, pressing a Menu Function Button
that is displayed takes execution directly to the routine to handle event like a normal object with only one event to code for.

Only 6 Buttons plus menu change button for 18 different functions.

As the thread topic says, Making user pointers for better Object control, it needs not end with new tricks to explore, yes?
Any tricks anyone thinks is worth trying are welcome.

Regards, Robert. (going on trip, back in a few days)
Last edited by Megahurts on 31 Jul 2014 01:34, edited 3 times in total.
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: [?]Using pointers for object properties for better contr

#4 Post by aCkO » 12 Jul 2014 03:58

Since C is my language of choice (and a closest thing to assembly ever invented), I tried to bring some of its elegance to your example in mB. Funny thing about mB is that it doesn't support arrays of pointers to functions, nor explicit typecasting to pointer to function. Fortunately, implicit typecasting of integral data types to function pointers is allowed so I used that feature as a workaround.

First, let's pick up all the addresses of your event handlers and make 2D array out of them:

Code: Select all

const MENU_EVENTS as longword[4][5] =
  (
    (
      @Scrn1Btn_Menu1_SMODE_OnClick,
      @Scrn1Btn_Menu1_SHAPE_OnClick, 
      @Scrn1Btn_Menu1_ALOCK_OnClick,
      @Scrn1Btn_Menu1_HOME_OnClick,
      @Scrn1Btn_Menu1_DRILL_OnClick
    ),
    (
      @Scrn1Btn_Menu2_LIMITS_OnClick,
      @Scrn1Btn_MENU2_OFFSET_OnClick,
      @Scrn1Btn_Menu2_MEASUR_OnClick,
      0,
      0
    ),
    (
      @Scrn1Btn_Menu3_EDIT_OnClick,
      @Scrn1Btn_Menu3_PREV_OnClick,
      @Scrn1Btn_Menu3_PLAY_OnClick,
      @Scrn1Btn_Menu3_NEXT_OnClick,
      @Scrn1Btn_Menu3_RECORD_OnClick
    ),
    (
      @Scrn1Btn_Menu4_SETUP_OnClick,
      @Scrn1Btn_Menu4_SHUTDN_OnClick,
      @Scrn1Btn_Menu4_TOOL_OnClick,
      @Scrn1Btn_Menu4_SAVREC_OnClick,
      @Scrn1Btn_Menu4_LOAD_OnClick
    )
  )
Our Scrn1Btn_MenuCHANGE_OnClick event handler then becomes much more compact:

Code: Select all

sub procedure Scrn1Btn_MenuCHANGE_OnClick()
  dim i as byte

  inc(MENU_PAGE)
  MENU_PAGE = MENU_PAGE mod 4
 
  for i = 0 to 4
    strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
    MENU_BTNS[i]^.OnClickPtr = MENU_EVENTS[MENU_PAGE][i]
  next i

  Scrn1Btn_MenuCHANGE__Caption     = "MENU x"
  Scrn1Btn_MenuCHANGE__Caption[5]  = MENU_PAGE + 1 + 48
  
  Scrn1Btn_MenuButton4_.Visible         = (MENU_PAGE <> 1) and 1 
  Scrn1Btn_MenuButton4_.Active          = (MENU_PAGE <> 1) and 1 
  Scrn1Btn_MenuButton4_.PressColEnabled = (MENU_PAGE <> 1) and 1 
  Scrn1Btn_MenuButton5_.Visible         = (MENU_PAGE <> 1) and 1 
  Scrn1Btn_MenuButton5_.Active          = (MENU_PAGE <> 1) and 1 
  Scrn1Btn_MenuButton5_.PressColEnabled = (MENU_PAGE <> 1) and 1 
  
  Scrn1BtnInd_MENU2_Results_.Visible    = (MENU_PAGE = 1) and 1
  Scrn1BtnInd_MENU2_Results_.Active     = (MENU_PAGE = 1) and 1
 
  DrawMenu()
end sub
Also note that there is no need to use box object and draw it over buttons in order to delete them from the screen. You can use built in functions for that. You just need the top-left and bottom-right coordinates to draw a simple rectangle. To paint over buttons 4 & 5 with background color (CL_BLACK in your screenshots) you can use:

Code: Select all

TFT_Set_Brush(1, CL_BLACK, 0, 0, 0, 0)
TFT_Set_Pen(CL_BLACK, Scrn1Btn_MenuButton4_.Pen_Width)
TFT_Rectangle(Scrn1Btn_MenuButton4_.Left_,
              Scrn1Btn_MenuButton4_.Top,
              Scrn1Btn_MenuButton5_.Left_ + Scrn1Btn_MenuButton5_.Width - 1, 
              Scrn1Btn_MenuButton5_.Top + Scrn1Btn_MenuButton5_.Height - 1)
Regards

Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Re: [?]Using pointers for object properties for better contr

#5 Post by Megahurts » 16 Jul 2014 21:47

Hi Aleksandar and V.T.U.'s,

I'm back from trip now and made it safely, but almost not. We had three times Deer run out in front of us and had to brake
hard and pick a path to right or left of the Deer in order to miss them. The Deer don't make it easy either as they always seem
to change their minds after you've committed to a swerve Left or Right of them. One Doe left a nose snot streak down the right
side of the truck after she decided to turn around and go back to the side of the highway she came from (my left, and the
direction I picked to swerve around her), but a quick decision to get off the brakes and hit the gas got the trucks nose past hers
before she could get one step further back the way she came, so she froze (thankfully) and got the end of her nose scraped only.
We seen around 20 recently hit and killed Deer along the road in a 60 mile stretch, but did not add to the count. :D
Funny thing about mB is that it doesn't support arrays of pointers to functions,
Yeah, I found that out before posting the code I did after changing it to remove the array I made for the function pointers. :(
:D That you knew other approaches to try to get around this is more proof of some awesome programming skills/knowledge
you have to call on. And I'm very thankful for that too. :wink:

If I understand the work around you did correctly, you just made a conventional array of Longword type that "dereferenced"
the routines addresses and stored them as longword values, that are acceptable targets (type and values) for the routine call
pointer for events for an object? Neat trick. I never would have thought of that. :mrgreen:

I put your example code into my app this morning but got an error on this line of code from the iterated button update loop:

Code: Select all

  for i = 0 to 4  ' aCkO's alternate method: changes buttons captions and OnClick pointers
    strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
    MENU_BTNS[i]^.OnClickPtr = MENU_EVENTS[MENU_PAGE][i]
  next i
628 327 Incompatible types ("constant" to "variable by reference")
for the code line:

Code: Select all

strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
I do have the "String" Library included for project also.

I must admit that after following a few more of your posts where the differences between mB and mC were explained by you,
just knowing C's features and functionality would be of great benefit for programming in any other language, if the differences and
limits were understood and known.
But just buying the mC compiler would not give one the knowledge and skills a class course would right? Even more so with the documentations only provided with mC (or mB, mP).

Since an objects actual "Caption" string variable is not part of its defined data structure, just a pointer to it is,
it makes for some confusion I have seen for users as to how to properly change caption text.
Personally, I have had the best success with direct manipulation of the actual string variable, but in this case where iterated access
to the "set" of captions would be ideal and consistent with the rest of the buttons properties manipulation code methods,
it would be nice to keep it as such.
I guess an index-able array of some sort could be made of/to the actual caption variables also?

A question: can you please say if this is right syntax for iterating the menu buttons redrawing?

Code: Select all

  for i = 0 to 4
    DrawButton(MENU_BTNS[i])   ' redraw Menu Buttons with current properties settings. ? Is pointer correct dereferencing
  next i
Once another pointer to a pointer has been done, it is confusing if the "@" is still needed or something else needs done to code to make it right?

As to the use of a box to blank out the area the menu buttons occupy, I choose this method as it was easy to do and shows a possible
usage of V-TFT objects in GUI designs and I intentionally wanted the entire set of menu buttons to 'blank out' as a visual effect
to help operator see the button set change occurred, so that part I will retain as-is, but thanks for showing alternative for others
to consider using.

One other point about the different approaches we are showing for these 'State' managed buttons, and why I almost think it would have better to use 18 different buttons instead of 5,
in this case (for my design wants), some of the buttons will have other visual properties changed to indicate different states of its
functions. And I have not finalized the extent of how much each may employ yet also.(but pretty sure more buttons/functions
will make use of some visual properties to indicate functions state or user attention required. There is not enough screen space left over to have other indicators programmed to provide the information, so making use of what is already on the screen is option I'm using with the buttons. The 'LIMITS' button will be another one that is like a toggle switch for ON/OFF state also.)
Example of this is in my last code posted for case 0 and case 1 for menu button 3.

The Menu set1 button3 "ALOCK" (Axis LOCK) function retains its state of ON (Red solid fill color) or OFF (Gradient fill colors)
being applied to the X/Y axis movement input circle area at all times, so when its function button is displayed again, it needs to be
shown at current state setting. But with the reusing of the menu buttons instead of individual buttons, these state of the properties
for indicating such needs to be handled differently also. (individual buttons automatically provided the tracking solution agreed?)
(I'm still working on best way to hide/show all of the rectangle buttons on the colored circles input area based on ALOCK status too.) :?
(probably going to make another array to those buttons for iteration loop control of drawing them, drawing the circles from code will hide them, so a loop to disable/enable active properties also will be used.)

Your coding methods (as is) does not address the need to restore the individual buttons 'last state' of these other properties
when menu sets are changed.
This is why I think I must use the additional Select Case code blocks to check and restore any buttons state that has additional indicator effects employed,
or resort to having a separate button for each menu function-(original reason why I did so), so its properties are the state
holders instead of additional user variables for tracking the states of each one it is needed for.

It can be done either way, and only the need to keep code readable and/or if space saving is required might be the only dictator as
to which should be used.

But at least we are setting up a basis that we can build upon to achieve the desired 'State' management of some reusable buttons.
I think this method of "presetting" the buttons event routine pointers has a lot of merit for making code easier to read/follow
and easier for the programmer to keep their code "structured" in smaller discrete chunks, instead of having large complex
routine code that has higher chance of failing logic conditions accounted for and ending up being trapped and causing program Lock-up. (btw- making all of those individual buttons and event routines in V-TFT did make it easier to do it this way also with all
of the event routines template code remaining after deleting the original buttons. pretty cool trick also to use.)

BTW, here is an updated image of the screen we have been working on for button state management:
cnc_stepper_menu1_buttons.jpg
cnc_stepper_menu1_buttons.jpg (77.21 KiB) Viewed 11668 times
*The word 'INDEX' is only displayed during movement recording or playback editing and button 5 will display index numerical value then.(Menu set 3, pressing the Record or Play or Edit buttons causes the RECORD button to display index value and 'INDEX' label object.)

Going to try some changes to the code and see what solutions I may find, Thanks as always Aleksandar for the insights and examples you provide,
now to digest it and see if I can put it to use, Robert.
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Re: [?]Using pointers for object properties for better contr

#6 Post by Megahurts » 18 Jul 2014 17:50

Hey guys,

Just a quick question for aCkO, or whoever may know answer to this.

From your first post here in this thread topic:
For example, let's say we want to manipulate 5 buttons simultaneously. The easiest way to do this is to declare an array of pointers to them:

Code: Select all

const Group1 as TButtonPtr[5] = (@Button1, @Button2, @Button3, @Button4, @Button5)
In this case pointers act like "handles" to button objects and by using them in an array we have the benefit of accessing pointed objects iteratively, i.e. we can use loops for setting object properties instead of doing that individually object-by-object (the unfolded way). Not only we will save some ROM, but our fingers will be grateful to us for typing much less code :)
I assume this same technique be done to make "handles" to objects properties?
and to different objects and/or properties in same array?

Will a different/new type definition be required, I am thinking it does, but not known if a compatible type already exists in V-TFT declarations
that can be reused like "TButtonPtr" was?

(I swear I will learn pointers inside and out, if I see/use/make some that have (important) meaning to me in their usage.
The documents for mB on pointers is too vague and general with the examples shown for me to learn/remember the context for usages.)

I also think/guess there is a limit condition that only the object properties of same type can be included in the pointer array?

I was wanting to see if I can make a more efficient pointer based storage array for holding/tracking the Menu Buttons states
of the other visual properties used/changed as needed for some of the buttons functions.

OR...

If mixed property types are wanted to be stored as last state for the buttons in a set array, should a structure similar to the buttons
structure be made of the properties only wanted to hold/preserve settings states and then make a "handle" pointer array for them?

I can "see" a solution/method done conventionally without structures and pointers using data arrays, but I suspect it would not
be nearly as efficient as the code you always show vs my usual simplistic approach.
(btw, I really love it when you show a code example that does the same function I coded, but you used a operator(s) or expression
that inherently gives same results but 90% fewer code instructions to do so. Awesome grasp of Logic, Operators and relationships you
have to 'see'/know when/where to make use of them intrinsically as you do. yes, jealous as heck.
Hope you get paid very well if programming is your occupation, your skill set deserves a high value payment. :wink: )

I really wish we could 'tie'/'link' objects and their properties to (as you called it) a group container. It would make things so much easier and more efficient.

Regards and looking forward to your thoughts on this, Robert. :?
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: [?]Using pointers for object properties for better contr

#7 Post by aCkO » 20 Jul 2014 02:38

Hi Robert,

Sorry for the late reply. I see many questions have piled up :)
Megahurts wrote:I put your example code into my app this morning but got an error on this line of code from the iterated button update loop:

Code: Select all

  for i = 0 to 4  ' aCkO's alternate method: changes buttons captions and OnClick pointers
    strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
    MENU_BTNS[i]^.OnClickPtr = MENU_EVENTS[MENU_PAGE][i]
  next i
628 327 Incompatible types ("constant" to "variable by reference")
for the code line:

Code: Select all

strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
I do have the "String" Library included for project also.
It should work if all the declarations are ok. You will find a working test project in the attachment.
Megahurts wrote:I must admit that after following a few more of your posts where the differences between mB and mC were explained by you,
just knowing C's features and functionality would be of great benefit for programming in any other language, if the differences and
limits were understood and known.
Short answer is YES. C is designed with the intention to provide simple machine level abstraction which makes it highly portable, i.e. platform independent. It was never intended to be a "high-level" programming language. In fact, the only thing lower then C is the assembly itself. Compared to C, all other languages introduce "features" (read: additional level of complexity) which make things "simpler" for the programmer. Unfortunately, most of the times these features leave the programmer in the dark as to what happens at the hardware level. Basically, there is always a trade-off between the ease of use and control. Let's take the string data type in mB and mP as an example. Both languages provide intrinsic string manipulation (assignment, copying, concatenation etc). Because of this feature, Basic/Pascal programmers don't need to worry about internal memory representation or interpretation of the string. Imagine how surprised (read: terrified) they feel when they attempt to learn C and find out that there is no string data type! A lot of them give up easily because they refuse to rethink the concept they are so used to. In C, string is just an array of bytes, more precisely - null terminated sequence of characters. Strings are represented in the same way in mB and mP, but that is not so obvious for the programmer. For mB/mP this is also a limitation as much as it is a feature especially in embedded systems. In C, you have the liberty to "invent" some other string format (for example, the short string format in Pascal where the first byte is the length of the string followed by the sequence of chars). It all depends on personal preferences: some people would consider C's absence of limitations as powerful, others as dangerous.
Megahurts wrote:But just buying the mC compiler would not give one the knowledge and skills a class course would right? Even more so with the documentations only provided with mC (or mB, mP).
Only the 2 XPs will give you that: eXPerimentation and eXPerience. The very well written mC/mB/mP Help files can only serve you as a reference when you have doubts about particular language concepts. As I have said, C is a very simple, powerful and effective language (small number of keywords to remember, simple data types, powerful operators combined with a very compact syntax etc). Maybe we could start a thread about "C for Basic/Pascal users" :)
Megahurts wrote:Since an objects actual "Caption" string variable is not part of its defined data structure, just a pointer to it is,
it makes for some confusion I have seen for users as to how to properly change caption text.
That's because of the limitations I already mentioned. In mB and mP string is an artificial data type which is internally implemented just like in mC. In mB/mP string cannot be part of the structure because the memory for it is allocated statically. In other words, for different caption lengths you would need to declare separate data structures, which is a bad solution considering the limited resources available. Interestingly enough, this exact problem was present in the early days of Pascal.
Megahurts wrote:Personally, I have had the best success with direct manipulation of the actual string variable
A perfectly valid solution if we know in advance the naming convention used by mE developers (<variable>_Caption). However, since Caption is declared as pointer to char in the object data structure, it should be always accessed through pointer. Otherwise we could have problems similar to this one:

Code: Select all

dim txt as string[5]

txt = "Bye"
Button1.Caption = @txt

Button1_Caption = "Hello"   ' this has no effect anymore
It is much better to use "C-style" string assignment:

Code: Select all

strcpy(Button1.Caption, "Hello")
Megahurts wrote:but in this case where iterated access
to the "set" of captions would be ideal and consistent with the rest of the buttons properties manipulation code methods,
it would be nice to keep it as such.
You can do this just by reassigning the caption pointer just like in the above example. In the attached example just replace the line:

Code: Select all

strcpy(MENU_BTNS[i]^.Caption, MENU_SET_TXT[MENU_PAGE][i])
with:

Code: Select all

MENU_BTNS[i]^.Caption = @MENU_SET_TXT[MENU_PAGE][i]
Megahurts wrote:A question: can you please say if this is right syntax for iterating the menu buttons redrawing?

Code: Select all

  for i = 0 to 4
    DrawButton(MENU_BTNS[i])   ' redraw Menu Buttons with current properties settings. ? Is pointer correct dereferencing
  next i
Once another pointer to a pointer has been done, it is confusing if the "@" is still needed or something else needs done to code to make it right?
Your code is fine. Function DrawButton uses object address (pointer) as an argument. Pointers behave just like "regular" variables: they have value and take up space in memory. Adding additional levels of indirection can be confusing sometimes, but it is fairly easy to match required data types. MENU_BTNS is an array of pointers => MENU_BTNS is a pointer. On the other hand, function DrawButton expects pointer as an argument, so we have a match.
Megahurts wrote:One other point about the different approaches we are showing for these 'State' managed buttons, and why I almost think it would have better to use 18 different buttons instead of 5,
in this case (for my design wants), some of the buttons will have other visual properties changed to indicate different states of its
functions.
Just create a simplified data structure out of the properties you will be changing (simplified version of the button object). Then create an array of those structures and save/load state properties when changing menus. I can make an example if you want.
Megahurts wrote:I assume this same technique be done to make "handles" to objects properties?
Yes.
Megahurts wrote:and to different objects and/or properties in same array?
Array elements by definition must be of the same type, i.e. size of each element must be the same for indexing to work. You can use address of the object and mark its type in a custom structure and perform casting based on that. That's what I did in my reusable objects tutorial.
Megahurts wrote:Will a different/new type definition be required, I am thinking it does, but not known if a compatible type already exists in V-TFT declarations
that can be reused like "TButtonPtr" was?
Yes. If it doesn't you can always create it. For example, for the Caption property:

Code: Select all

typedef TCharPtr as ^char
One of the reasons I prefer mC is that I don't have to prepare my typedefs like in mB/mP. In C, this is part of the declaration.
Megahurts wrote:If mixed property types are wanted to be stored as last state for the buttons in a set array, should a structure similar to the buttons
structure be made of the properties only wanted to hold/preserve settings states and then make a "handle" pointer array for them?
Your approach is good but you need to know when to use pointers and when not to. In C, arrays and pointers are almost the same thing, i.e. they are used for memory navigation in the same way. Arrays are physical objects which take up space in memory. On the other hand, pointers are just addresses (integer values) which have their pointed types declared so the compiler knows the increments in which the memory is navigated. In practice, this means:
1) If you want to create new objects, you will naturally declare an array of objects
2) If you have existing objects scattered throughout RAM/ROM, you would want to create an array of pointers to them so you can process them iteratively. Kind of like bringing order to chaos :)
Megahurts wrote:btw, I really love it when you show a code example that does the same function I coded, but you used a operator(s) or expression
that inherently gives same results but 90% fewer code instructions to do so. Awesome grasp of Logic, Operators and relationships you
have to 'see'/know when/where to make use of them intrinsically as you do. yes, jealous as heck.
Thank you for your kind words. During their lifetime, majority of C programmers develop OCD for writing compact expressions :) That's why Basic/Pascal guys often accuse us for writing unreadable code :D
Megahurts wrote:Hope you get paid very well if programming is your occupation, your skill set deserves a high value payment. :wink: )
Well, things could be better, but I am not complaining :) Unfortunately, I am somewhat stretched between the things I love to do (embedded development/DSP/cryptography) and the things I do to make for a living (mostly database/networking stuff). I have some big projects in my plans so let's hope I'll manage to combine business and pleasure very soon ;)

Regards
Attachments
group2.zip
(11.01 KiB) Downloaded 286 times

PIC007
Posts: 179
Joined: 28 Aug 2013 18:28

Re: [?]Using pointers for object properties for better contr

#8 Post by PIC007 » 23 Jul 2014 23:21

Hello Aleksandar,

I have been following with interest this more elegant way of encapsulating objects as an array of pointers to allow one to iterate through them and set properties, detect events etc.
For example, let's say we want to manipulate 5 buttons simultaneously. The easiest way to do this is to declare an array of pointers to them:

const Group1 as TButtonPtr[5] = (@Button1, @Button2, @Button3, @Button4, @Button5)

In this case pointers act like "handles" to button objects and by using them in an array we have the benefit of accessing pointed objects iteratively, i.e. we can use loops for setting object properties instead of doing that individually object-by-object (the unfolded way). Not only we will save some ROM, but our fingers will be grateful to us for typing much less code :)

Here's how we can change the Visible property of all the members in the above group:

sub procedure ShowGroup(dim byref p as TButtonPtr[5], dim IsVisible as byte)
dim i as byte

for i = 0 to 4
p^.Visible = IsVisible
next i
end sub

Usage:
ShowGroup(Group1, 1) ' Show buttons
ShowGroup(Group1, 0) ' Hide buttons


My aim is to converted your example Group2.zip to c code as a starting point to understanding and experimenting (maybe you have it in c already and would be good enough to prost it too).

I made a small start with trying to create an array of pointers to the round_button type using...

TButton_Round *TButtonPtr[5] = (&S2_BtnRnd_Btn1, &S2_BtnRnd_Btn2, &S2_BtnRnd_Btn3, &S2_BtnRnd_Btn4, &S2_BtnRnd_Btn5);

but keep getting an error "Incompatible types", so am a bit unsure of why this is.

Also, I have a question understanding the line of Basic code:
const Group1 as TButtonPtr[5] = (@Button1, @Button2, @Button3, @Button4, @Button5)

It seems Basic has allowed you to create a new object called "Group1" (using the "const Group1 as"). Is this correct? I can not see this is possible in C - so assume I am meant to just pass the array (i.e. address of the array of pointers) to the function where I can act on each pointer using the -> designation? Am I on the right track?

Thanks.

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: [?]Using pointers for object properties for better contr

#9 Post by aCkO » 24 Jul 2014 02:25

PIC007 wrote:My aim is to converted your example Group2.zip to c code as a starting point to understanding and experimenting (maybe you have it in c already and would be good enough to prost it too).
Check the attachment.
PIC007 wrote:I made a small start with trying to create an array of pointers to the round_button type using...

TButton_Round *TButtonPtr[5] = (&S2_BtnRnd_Btn1, &S2_BtnRnd_Btn2, &S2_BtnRnd_Btn3, &S2_BtnRnd_Btn4, &S2_BtnRnd_Btn5);

but keep getting an error "Incompatible types", so am a bit unsure of why this is.
Use curly braces instead of parentheses.
PIC007 wrote:It seems Basic has allowed you to create a new object called "Group1" (using the "const Group1 as"). Is this correct? I can not see this is possible in C - so assume I am meant to just pass the array (i.e. address of the array of pointers) to the function where I can act on each pointer using the -> designation? Am I on the right track?
Don't get confused by Basic declarations. That's how you declare an array of constant pointers. The equivalent in C would be:

Code: Select all

TButton * const Group1[5] = {&Button1, &Button2, &Button3, &Button4, &Button5};
Reading C declarations can be tricky sometimes. The easiest way to get them right is to "parse" the tokens through a spiral. The above example for Group1 then becomes:

Code: Select all

         +----------------------+
         |  +----------------+  |
         |  |     +------+   |  |
         |  |     |      |   |  |
TButton  *  const Group1[5]  |  |
^        ^  ^            |   |  |
|        |  +------------+   |  |
|        +-------------------+  |
+-------------------------------+
Which reads: Group1 is an array of 5 constant pointers to TButton.

As an exercise, I leave the next one to you: :)

Code: Select all

void (* const MENU_EVENTS[4][5])()
Regards
Attachments
group2.zip
(9.75 KiB) Downloaded 280 times

PIC007
Posts: 179
Joined: 28 Aug 2013 18:28

Re: [?]Using pointers for object properties for better contr

#10 Post by PIC007 » 24 Jul 2014 14:43

Great help - many thanks Aleksandar (and Robert for getting this post started).

I'm adding a link here for the benefit of readers, to your other post on reusable objects as the subject matter is closely related...

http://www.mikroe.com/forum/viewtopic.p ... ct#p223900

Re the tutorial homework:
As an exercise, I leave the next one to you: :)
void (* const MENU_EVENTS[4][5])()
I think this means a 4x5 dimensional array of pointers but which is type cast to no particular object type (i.e. void). I assume this lets you pass this as a parameter of type void to a function, where within the function you would be able to dynamically set the Type it relates to (e.g. TButton, TBox etc), and probably also be able to initialize the array {Button1, Button2, ...} or {Box1, Box2, ...}.

Is this close :?:

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: [?]Using pointers for object properties for better contr

#11 Post by aCkO » 24 Jul 2014 16:52

Code: Select all

      +--------------------------+
      | +----------------------+ |
      | |     +----------+     | |
      | |     |          |     | |
void (* const MENU_EVENTS[4][5]) ()
^     ^ ^                |     | |
|     | +----------------+     | |
|     +------------------------+ |
+--------------------------------+
MENU_EVENTS is an array of 4 arrays of 5 constant pointers to functions which take no arguments and return void (nothing).

This declaration can be found in the example from my previous post. Declaring array of pointers to functions directly is possible in mC, but not in mB/mP. However, mB/mP users can use the workaround I already described.

Regards

Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Re: [?]Using pointers for object properties for better contr

#12 Post by Megahurts » 24 Jul 2014 21:01

Hi Guys and followers,

Wow, good stuff and informative Aleksandar. Thanks @ PIC007 for the jump-in questions too. Also very informative to users of mC and mB, mP to show differences between implementations.

I have a observation I found to pass along also on some 'container' declarations in a V-TFT projects declarations in the 'driver' file:
(these are from a different project I was working on yesterday, putting what I have learned above to use in it)

After I made this new pointer 'container' or 'handles' array of constants for 4 Round Buttons I am using as data output/display replacements for 4 Labels:

Code: Select all

      const COUNT_DISPLAY  as TButton_RoundPtr[4] =
         (
         @Scrn1_BtnRnd_DDInd_POnC,
         @Scrn1_BtnRnd_DDInd_POffC,
         @Scrn1_BtnRnd_DDInd_GOnC,
         @Scrn1_BtnRnd_DDInd_GOffC
         )
I was browsing thru the driver file looking for the next set of objects declarations I wanted to add array handles for and found this:

Code: Select all

      const Screen1_Buttons_Round  as TButton_RoundPtr[4] =
         (
         @Scrn1_BtnRnd_DDInd_POnC,
         @Scrn1_BtnRnd_DDInd_POffC,
         @Scrn1_BtnRnd_DDInd_GOnC,
         @Scrn1_BtnRnd_DDInd_GOffC
         )
:shock: Yep, exactly the same structure I needed, already made by V-TFT! In fact V-TFT makes these for every screens objects of same type used (and even if only One of a component type is used on a screen).
(Note: I had seen these declarations before, back when I was first delving into the workings of V-TFT, but until we started this topic, had not realized exactly what they were or that they could be used by us users.)

For example of a screens Object container array identifier listing, here are my other projects complete Screen1 groups of handler arrays made by V-TFT in the driver file:
(These are found at the end of each screens constants for static objects properties structure declarations code listings, even if objects are Dynamic.
Top of driver file, before the "implements" statement, organized by creation order of Screen-->Object Type-->Draw Priority {Back to Front})

Code: Select all

      const Screen1_Buttons  as TButtonPtr[2] =
         (
         @Scrn1_Btn_PULSE10_,  
         @Scrn1_Btn_GATE10_    
         ) code
      const Screen1_CButtons  as TCButtonPtr[25] =
         (
         @Scrn1_Btn_PWM_,      
         @Scrn1_BtnPulseOn_Plus1_,
         @Scrn1_BtnPulseOn_Plus10_,
         @Scrn1_BtnPulseOn_Plus100_,
         @Scrn1_BtnPulseOff_Plus100_,
         @Scrn1_BtnPulseOff_Plus10_,
         @Scrn1_BtnPulseOff_Plus1_,
         @Scrn1_BtnPulseOn_Minus1_,
         @Scrn1_BtnPulseOn_Minus10_,
         @Scrn1_BtnPulseOn_Minus100_,
         @Scrn1_BtnPulseOff_Minus1_,
         @Scrn1_BtnPulseOff_Minus10_,
         @Scrn1_BtnPulseOff_Minus100_,
         @Scrn1_BtnGateOn_Plus1_,
         @Scrn1_BtnGateOn_Plus10_,
         @Scrn1_BtnGateOn_Plus100_,
         @Scrn1_BtnGateOff_Plus1_,
         @Scrn1_BtnGateOff_Plus10_,
         @Scrn1_BtnGateOff_Plus100_,
         @Scrn1_BtnGateOn_Minus1_,
         @Scrn1_BtnGateOn_Minus10_,
         @Scrn1_BtnGateOn_Minus100_,
         @Scrn1_BtnGateOff_Minus1_,
         @Scrn1_BtnGateOff_Minus10_,
         @Scrn1_BtnGateOff_Minus100_
         ) code
      const Screen1_Buttons_Round  as TButton_RoundPtr[4] =
         (
         @Scrn1_BtnRnd_DDInd_POnC,
         @Scrn1_BtnRnd_DDInd_POffC,
         @Scrn1_BtnRnd_DDInd_GOnC,
         @Scrn1_BtnRnd_DDInd_GOffC
         ) code
      const Screen1_CLabels  as TCLabelPtr[4] =
         (
         @Label1,              
         @Label2,              
         @Label4,              
         @Label3               
         ) code
      const Screen1_CBoxes  as TCBoxPtr[2] =
         (
         @Box1,                
         @Box2                 
         ) code
It seems V-TFT makes these for every screen in the driver file declarations area (above 'implements' statement).
In this case, the only Round Buttons on my screen are the ones I am using as data output displays, so the V-TFT declaration was perfect
for my reusing it in my User Code as follows:

Code: Select all

sub procedure UpdateCounter_Ind(dim COUNT as word, dim DISPLAY as byte)
'  routine to update the COUNT value to indicator indexed @Screen1_Buttons_Round[DISPLAY]
  WordToStrWithZeros(COUNT, CONVERT_STR) '  converts passed word value to 5 character string with leading zeros in variable CONVERT_STR.
  strcpy(Screen1_Buttons_Round[DISPLAY]^.Caption, CONVERT_STR) '  put converted word value 5 character string in objects caption variable.
  DrawRoundButton(Screen1_Buttons_Round[DISPLAY])    ' redraw Count indicator Screen1_Buttons_Round[DISPLAY]
                                                     ' 0= @Scrn1_BtnRnd_DDInd_POnC  Pulse On Count display
                                                     ' 1= @Scrn1_BtnRnd_DDInd_POffC  Pulse Off Count display
                                                     ' 2= @Scrn1_BtnRnd_DDInd_GOnC  Gate On Count display
                                                     ' 3= @Scrn1_BtnRnd_DDInd_GOffC  Gate Off Count display
                                                     ' function call uses V-TFT driver file definition
                                                     ' Screen1_Buttons_Round[x] screen grouping of
                                                     ' Round Button Objects
  Reset_Pulser()
end sub
'===============================================================================
This can be of benefit for users for two reasons:
1- if nothing else, it provides (in the compiler language used) a clear working example of an array container declaration V-TFT code will work with.
2- If planned out so there are only the type of objects on a screen needing to be used in a group control like this, users can just reuse
the V-TFT generated arrays without needlessly adding duplicate code to project (although probably eliminated by optimization when compiled anyway, but saves you typing the code).

Still digesting the previous posts Aleksandar (Thank You), but thought this find was important to pass along at this time.
So users remember to examine the driver files declarations to find the pre-made arrays for every projects screen objects used,
since it seems every object is already a part of some defined index-able array, you might find this very useful in your coding.

Best wishes all, Robert.
Last edited by Megahurts on 31 Jul 2014 05:57, edited 4 times in total.
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

PIC007
Posts: 179
Joined: 28 Aug 2013 18:28

Re: [Making] User pointers for better control of objects

#13 Post by PIC007 » 29 Jul 2014 16:17

Thank you for the helpful guidance aCkO and Megahurts,

I trying to build on the concept of creating reusable menu buttons (each with a caption and pointer to a click function) which are reused on different screens.

The code ideas you gave me Aleksandar are the basis to this, but instead of having separate arrays for - menu button captions, menu button calling function pointers etc - I am trying to combine these into one MENU structure as shown below.

Ed --- please see revised post after Robert's below.
Last edited by PIC007 on 30 Jul 2014 16:41, edited 2 times in total.

Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Re: [Making] User pointers for better control of objects

#14 Post by Megahurts » 30 Jul 2014 01:45

Hi PIC007,

Sorry, for me, I don't know where to start with that mC code, Aleksandar will have to analyze it I'm sorry to say.

But I do have another observation and code test results to share with everyone following this topic. The text below this picture explains my findings:
for loop vs individual statements routine size.jpg
for loop vs individual statements routine size.jpg (837.52 KiB) Viewed 11391 times
The image is a composite of 3 screen grabs of the same routine and statistics for it shown at right of the code editor window.
They are labeled A,B,C and show the differences in the routines code as I performed my testing of routine size (in bytes) for each case.
As I implemented the iterated object pointer handlers in this project and another project, I expected the programs code size to be reduced,
but this was not the case for either projects final code size.?

A: Shows the "DrawMenu()" routines original code as I first designed it using individual draw functions for each button in the menu set. It compiled to a size of 44 bytes as listed.
B: Shows the For-Next Loop replacement of the commented out individual draw button functions (5 function calls) enclosed in the red box,
and in the Statistics window, highlighted by red box also, it shows after being compiled that the routines size increased by 8 bytes, 44->52 now.
It seems that the final assembly code implementation for a 'For-Next' loop to iterate through 5 draw calls is more than the 5 individual draw button function calls.
So I decided to go a little bit further and see if any gain could be gotten by adding the last two individual draw button calls to the array pointer handler
I had already made.

C: Shows the results from doing that. As shown, the routine "DrawMenu()" is now back to 44 bytes in size!

So 7 (maybe 6?) iterations seems to be the minimum number of individual calls to be replaced by looping thru iteration calls that does not increase
the programs final file size (using a 'For-Loop' anyway).

This is not really important unless program size is a factor with the device you are using, so I post it just for information purposes only,
and not as coding practices you should employ always.

I'm sure that the more elements there are in a array of object pointers, the more saving of program space will be realized by using iteration code replacing individual element handling code.
But you should remember that for a small number of elements to be handled, doing it as individual lines of code might be the best way to save some code space.

btw @Aleksandar, here is what I had to do to get rid of that compiler error with string copy to buttons caption using objects structure element pointer:

Code: Select all

sub procedure Scrn1Btn_MenuCHANGE_OnClick()
' cycles to next menu set of buttons on each press (click),
' changes the Caption Label for each button in the menu set
' changes each buttons ".OnClickPtr" reference to use a routine for current function
dim i  as byte
    TS as string[6]       ' added to eliminate "constant to variable by reference" error

 if (MENU_PAGE = 3) then  ' cycle to next menu or roll over to first menu
    MENU_PAGE = 0
   else
    inc(MENU_PAGE)
 end if
 
' change the 5 Menu Buttons Captions text to current menu set function labels
'  Scrn1Btn_MenuButton1__Caption = MENU_SET_TXT[MENU_PAGE][0]
'  Scrn1Btn_MenuButton2__Caption = MENU_SET_TXT[MENU_PAGE][1]
'  Scrn1Btn_MenuButton3__Caption = MENU_SET_TXT[MENU_PAGE][2]
'  Scrn1Btn_MenuButton4__Caption = MENU_SET_TXT[MENU_PAGE][3]
'  Scrn1Btn_MenuButton5__Caption = MENU_SET_TXT[MENU_PAGE][4]
' Replaced by alternate loop code below

  for i = 0 to 4  ' aCkO's alternate method: changes buttons captions and OnClick pointers
    TS = MENU_SET_TXT[MENU_PAGE][i]    ' load temp string holder (TS) with caption text
    strcpy(MENU_BTNS[i]^.Caption, TS)      ' copy TS string to object caption string (by indexed pointer de-reference)
    MENU_BTNS[i]^.OnClickPtr = MENU_EVENTS[MENU_PAGE][i]  ' also change objects OnEvent pointer to array indexed address
  next i          ' loop to do next menu button in set
(added a local string variable (TS) to act as temp buffer for caption text constants from the array holding them)
It now compiles without that error, yet to be tested running on device.


Happy programming everyone, Robert. (and thanks for following this and any comments you share)
Last edited by Megahurts on 31 Jul 2014 06:21, edited 1 time in total.
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

PIC007
Posts: 179
Joined: 28 Aug 2013 18:28

Re: [Making] User pointers for better control of objects

#15 Post by PIC007 » 30 Jul 2014 16:27

Thanks for looking Robert.

Aleksandar (or anyone else), since I posted yesterday, I have made some headway in getting the code below to compile and work. Again, my intention is to have 5 reusable menu buttons. Menu tables will hold the - button type, button caption, button action (per struct _MENU).

Depending on button type (see menu type defines), different button actions should follow. For example, if a button type is CMD, then the OnClick for that button should point to function which should operate when the button is pressed. The code seems to work for this.

Where I am stuck is going to the next step where button type is SUB_MENU. This should point the OnClick for that button to DispMenu function and pass the sub menu we wish to display to it.

I seem unable to get syntax correct for this:
MENU_BTNS[i-1]->OnClickPtr = void (*DispMenu((MENU *)MenuTbl.MenuPtr)); // Illegal expression with void Menu_events_code.c

and also worry a bit that I am calling the same function in which this line of code is being setup!

I would appreciate any help you can provide...

Code: Select all

/* --- Menu Type Defines --- */
#define MENU_TYPE_MAIN_MENU_HEADER 0
#define MENU_TYPE_SUB_MENU_HEADER  1
#define MENU_TYPE_SUB_MENU         2
#define MENU_TYPE_CMD              3
#define MENU_TYPE_CHK_BOX          4
#define MENU_TYPE_RADIO_BTN        5
#define MENU_TYPE_END_OF_MENU      6

/* --- MENU Type ---- */
typedef struct _MENU
{
  short MenuType;       // Menu type define
  const char *MenuTxt;  // Menu btn caption (no more than 11 characters)
  void *MenuPtr;        // Menu btn function
} MENU;


/* --- Forward declaration of Local Function Prototypes --- */

void DrawMainScn(void);
void DrawAboutScn(void);
void DrawBATScn(void);
void HistoryCmd(void);
void RTCAdjDate(void);
void RTCAdjTime(void);
void TVSChk(void);
void DispMenu(MENU *);

/* --- Forward declaration sub menus --- */
const MENU SetupMenu[];
const MENU StatusMenu[];
const MENU AboutMenu[];
const MENU LCDMenu[];
const MENU TimeDateMenu[];

/* --- Initialize Menus {MenuType; *MenuTxt; *MenuPtr} --- */
MENU MainMenu[] = {
  {MENU_TYPE_MAIN_MENU_HEADER, "MAIN MENU", DrawMainScn},
  {MENU_TYPE_SUB_MENU, "SETUP Menu", SetupMenu},
  {MENU_TYPE_SUB_MENU, "STATUS Menu", StatusMenu},
  {MENU_TYPE_SUB_MENU, "ABOUT Menu", AboutMenu},
  {MENU_TYPE_CMD, "HISTORY", HistoryCmd},
  {MENU_TYPE_CHK_BOX, "TVS", TVSChk},
  {MENU_TYPE_END_OF_MENU, "", 0}
};
MENU SetupMenu[] = {
  {MENU_TYPE_SUB_MENU_HEADER, "SETUP MENU", MainMenu},
  {MENU_TYPE_SUB_MENU, "LCD Menu", LCDMenu},
  {MENU_TYPE_SUB_MENU, "Time/Date", TimeDateMenu},
  {MENU_TYPE_END_OF_MENU, "", 0}};

MENU StatusMenu[] = {
  {MENU_TYPE_SUB_MENU_HEADER, "STATUS MENU", MainMenu},
  {MENU_TYPE_CMD, "Battery", DrawBATScn},
  {MENU_TYPE_END_OF_MENU, "", 0}};

MENU AboutMenu[] = {
  {MENU_TYPE_SUB_MENU_HEADER, "ABOUT MENU", MainMenu},
  {MENU_TYPE_CMD, "ABOUT", DrawAboutScn},
  {MENU_TYPE_END_OF_MENU, "", 0}};

MENU LCDMenu[] = {
  {MENU_TYPE_SUB_MENU_HEADER, "LCD MENU", SetupMenu},
  {MENU_TYPE_SUB_MENU, "Intensity", 0},
  {MENU_TYPE_RADIO_BTN, "TimeOut", 0},
  {MENU_TYPE_END_OF_MENU, "", 0}};

MENU TimeDateMenu[] = {
  {MENU_TYPE_SUB_MENU_HEADER, "SET DATE/TIME", SetupMenu},
  {MENU_TYPE_CMD, "Date", RTCAdjDate},
  {MENU_TYPE_CMD, "Time", RTCAdjTime},
  {MENU_TYPE_END_OF_MENU, "", 0}};


// Create an array of pointers to menu buttons
TButton_Round *const MENU_BTNS[5] = {
  &S1_BtnRnd1, &S1_BtnRnd2, &S1_BtnRnd3, &S1_BtnRnd4, &S1_BtnRnd5};


/*------------------------------------------------------------------------------
**  Routine: DispMenu
**  Parameters: Ptr to the menu table to be displayed
**  Return: void
**  Purpose: Display the current menu
------------------------------------------------------------------------------*/
void DispMenu(MENU *MenuTbl)
{
  short i=1;

  // Display menu name in title bar
  S1_Btn_TitleBar.Caption = MenuTbl[0].MenuTxt;
  DrawButton(&S1_Btn_TitleBar);

  // Clear panel
  //DispSpaceClr();

  // Setup caption and event pointer for each menu btn
  while(MenuTbl[i].MenuType != MENU_TYPE_END_OF_MENU)
  {
    // Assign btn captions (ensure max length in vTFT is enough)
    strcpy(MENU_BTNS[i-1]->Caption, MenuTbl[i].MenuTxt);

    // Assign btn events (note, we do not create onClick events for the button in vTFT)
    // MENU_BTNS[i-1]->OnClickPtr = MenuTbl[i].MenuPtr;

    // Assign btn actions for onClick events - depends on menu type
    switch(MenuTbl[i].MenuType) // Determine the menu type
    {
      // Btn pressed on a "Command" menu item
      case MENU_TYPE_CMD:
        // Call the function provided in the menu's table
        MENU_BTNS[i-1]->OnClickPtr = MenuTbl[i].MenuPtr;
      break;

      // Btn pressed on a "Sub-Menu" menu item
      case MENU_TYPE_SUB_MENU:
        // Display the SubMenu
        MENU_BTNS[i-1]->OnClickPtr = void (*DispMenu((MENU *)MenuTbl[i].MenuPtr));    // < Problem is here
      break;
    }

    // Draw btns
    DrawRoundButton(MENU_BTNS[i-1]);

    i++;
  }
}

/* --- User Event Handlers - CMDs --- */

void HistoryCmd(void)
{
  strcpy(S1_Btn_Output.Caption, "NICE WORKS for CMD Type");
  DrawButton(&S1_Btn_Output);
}

void DrawMainScn(void){}
void DrawAboutScn(void){}
void DrawBATScn(void){}
void RTCAdjDate(void){}
void RTCAdjTime(void){}
void TVSChk(void){}


//----------------- End of User code ------------------//

// Event Handlers


// NOTE: The functions below get added as prototypes in Menu_objects.h

/* --- VTFT Event Handlers --- */

void S1_BtnRnd_ChangeMenu_OnClick()
{
  DispMenu(MainMenu);  // Check by showing main menu
}


Post Reply

Return to “Visual TFT General”