Tuesday, July 18, 2017


--- Museums ---

2016

Museums are great places to learn.

Just visiting a museum provides opportunities to pick up things you didn't know before - not too good for picking up practical knowledge or skills. but many museums offer classes, workshops and field trips.

I've never lived in an area that didn't have museums. Most of the museums around Valley, Alabama, where I grew up, were in nearby cities like Opelika, Auburn, and Columbus, but the University at Auburn was packed with museums and I see that at least one old closed mill has been turned into a historic museum in Lanett, Alabama (It's called The Cannery).

Most university buildings maintain displays. I used to enjoy walking through the buildings at Auburn University. The art school was practically an art museum itself, hosting exhibits of the works of well known artists and showing the works of students. Between building were places like the Arboretum and the Eagle mascot's aviary.

Large towns are often cultural centers. Denver is loaded with museums and theaters. Within my hiking range is an outdoor art museum and a great paleontology museum. And then there's Dinosaur Ridge which includes two indoor museums and the side of a mountain.

I maintain a family membership with the Denver Museum of Nature and Science which provides exhibits, films, IMax, a planetarium, crowd sourced research  opportunities, classes, workshops, field trips and entertainment. In the neighborhood is also the Denver Botanic Gardens and the Denver Zoo. It's an easy train ride and hike through Capitol Hill (where the Capitol is) with great examples of architecture, from home to the museum.

I went in search of a more convenient path to the large Walmart in my area. The way I had been taking was a full day's hike. My plan was to walk through River Point shopping area to Oxford Station, catch the train to Englewood Station and walk the short distance from there to the Walmart. It was an improvement and the bonus was that my trail lead through the Denver Museum of Outdoor Arts.

This is a strange concept. There is no one building (though there is a central headquarters and indoor museum) and the museum is scattered all over Denver There is a website (http://moaonline.org/) so you can plan a visit. They even have a walking tour brochure that you can download. I went through the Englewood exhibition in December, so the central piece was a Christmas Tree.






I'll be utilizing the museums of Denver in future blogs and I'll be remembering museums of my past.


--- Intelligence ---

Being a psychologist and retired vocational evaluator, I have what may seem like an embarrassing confession to make. I don't know what "intelligence" is, but I suspect that no one else does either - at least not in any precise way. I'm certainly not sure what an IQ is good for.

I've given many IQ tests, to be sure. I generally gave them for two reasons. First, the schools required them, but I have choice words for that requirement in my reports. That anyone could use the results of a test that can be so drastically influenced by indigestion for purposes of placement - to decide the future track of a person's life - boggles my mind.

I was disillusioned by IQ tests early on. My first client, in fact, was a charming young lady who chatted with me in a witty and smart manner as I stared at her profile that assured me that her IQ was 65. That's a heck of a way to break a vocational evaluator in. After the intake interview I went straight to the behavioral specialist and said, "This can't be right." After a brief interview with the client, the behavioral specialist returned and said, "You're right. I'll retest her." And sure enough, her IQ was 65!

I never trusted an intelligence quotient again.

But I won't say I didn't like IQ tests. My favorite ones were the ones that gave multiple scores. I used them in a more straight forward fashion. Instead of trying to get a blanket score to tell me how well people could solve problems, I looked at the individual scores to see how well people could solve those specific kinds of problems, and then I compared them with scores from other tests, and more importantly, I compared all those scores with what the person had done with their life - their successes and failures, their interests and their dreams, and I pulled all that together into a narrative. No one score could have ever satisfied me when the object under my scrutiny was anything so complex and magnificent as a person.

Uh....there is one other reason I liked IQ tests. They are fun. I like puzzles, so, obviously, I liked IQ tests.

Over the next week or two, I will be reading the Yale-New Haven Teacher's Institute's unit on Human Intelligence: Theories and Developmental Origins (http://teachersinstitute.yale.edu/curriculum/units/2001/6/ last accessed 7/18/2017), and then I'll see if I can find an IQ test that I haven't taken and given so many times I already know the answers by rote (and I'll recommend some that you can take yourself). I expect to have fun.

The first section was written by Dina Pollock and focused on intrapersonal intelligence, which is one of the intelligences mentioned by Howard Gardner in his work on multiple intelligences. Intrapersonal intelligence somewhat calls into question the classical idea that personality is the characteristics that are fairly stable in a person over their lifetime. A skill  included in intrapersonal intelligence is the ability to know self and to guide the development, to some extent, of self.

Most of the exercises suggested by Ms. Pollock are group exercises, which is reasonable since the section is about knowing self and we learn much of what we know about ourselves from other people. But some of the exercises are amenable to individual self exploration. Be careful with "Know your potatoes" if you don't live alone.

I'll add to Ms. Pollock's suggestions the Berkeley Personality Inventory, available in the book "Who Do You Think You Are?" by Keith Harary (the 2nd edition was published in 2005 by Penguin Putnam Trade). This brief personality inventory allows you to explore the way you see yourself (perceived personality) and the way you would like to be (ideal personality), and you can even let others score the inventory for you to see how they perceive your personality (if you dare).

I'm working on a guide for professionals working with therians and I have just finished reviewing a report by the International Anthropomorphic Research Group (Roberts, S. E., Plante, C., Gerbasi, K., & Reysen, S. (2015). Clinical interaction with anthropomorphic phenomenon: Notes for health professionals about interacting with clients who possess this unusual identity. Health & Social Work, 40(2), e42-e50). In their study, they found that furries (people who belong to a culture based on anthropomorphic characters and/or art) use alternate personas to move from the way they see themselves closer to they way they want to be.

I would expect the players of RPGs (Role Playing Games) could use characters created during play to do the same thing. But, then, I know a lot of gamers who intentionally choose characters that are not at all like themselves and are not at all like who they would want to be, as a kind of challenge.

I suspect that RPGs present a very fertile ground for psychological and sociological research.


What is gelato?

Well, for me, it's a small adventure. I've never had gelato before but the ice cream shop down the street sells it so I figure I'd try it.

It's right next to the grocery store and I walk there three or four times a week. One of the advantages of our new house is that the block we're own is bracketed by traffic lights which allows me safe crossing every couple of minutes, which lets me get to the side with sidewalks. Down the street a ways is a patch of lavender that is helping me deal with my mild bee phobia. People in this area like their bees (I'm not so sure I would like them. There are bee collecting bags hanging off many of the trees. No, I'm sure I wouldn't like to be packed into a bag with a bunch of other bees - of course, did I mention my mild bee phobia?)

The Glacier Ice Cream and Gelato shop is a very friendly place. Since they are the ice cream specialists, I asked one of them the other day if they knew how to stop brain freeze - that agonizing headache that results from eating your ice cream too quickly. He recommended pressing my tongue to the back and roof of my mouth. That works pretty well - not perfectly but pretty well.

They have a wide selection of flavors.

My brain tries hard to make gelato have gelatin in it, but I'm told that it doesn't. Gelato just has less butterfat and more sugar than ice cream. The texture is a little different. Being from the South, the "less butterfat" thing isn't a draw for me.

Honestly, in a blind taste test, i don't thing I could tell the difference between gelato and ice cream, which does not detract from this ice cream shop - it's a great place. It just means that I'll always err on the side of a milk shake. I'm pretty crazy about milk shakes - add the butterfat.

Sunday, July 16, 2017

--- Self reference ---

"Does everything have to be about you?"

How many movies have you heard that in?

But maybe it's justified.

Here's another great experiment that you can take part in on the Online Psychology Laboratory. I won't tell you anything about it because, again, anything I told you would ruin your fun and spoil your outcome.

Find it here:

http://opl.apa.org/Experiments/CategoricalList.aspx

under social psychology, and have fun learning about yourself.



--- Crosstabulation ---

2016

Until I figured out how to create stub and banner tables with LibreOffice pivot tables, I was considering making a tabling routine for DANSYSX but that would be redundant, so my focus for crosstabulation became just the 2-way and 3-way statistics programs. Since they are involved and, from scratch, it will give me a chance to talk about my structured approach to developing Calc routines.

XTab is a big (!) matrix function, but it's a sequential function, meaning that it has many procedures that are completed before the next process is started. My first task is to outline the processes with comments. A comment in LibreOffice Basic begins with a single apostrophe. Here, I include a header:

FUNCTION XTab(optional InMat,optional InType, optional CellCont as string,
_)

(It's not complete, because I'll be adding parameters as different procedures require them.) Then, comes a descriptive comment:

'Performs a complete analysis on crosstabulation data
'from a raw data table or a crosstabulation of data.
'The input is the data and the output is a matrix containing
'a stub-and-banner table of cell data followed by
'a table of statistics. InType=1 (Crosstab), 2 (raw data)
'CellCont is a binary string designated data to be displayed in
'cells of output: 10 places: counts, exp counts, row%, column%,
'Total%, residuals, stand. residuals, adj, residuals, chi square,
'likelihood chi square, odds, compare column proportions (Bonferroni).

and a declarations and initialization section:

'Declarations and initialization. If InMat isn't specified,
'InMat=MatArray1. If InType isn't specified, InType=1 (crosstab).
'If CellCont isn't specified, CellCont="100000000000"

DIM OutMat(), Xi(), Yj(), OutR as integer, OutC as integer
DIM I AS INTEGER, J AS INTEGER, K AS INTEGER, L AS INTEGER

That will also grow as I add code. I'll declare other variables in alphabetical order, inserting each as I use them, so I can keep up with names that I've used. Double declarations and accidentally using the same variable for multiple purposes without knowing it can be major headaches.

Then, I know that I'll have to crosstabulate data if a raw data table is fed to the function, so I annotate that section:

'Crosstabulation, if needed.


Redim OutMat(), Xi(1,2), Yj(1,2)

Thinking ahead, I know I'll have to redimension the output matrix when I know what the stub-and-banner part of the display will look like. Everything below that will be pretty straightforward and I can add size as I finish each section. Each section is independent of the ones below it, so I can test each one as I finish it. I have a test data on the Report sheet of DANSYSX that I will use to progressively test each section.

The final section will just display the OutMat matrix which, by that time, will already be constructed by the procedures I have coded. OutMat is a convention I use for all macros that display a matrix.

I will have the crosstabulation saved in MatArray3, just to increase it's utility and make it compatible with the matrix functions I've programmed for DANSYS and DANSYSX.

I use a lot of spreadsheet functions in the program and that's a little tricky. The topic isn't covered in the programming guide, but you can find information online.

To use a spreadsheet function in a Basic routine, you must first declare an object variable to hold the function. You only have to declare it once since you can't use more than one spreadsheet function at a time. I use the same name, svc, and declare it as an object variable:

DIM svc AS OBJECT

Then the variable has to be set as a function variable. That only has to be done once, also.

svc=createUnoService("com.sun.star.sheet.FunctionAccess")

Uno is the object manipulation language used by LibreOffice. This statement invokes a Uno service called FunctionAccess.

After the variable is set, it can be used to call spreadsheet functions such as :

PCS=svc.CallFunction("CHIDIST",Array(CSQW,dfCS))

This statement calls the CHIDIST spreadsheet function. CHIDIST evaluates a chi square value at a specified degrees of freedom value. The CallFunction method for a function variable requires the name of the function as a string (in quotes) followed by the information to be transferred to the function in an array. The function requires a value and degrees of freedom (if you look the function up in the Calc Function Wizard, you can see the structure of the function) to be passed as an array. Even if you pass an array to a spreadsheet function, you have to use the Array statement followed by the name of the array in parentheses. You can see that here:

XMIN=SVC.CALLFUNCTION("MIN",ARRAY(Eij))

in a statement that finds the minimum value in the array Eij.

To get the return value, a variable, PCS, is set equal to the function variable.

One of the aggravating things about LibreOffice Basic is you can't return a matrix like this, which is why I went about programming a complete matrix language for DANSYS.

Displaying the results is easy. I just set the function to the output matrix, like:

XTab=OutMat.

There was some debugging that had to be done, but you can see the final product when I post DANSYSX in the Therian Timeline, here:

http://www.theriantimeline.com/excursions/labbooks

Note: DANSYSX version 1.0 is available now on the timeline.



Saturday, July 15, 2017

I figured the take away for the fourth Indiana Jones movie was, "seems we've reached an age when life stops giving you things and starts taking them away." And the implicit answer is that life can surprise you at any age.

This last relocation was an unpleasant jar but I think we might have come out better. I guess my biggest regret is that, now, we're further from the mountains than I've been since I moved to Colorado. In Broomfield, I was just far enough away that I could walk up to them close enough to be able to spit on them, but then I couldn't go any further. In South Harvey Park, I could walk a little ways into them. Now, on foot, I wouldn't even be able to get close, but, luckily, I'm learning to use the transportation resources around here and the buses and trains can get me places I never could go before.

The good thing is that there is a lot around here. My favorite restaurant is within walking distance. The University of Denver is right up the street and between here and there there is an operating observatory and a line of parks along Harvard Gulch. Also, the bus that stops in front of our house makes a beeline to City Park, which includes the zoo and the science and nature museum. I'm expecting some exciting adventures in my future.

I walked to the local library the second time today. It's an easy walk sans that killer hill above Bear Creek. The area is lushly packed with trees and the walk isn't far. The library is well stocked and, being a part of the Denver library system, cooperates with the other libraries in the area to provide a huge selection of books and other media. They also have an interesting calendar. I expect to be spending a lot of time there. Here's a picture of the Ross-University Hills branch of the Denver Public Library. The building itself is interesting - modern art.



Friday, July 14, 2017


--- A moving experience ---

I have always been interested in community affairs. Among other things I did in Selma, I was a founding member of two community action organizations, the chairperson of a social services quality assurance committee, the temporary president of a disaster relief organization, and a volunteer in several other community organizations. It's no different here in Denver.

In January of 2016, I attended a conference entitled "Talking About the Affordable Housing Crisis: Tools for Delivering Bad News." Now, that would be a funny title if the crisis were not such a disaster. At the time, there was an 80,000 affordable unit deficit and, with property values going up, land owners were evicting tenants so they could refurbish their properties and increase the rents on their houses and apartments. The evicted parties found that they had nowhere to go and whole families were on the street.

Denver has a large homeless population and many of those are evicted tenants. A report by the Denver Foundation in 2015 indicated that one out of ten respondents to a survey to study homelessness had been homeless and one in five had come close. A survey by the Metro Denver Homeless Initiative in 2014 indicated the following causes for the homelessness of respondents: Unemployment (43.9%), Housing costs too high (31.9%), Relationship break up (28.2%), Mental illness (21.3%), and Substance abuse (18.9%). (From "Homelessness in Denver: The Cold, Hard Facts Behind Six Myths" from the Westworld website: http://www.westword.com/news/homelessness-in-denver-the-cold-hard-facts-behind-six-myths-7348310 (accessed 7/13/2017)

I had made two suggestions to reduce some of the homelessness: extended families, and bus tickets to places with lower price of living, more employment, and more affordable housing. I was then an example of how well an extended family works. I was living with 8 others who I considered family, but who were unrelated. Little did I know...

Fast forward to April of 2017, some one had evidently taken a dislike to our extended family because we were informed by a zoning officer that there were too many unrelated individuals living in our house. It was a zoning law that I was not aware of, but there it was. We were being evicted. We were given a month to find a new place in which we would be in compliance with zoning laws, and move.

Digging up the resources, splitting into two households, and finding a new residence was....harrowing, but now, in July, we have settled into a new home. Make no mistake about it, though, it was close.

I believe that one of the problems, though, is that people don't know where to get help. Despite the fact that the zoning laws seem to be archaic and increase the homeless population, Denver is not one of those psychopathic places I have mentioned elsewhere. There are parts of Denver ready to help people in this kind of predicament. For instance, organizations like Colorado Housing Connects and Colorado Legal Services are zealous in helping residents with disputes with their landlords (there is a common perception that, if there is a dispute between a tenant and a land owner, Colorado will always side with the landowner and that there is no help for the tenant). And the local councilman, Kevin Flynn and his assistant Dana MontaƱo, were eager to help us buy the time we needed to make plans and move.

As to the move, I am no longer in the Bear Creek Valley, but I will not be changing the name of my blog, and I will still be spending considerable time along Bear Creek - after all, it's just on the other side of the South Platte River.

Thursday, July 13, 2017


--- Notes on free will ---

What is freedom? It means not being a slave to any circumstance, to any restraint, to any chance; it means compelling Fortune to enter the lists on
equal terms.

Seneca

My position on fortune, destiny, and the like is that we're dealt a hand at the beginning and we can choose how we play our cards. Destiny is at the first, not the last.

As long as free-will remained in the claws of the philosophers (and I include unthinking thinkers like Skinner in that group), humans could not reasonably be said to necessarily have free-will because their every action, every thought was predetermined by their circumstances. The physicists and neuroscientists have reopened the question. That's an odd twist.

As it is, there is too much chaos in the works to be able to say that there cannot be free will.

Freedom, in the language of physicists and statisticians, is the number of directions a thing can move in. They rarely talk about freedom - they talk about "degrees of freedom" - how many different ways can a thing move or change. I get the idea that when people talk about free will, they're talking about the ability of a person to make literally any decision within their physical capabilities. I hope not. Random action is not free will. Free will is the ability to choose between any of a range of rational decisions available to a person. It's the ability to think things out and then decide a course of actions.

Cognition is fuzzy enough to easily allow for free choice. The logical positivism set (may logical positivism rest in peace) wanted to believe that everything was strictly determined - it would make the calculation of everything a lot easier. But then Heisenberg came along with his uncertainty nonsense and put a stop to their dreaming.

I often have recourse to, "That's a good explanation, but not a very good excuse." Serial and mass murderers often have very good reasons for doing what they do. Hate humanity? I can see that. I was mistreated as a child? Yep, so people go through that. Humans taste good? Probably do.

But those are not good excuses. I know too  many people who had horrible childhoods and they grew up to be caring, helpful people. I know too many people who have every reason to hate humanity but, surprisingly, don't. I don't want to hear anyone use their bad temper as an excuse. I have a murderous temper, I can easily go into a berserker's rage, but I don't. People are supposed to develop self-control as a part of growing up. I don't want to hear any one say, "I just couldn't control my sex drive." I'm a satyr and have been plagued with a raging libido since I was 8 years old. If anyone had the right to claim over-active sex drive it would be me, yet I respect other people. Too many minorities grew up to be great people who quite obviously love humanity and live lives that make life worth living for others for other individuals to justify bad actions by, "I was mistreated by The Man."

So I just can't buy the, "I had to do it," or "the devil made me do it," or the "they just caught me in a weak moment," defense. I believe that people do have choice and they're responsible personally for how they use it.



Wednesday, July 12, 2017


--- Me and sociology ---

I've just been through a harrowing sociological adventure (but an adventure, nevertheless) but, being a sociologist, I can easily see the interesting side. See? Sociology does have it's uses. But, before I blog about it, I should cover my own history in sociology.

By the way, it is my intention to maintain a nonadversarial position in these blogs regardless of how painful a topic is. I don't want to slip into blaming. After all, and I will state my position here are honestly as I know how, people are never the problem. Things, situations, faulty procedures are problems. It's not that I believe that there are no bad people. I most certainly do believe that there are bad people, but the solution is to nullify the action of those people.

Also note that I'm slipping into next year's topics, here.

I have always been disturbed by "problem solving" sessions that turn out to be finger-pointing sessions. Bedrock problems are always things and finger pointing always distracts from addressing the real problems.

When I entered Auburn University in the early 70s, my intention was to enter a profession that would allow me to help people who had lost their ability to function get their lives back. I hit on a double major in pharmacy and psychology. I didn't want to be a doctor (nor did I want to take the huge chunk out of my life that it would require) but I did want a strong physiological background. I wanted to understand what I would be working with - the human brain. Pharmacy seemed to be the quickest path between where I was and where I wanted to be. I consider it to have been a good choice even though a series of grueling pharmaceutical chemistry courses caused me to drop out of the pharmacy curriculum a couple of quarters early and transfer to the School of Psychology as a single major.

In the 70s, studying psychology meant that I had to claim a particular school of thought to focus on. There were three such directions at Auburn - behaviorism (which was like a virus at the time pervading everything. Noam Chomsky should be canonized.), personality psychology, and social and industrial psychology. I went the latter route, and I also minored in sociology. Again, I don't regret the choice.

After graduation, I took a very enforced hiatus. My autoimmune problems settled in my knees and put me out of operation from April (the problem flared up on Easter Sunday), to November, when I received a letter from Auburn inviting me to apply for their Rehabilitation and Special Education graduate school. This opened a dream opportunity for me. I hated the you-have-to-choose-a-school mentality in psychology and there was no integrative psychology options available back then. Rehabilitation was as close to integrative psychology as there was. A years work placed me into the profession I had been looking for. I worked with individuals as a rehabilitation specialist and professionalism required that I serve my community, so I had plenty of opportunity to help build and develop communities.

So, if I'm a sociologist, do I have any distinctive characteristics as a sociologist that sets me apart from other sociologists and that I should warn you about?

Well, sociologists like me look at cities, towns, families, churches, etc. as individuals in their own right. Cities, for instance, have bodies, minds, souls, spirits as much as individual humans do. They can be healthy, be hurt, be sick, be happy or sad, just like any individual. Cities have egos, subconsciouses, administrative functions. They can be mentally ill and they can sometimes be scary people. They can be nurturing, caring people.

Also, I'm a shaman, which brings the group and the individual more solidly together. Whereas doctors treat individuals, and psychologists sometimes treat small groups, shamans are concerned about both their communities and the people that make them up.

So, how can cities, the groups that make them up, and the people that live there all be individuals? Simple answer: we're colonial animals - like volvox. All the cells in a volvox are individual animals. The volvox itself is also an individual animal.


Tuesday, July 11, 2017


--- Graphics ---

2016

One of my more frustrating programming episodes occurred with one of OpenOffices updates. I tried to install the new version and it wouldn't install. The suggestion on the user forum was to uninstall the older version and then try to install the new version. The new install still didn't work so I had no working version of OpenOffice and a lot of work on DANSYS that I had not saved. Dumb of me - irritating of OpenOffice. That was when I decided to junk OpenOffice and switch to LibreOffice.

The biggest loss was a set of programs I had put a lot of work into that expanded the ability of OpenOffice Calc to produce statistical graphs. They constituted a graph building suite. Instead of creating a set of predesigned graphs (as with the charts currently produced by Calc), I could build graphs from elements such as axes, points, lines, and such. I decided to ditch the idea. I just didn't have the heart to redo all that work, and I had other programs that would produce all the statistical graphs I would ever need.

But then I started thinking (often a big mistake, but one that often leads to adventure) that it would be nice to have DANSYSX be able to generate some simple graphics. Points and lines and such are useful for a lot more than making statistical graphs.

One limitation of spreadsheet functions is that they can only output data into cells, so I couldn't use functions to generate geometrical objects on a spreadsheet. I would have to use subroutines, and thus commands, to do the job, and that meant creating a menu of graphical commands.

I also wanted to be able to translate the positions of the geometrical objects into a specified area - a frame. I had done that with the OpenOffice commands, so I should be able to do it again for LibreOffice.

This is a different kind of programming than creating a function to output a value or matrix of values. I had to actually place objects on a spreadsheet. That meant that I had to have the program determine where everything had to go and place it there. LibreOffice Basic can do that and I'll show you the frame routine. You can find the others in the Graphics folder of the DANSYSX macros.

One thing I remember doing over and over in the older programs was translating data points from one range (the range of data values) to another (the range of positions on a frame on a spreadsheet). That got old, so, this time I created a very simple function to do that. It looks like this:

Function Rescale(c,a,b,y,z)
'Rescales a value, c, between a and b to be proportionally
'between y and z)
Rescale=(c-a)*(z-y)/(b-a)+y

End Function

That was easy and, if you went through the article, DANSYSX: Complex cubic equations, you know what that all means.

The way I had the older macros work is that the user would create a specification form on a spreadsheet for a specific object, fill it out, process the specifications, and then display the object on the spreadsheet.  I've trimmed this four step process down in DANSYSX except for the frame. You still have to process the specifications for the frame. A frame has to be generated (whether it's displayed or not) so LibreOffice knows where to place the graphics object.

The Specification routine is tedious (there's a lot of information required to specify the frame) but straightforward. A frame is just a rectangle. Draw a rectangle and you have a frame that you can situate everything else on.

The only complication is that I need different specifications according to the kind of background to have on the frame, so I had to work up a dialog to select the kind of background before printing the specification form.

Here is the specification routine:

SUB FrameSpec()
'Prints out a frame specification form onto a spreadsheet
'beginning at the current cell.
DIM I AS INTEGER, J AS INTEGER
DIM RP, CP, DLG AS OBJECT, STL AS INTEGER, LBX AS OBJECT
DIM oDoc AS OBJECT, oSheet AS OBJECT, oSel AS OBJECT
DIM addr AS OBJECT, M AS INTEGER, N AS INTEGER
DIM oCell AS OBJECT, oView AS OBJECT



'Display dialog Frame

DialogLibraries.LoadLibrary("Standard")
DLG=CreateUnoDialog(DialogLibraries.Standard.Frame)
DLG.Execute()


LBX=DLG.getControl("ListBox1")
STL=LBX.SelectedItemPos

IF DLG.Execute()=0 THEN EXIT SUB


'Print form
 oDoc=ThisComponent
 oView=ThisComponent.getCurrentController()
 oSheet=oView.getActiveSheet()
 oSel=oDoc.getCurrentSelection
 addr=oSel.getRangeAddress()

 m=addr.StartRow
 n=addr.StartColumn

oCell=oSheet.getCellByPosition(n,m)
oCell.String="Frame"
oCell=oSheet.getCellByPosition(n,m+1)
oCell.String="Position 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+2)
oCell.String="X"
oCell=oSheet.getCellByPosition(n+1,m+3)
oCell.String="Y"
oCell=oSheet.getCellByPosition(n,m+4)
oCell.String="Size 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+5)
oCell.String="Width"
oCell=oSheet.getCellByPosition(n+1,m+6)
oCell.String="Height"
oCell=oSheet.getCellByPosition(n,m+7)
oCell.String="Margins: 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+8)
oCell.String="Top"
oCell=oSheet.getCellByPosition(n+1,m+9)
oCell.String="Bottom"
oCell=oSheet.getCellByPosition(n+1,m+10)
oCell.String="Left"
oCell=oSheet.getCellByPosition(n+1,m+11)
oCell.String="Right"
oCell=oSheet.getCellByPosition(n,m+12)
oCell.String="Caption"
oCell=oSheet.getCellByPosition(n+1,m+13)
oCell.String="Top"
oCell=oSheet.getCellByPosition(n+1,m+14)
oCell.String="Bottom"
oCell=oSheet.getCellByPosition(n+1,m+15)
oCell.String="Left"
oCell=oSheet.getCellByPosition(n+1,m+16)
oCell.String="Right"
oCell=oSheet.getCellByPosition(n,m+17)
oCell.String="Transparency: percent"
oCell=oSheet.getCellByPosition(n,m+18)
oCell.String="Border"
oCell=oSheet.getCellByPosition(n+1,m+19)
oCell.String="Line Style: NONE, SOLID, DASH"
oCell=oSheet.getCellByPosition(n+1,m+20)
oCell.String="Line Color: RGB"
oCell=oSheet.getCellByPosition(n+1,m+21)
oCell.String="Line Transparency :percent"
oCell=oSheet.getCellByPosition(n+1,m+22)
oCell.String="Line Width: 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+23)
oCell.String="Line Joint: NONE, MIDDLE, BEVEL, MITER, ROUND"
SELECT CASE STL
CASE=0
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Background: NONE"
CASE=1
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Background: SOLID"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="Red"
oCell=oSheet.getCellByPosition(n+1,m+26)
oCell.String="Green"
oCell=oSheet.getCellByPosition(n+1,m+27)
oCell.String="Blue"
CASE=2
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Background: HATCH"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="Style: SINGLE, DOUBLE, TRIPLE"
oCell=oSheet.getCellByPosition(n+1,m+26)
oCell.String="Color: RGB"
oCell=oSheet.getCellByPosition(n+1,m+27)
oCell.String="Distance: 1/100 mm"
oCell=oSheet.getCellByPosition(n+1,m+28)
oCell.String="Angle: 1/10 degree"
CASE=3
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Bitmap - Named"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="Name"
oCell=oSheet.getCellByPosition(n+1,m+26)
oCell.String="Style: REPEAT, STRETCH, NO_REPEAT"
CASE=4
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Bitmap - URL"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="URL"
CASE=5
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Gradient - Named"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="Name"
CASE=6
oCell=oSheet.getCellByPosition(n,m+24)
oCell.String="Gradient - Custom"
oCell=oSheet.getCellByPosition(n+1,m+25)
oCell.String="Style: LINEAR, AXIAL, RADIAL, ELLIPTICAL, SQUARE, RECT"
oCell=oSheet.getCellByPosition(n+1,m+26)
oCell.String="Start Color: RGB"
oCell=oSheet.getCellByPosition(n+1,m+27)
oCell.String="End Color: RGB"
oCell=oSheet.getCellByPosition(n+1,m+28)
oCell.String="Angle: 1/10 degree"
oCell=oSheet.getCellByPosition(n+1,m+29)
oCell.String="X Offset: 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+30)
oCell.String="Y Offset: 1/10 mm"
oCell=oSheet.getCellByPosition(n+1,m+31)
oCell.String="Start Intensity: percent"
oCell=oSheet.getCellByPosition(n+1,m+32)
oCell.String="End Intensity: percent"
oCell=oSheet.getCellByPosition(n+1,m+33)
oCell.String="Step Count: number of color graduations"
END SELECT

It's long but fairly simple. It does illustrate how you can get things from a program onto a spreadsheet, though. Let's look at the sections.

Variables can be set to hold things like documents, sheets, cells, ranges, shapes, and such but they have to be declared as objects. This program uses several object variables.

DialogLibraries.LoadLibrary("Standard")
DLG=CreateUnoDialog(DialogLibraries.Standard.Frame)
DLG.Execute()


LBX=DLG.getControl("ListBox1")
STL=LBX.SelectedItemPos

IF DLG.Execute()=0 THEN EXIT SUB

This section displays the dialog that has the list box of styles for backgrounds. I constructed the dialog in the dialog editor (Select Macro>Organizer>Dialogs tab) with a listbox (I specified the items in the listbox in the properties settings for the listbox.), a Okay button, and a Cancel button. Here's what the dialog editor looked like:



"DialogLibraries.LoadLibrary("Standard")" loads the library that contains the Frame dialog.
"DLG=CreateUnoDialog(DialogLibraries.Standard.Frame)" sets the DLG object variable to contain the Frame dialog.
"DLG.Execute()" displays the dialog. As long as the dialog is displayed and working, nothing else runs in Calc.
"LBX=DLG.getControl("ListBox1")" loads the listbox1 control into object variable LBX and "STL=LBX.SelectedItemPos" gets the selected text string from the listbox1.
"IF DLG.Execute()=0 THEN EXIT SUB" specifies that, if the Cancel button is clicked (which generates a 0 from the DLG object), that the subroutine is closed without doing anything.

 oDoc=ThisComponent
 oView=ThisComponent.getCurrentController()
 oSheet=oView.getActiveSheet()
 oSel=oDoc.getCurrentSelection
 addr=oSel.getRangeAddress()

 m=addr.StartRow
 n=addr.StartColumn

The oDoc variable is set to contain the document that is currently open (DANSYSX)
The oView variable is set to contain the current documents view.
The oSheet variable is set to contain the currently active sheet in the view of the document.
The oSel variable is set to contain the currently active range (in this case, just one cell, the top left cell intended to start the Frame form.)
The addr variable contains the address structure of oSel. It contains the starting and ending cell row and columns as a data structure.

Data structures are addressed by the name of the data structure (in this case addr) followed by a period and the name of the specific value to be accessed. For instance, addr.StartRow returns the value of the StartRow value in addr. The integer variable m is set to the StartRow value and the integer variable n is set to the StartColumn value.

The rest of the subroutine is just a long list of statement of the form:

oCell=oSheet.getCellByPosition(n,m)
oCell.String="Frame"

Here, the oCell variable is set to the cell at column n and row m on the currently active sheet. Notice that cell positions are opposite to matrix positions. Matrix positions are addressed by (row,column); cell positions are addresses by (column, row) order. This is in keeping with the way cells are addressed on spreadsheets. A cell at position C5 is at column C and row 5. It's also not obvious here, but the first row on a spreadsheet is row 0, and the first column is column 0.

I use a Select Case structure to decide the labels to output onto the spreadsheet according to which background style is chosen. The Select Case structure works like this:

SELECT CASE (statement)
CASE (value)
CASE (value)
...
CASE (value)
END SELECT

The statement in the first line specifies what the following case values refer to. In this example, the case is the value of STL, the numerical position of the selected style in the dropdown list of the dialog. The first CASE statement is CASE 0, which is the value of the first item, NONE, in the list. If STL=0, the block of statements following CASE 0 is executed and, then, the other case statements are ignored. END SELECT marks the end of the Select Case structure. Notice that the Case values can be numerical or string values, inequalities like >5 or <=3, or statements like "between 2 and 5".

When this routine is run from the Graphics menu>FrameSpec, a form is printed onto the active spreadsheet beginning at the selected cell. This form can be filled in to specify a frame for other graphic objects.

Saving all this information so that it doesn't go away between sessions requires that I construct a hidden spreadsheet to save it on. You can see that by unhiding the Graphics sheet in DANSYSX. Right click on any sheet tab and select the Show Sheet... command. It will open a list of hidden sheet. Double click Graphics. Be careful and don't change anything. You'll the information generated by the FrameSpec command in the top part of the sheet. Below that, though, are several calculated value. These are values necessary to scale values to the frame, taking margin specifications into account.

The FrameGen command transfers information from the frame table to the FrameSpec sheet. It uses much of the same Basic and Uno commands but there are two sheets to deal with, the sheet the table is on and the FrameSpec sheet. You will recognize most of the code if you look at it.

This pattern is repeated a lot.

oCell=oSheet.getCellByPosition(n1+1,m1+0)
aCell=aSheet.getCellByPosition(1,0)
aCell.Value=oCell.Value

That, of course, transfers the information from the first column to the right and top row of the frame table to the first column and top row of the Frame Spec sheet. These lines are quite simple but tedious to write. Luckily, there is a lot of cut, paste, and modification going on.

There is an interesting little subroutine tagged onto the end that parses out a string of color specifications. Here, color is specified by three numbers from 0 to 225 specifying how much red, green, or blue is used to create the color desired. The subroutine is called using the statement:

GOSUB FG10

The cell containing the string is first specified as aCell. The subroutine has to come after the last line of the main subroutine:

EXIT SUB

and it must begin with the calling label. Here is the subroutine:

FG10: 'RGB subroutine. Sets R, G, and B.
RGBSTR=aCell.String
Clr=""
S=1
FOR I=1 TO LEN(RGBStr)
Clr=Clr & MID(RGBStr,I,1)
IF MID(RGBStr,I,1)="," OR I=LEN(RGBStr) THEN
IF S=1 THEN
R=Val(Clr)
ELSEIF S=2 THEN
G=Val(Clr)
ELSE
B=Val(Clr)
END IF
S=S+1
Clr=""
END IF
NEXT I

RETURN


 END SUB

The string in aCell is transferred into the RGBStr variable and the following loop structure takes the string apart, converting the parts between the commas into numerical values stored in the R, G, and B variables. The last line of the subroutine is RETURN, which switches processing back to the line immediately following the last GOSUB statement. Finally, the whole macro is closed out using the END SUB statement.

More than one subroutine with different line labels can be placed at the end of a macro, but they all have to come before the END SUB or END FUNCTION statement.

The FrameShow command acually places the graphics frame on the spreadsheet. It is just a drawn rectangle and the LibreOffice Basic Programmer's Guide very adequately explains how to code for various drawn shapes and I will direct you to that since there are a lot of possibilities, but I will point out a few things that it doesn't make terribly clear.

First, every spreadsheet has it's own drawing page. In Draw and Impress, this is pretty explicit, but not for Calc. The way the drawing page for the active sheet is specified is:

oSheet = aDoc.getcurrentcontroller.activesheet
DPAGE=oSheet.DrawPage

The first line defines the active sheet and loads it into an object variable (oSheet). The second loads the drawing page of oSheet into another object variable called DPAGE. Later, the frame, which is a rectangle stored in the object variable oRect, is placed on the drawing page by the following line:

DPAGE.add(oRect)

The frame is built up by sequentially adding the frame and all the specified captions (which are rectangles with text) with similar commands.

Other commands to create points, lines, ellipses, and boxes will be very similar. They will all be in the Graphics folder of the DANSYSX macro library.