home *** CD-ROM | disk | FTP | other *** search
- Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news!uhog.mit.edu!news.mathworks.com!newshost.marcam.com!usc!howland.reston.ans.net!europa.chnt.gtegsc.com!newsfeed.internetmci.com!news.sprintlink.net!simtel!harbinger.cc.monash.edu.au!yarrina.connect.com.au!warrane.connect.com.au!godzilla.zeta.org.au!not-for-mail
- From: grove@zeta.org.au (Rachel Polanskis)
- Newsgroups: comp.os.msdos.programmer.turbovision,comp.answers,news.answers
- Subject: C++ Turbo Vision FAQ, part2/3
- Followup-To: poster
- Date: 15 Aug 1995 01:11:16 +1000
- Organization: Kralizec Dialup Unix Sydney, +61-2-837-1183 V.32bis
- Lines: 1453
- Approved: news-answers-request@mit.edu
- Message-ID: <40np2k$jms@godzilla.zeta.org.au>
- NNTP-Posting-Host: godzilla.zeta.org.au
- Summary: This article is a compilation of information on the use of,
- and resources for, Turbo Vision for C++ (Borland's application
- framework).
- Xref: senator-bedfellow.mit.edu comp.os.msdos.programmer.turbovision:5085 comp.answers:13671 news.answers:50723
-
- Archive-name: C++-faq/turbovision/tvplus/part2
- Posting-Frequency: monthly
- Last-modified: 1995/08/14
- Version: 1.8
- URL: http://www.zeta.org.au/~grove/tvhome.html
-
-
-
- -----------------------------------------------------------------------
- TECHINFO
- -----------------------------------------------------------------------
-
- Borland International makes technical advice available through a series
- known as TechInfo, abbreviated as TInnnn. The series is not limited to
- TV and covers other topics relevant to Borland products. Each issue
- covers a specific topic.
-
- All issues in this series mentioning Turbo Vision are listed here.
-
- TI1006 Overlaying Turbo Vision 1992.08.12
- TI1011 Modal and Modeless Dialog Boxes using Turbo Vision 1992.08.12
- TI1013 Making string lists using Turbo Vision 1992.08.12
- TI1020 Understanding & Using Turbo Vision's Palette 1992.08.21
- TI1021 How to extract text from a TEditor Buffer 1992.10.23
- TI1022 Initialization Order of Objects & Turbo Vision 1992.12.03
- TI1023 Persistent Objects using Turbo Vision 1992.12.23
- TI1025 Optimizing Screen Updates with Turbo Vision v3.1 1992.12.23
- TI1033 Example of derived TListViewer for Turbo Vision 1992.12.23
- TI1158 A modal dialog from a modal dialog with Turbo Vision1992.11.11
- TI1159 Graying Buttons with Turbo Vision 1992.11.11
- TI1160 Dynamically modifying Turbo Vision menus1992.12.03
- TI1296 Using Turbo Vision resource files 1993.10.25
- TI1297 Example of password entry using a TInputLine 1993.10.25
- TI1369 Changing the color of shadows in Turbo Vision 1993.10.25
- TI1395 How to use HeapView in a Turbo Vision program 1993.10.25
- TI1398 tools.h++ from Rogue Wave conflicts with Turbo Vision 1993.10.25
- TI1532 Continuously updated message box in Turbo Vision1992.12.03
- TI1541 Using cmReleasedFocus message to update a dialog box 1993.10.25
- TI1549 Switching between text video modes in Turbo Vision 1993.10.25
- TI1552 Turbo Vision example of determining cursor position 1993.10.25
- TI1553 How to override freeItem for Collections 1993.10.25
- TI1554 Context sensitive help example (Turbo Vision) 1993.08.30
- TI1555 Example of a restricted InputLine (Turbo Vision) 1993.10.25
- TI1557 Creating red error dialog boxes in Turbo Vision 1993.10.25
- TI1558 Saving/Restoring the mouse state in Turbo Vision 1993.09.01
- TI1701 Turbo Vision: Streaming a user defined dialog 1993.10.07
- TI1707 Broadcast to close a Turbo Vision Modeless Dialog 1993.10.12
- TI1708 Using setData to initialize dialog box contents 1993.10.25
- TI1712 Turbo Vision Dialog Box (Modal/Modeless) Examples 1993.10.25
- TI1720 How to disable a button in Turbo Vision 1993.10.25
- TI1730 Inserting text into a Turbo Vision window 1993.10.21
- TI1752 Rebuilding Turbo Vision 1.0x with Borland C++ 4.0 1994.01.13
- TI1753 Using Turbo Vision 1.0x with Borland C++ 4.0 1994.01.13
- TI1773 How to build DOS applications in Borland C++ 4.0 1994.01.25
- TI1778 Common questions and answers about Borland C++ 4.0 1994.02.17
-
- These text files have been bundled together under the name
- techinfo.zip for an easy download from the TVPlus ftp site.
-
- -----------------------------------------------------------------------
- CDROM SOURCE CODE
- -----------------------------------------------------------------------
-
- There are commercial compilations of source code and code snippets
- written in various programming languages. The compiler (of the human
- variety) will obtain material from various locations and sites for
- distribution as CDROM collections.
-
- There are CDROM collections that include TV code. Such compilations can
- greatly facilitate programming by providing consolidations of sources,
- snippets, hints and tools. Much of the material is shareware; some of it
- in the public domain.
-
- These compilations are a useful service provided that they do not breach
- copyright. However, there are numerous CDROM services which are
- advertised in computer magazines and which you can easily select without
- recommendations from here.
-
- -----------------------------------------------------------------------
- The discussion list
- -----------------------------------------------------------------------
-
- The Turbo Vision discussion list is run as an unmoderated site from
- Virginia Polytechnic Institute ('Virginia Tech'), Blacksburg, Virginia
- USA.
-
- To subscribe to the discussion list:
-
- Send a message to Listserv@vtvm1.cc.vt.edu
- Leave the subject header blank if you wish
- In the body of your message, type the command:
- SUBSCRIBE TURBVIS <your name>
-
- Expect confirmation of your subscription and a list of additional
- Listserv commands which you should keep handy.
-
- Any question about Listserv should be addressed to your system
- administrator.
-
- To send a message to the discussion list:
-
- Post your message to Turbvis@vtvm1.cc.vt.edu
- Do not use this address to subscribe or unsubscribe
- to the discussion list because, if you do, everyone
- will get the commands intended only for Listserv.
-
- Note the distinction between Listserv and Turbvis - commands are sent to
- Listserv; messages, to Turbvis.
-
- Check on posting to the discussion list before doing so.
-
- To unsubscribe to the Turbo Vision discussion list:
-
- Send a message to Listserv@vtvm1.cc.vt.edu
- Leave the suject header blank if you wish
- In the body of your message, put the command:
- UNSUBSCRIBE TURBVIS <your name>
-
- -----------------------------------------------------------------------
- UseNet News
- -----------------------------------------------------------------------
-
- A Usenet newsgroup is a collection of the communications of various
- subscribers about a predefined topic.
-
- SELECTING NEWGROUPS
-
- We have divided the newsgroups into four sections, moving from the most
- to the least relevant:
-
- special interest: about Turbo Vision itself
- programming: about your language of choice and other programming
- subjects
- various topics: about all manner of things that may, or may not,
- be relevant
- Usenet operations: about netiquette and other hints (good for
- newbies).
-
- After selecting a newsgroup in which you are interested, you will be
- presented a list of topics currently under discussion within that group.
- Go for it.
-
- Application framework
-
- Just after the discussion group on TV went on line towards the end of
- 1992, this news group was established with a link to the discussion
- list. It covers both the C++ and Pascal language version of the
- software.
-
- comp.os.msdos.programmer.turbovision
-
- Language
-
- It goes without saying that using the TV library will not make you self
- sufficient in techniques or programming tools. These groups present an
- opportunity to look further afield into the C++ language as a related
- subject.
-
- alt.msdos.programmer
- comp.lang.c++
- comp.lang.c++.moderated
- comp.msdos.programmer
- comp.os.msdos.programmer
- comp.std.c++
-
- Reference
-
- The following sites are somewhat chaotic, catch all sites and are
- included on the basis that they specialise in FAQs on diverse topics.
- They may be a bit like a junk shop but you are more than likely to find
- a treasure or two - they are quite useful as a starting point in your
- research on all kinds of interests.
-
- comp.answers
- news.answers
- UseNet news
-
- Usenet and its operation
-
- news.announce.newusers
-
- The purpose of this newsgroup is to discuss Usenet and the way it
- operates. Questions about netiquette, the Usenet FAQ, posting rules
- and similar matters can be put to this group.
-
- USING NEWSGROUPS
-
- Each newsgroup has its own area of expertise and going outside this area
- could bring down the wrath of the regulars. They like to keep the topic
- tight and you should check to see if the subject you want to discuss is
- pertinent to the particular group.
-
- In any event, it is to your own advantage to ensure you have the right
- group for your posting as you will get a better answer from those
- experienced in the subject than from someone who is merely acquainted
- with the topic.
-
- Do not post test articles to an active newsgroup. Find a test group such
- as alt.test designated for this purpose.
-
- Also see about posting to the Turbo Vision discussion list.
-
-
- How
-
- As TV is produced in two language versions, postings to
-
- turbvis@vtvm1.cc.vt.edu or
- comp.os.msdos.programmer.turbovision
-
- should bear a subject header that readily identifes the language version
- if applicable to the topic under discussion. It make life a little
- easier - it helps communication and gets the information sought in one
- pass.
-
- When
-
- Before you resort to the net for a solution to your code problem, make
- sure you have done your homework and have been through the following
- steps:
-
- read the manual (it may happen to be lucid on your
- particular problem);
-
- check ..\turbovision\demos and ..\turbovision\docdemos of TV;
-
- browse through the examples from ftp://ftp.borland.com;
-
- read the source code if you have it;
-
- refer to the relevant FAQ which is, in this case, TVPlus; and
-
- try to resolve the difficulty using whatever resources you have
- available.
-
- Where
-
- If you still cannot solve the problem, post a question to
-
- turbvis@vtvm1.cc.vt.edu if you have access to e-mail or
-
- comp.os.msdos.programmer.turbovision if you only have
- access to UseNet News.
-
- -----------------------------------------------------------------------
- Handy ftp sites
- -----------------------------------------------------------------------
-
- GENERAL FTP SITES
-
- These archives contain collections of files that may be of
- interest and that may have duplicate material from other sites;
- but there are some unique items at each site as well.
-
- ftp://ftp.borland.com
- This site was dis-organised early in 1995. There are Turbo Vision
- files to be found at /pub/techinfo/techdoc/language/c++/bcpp - if
- you can detect which one are TV. The LARN like maze to
- /pub/techinfo/techdoc/language/c++/bcpp/ti contains the TI
- series.
- ftp://ftp.ee.und.ac.za
- Of special interest here are a graphical version of TV and
- patches for porting TV to other compilers. This site is very slow
- if you are accustomed to US ftp speeds.
- ftp://ftp.pharlap.com
- This site contains patches for the Pharlap DOS extender to work
- with TV.
- ftp://garbo.uwasa.fi
- This is the Garbo Archives sited in sunny Finland. There are
- libraries for database applications and C++ sources which are
- suitable for use with TV.
- ftp://oak.oakland.edu
- This is a popular site for all kinds of code. The turbovis
- directory contains code listings for C++ TV1.03 and TV2.0 (and
- Pascal Turbo Vision).
- ftp://vtucs.cc.vt.edu
- This site, amongst other things, archives the Turbo Vision
- discussion list and comp.os.msdos.programmer.turbovision for both
- the C++ and Pascal versions of TV.
- CompuServe
- CompuServe is one of many commercial alternatives to the Internet
- which contains a Turbo Vision forum. For the information of CIS
- customers, the TV files are located at BCPPDOS Library 11.
-
-
- SPECIALIST FTP SITES
-
- This group of archives is devoted to a rather narrow purpose in
- that they usually contain files that have originated from one
- author or relate to one application.
-
- DosLynx Project: Kansas University <doslynx@falcon.cc.ukans.edu>
- ftp://ftp2.cc.ukans.edu/pub/WWW/DosLynx/ The self-extracting
- archive file name is DLX0_8A.EXE; the source file name is
- SCR0_8A.ZIP.
- Nelson, Roger <rnelson@mail.wsu.edu>
- ftp://iris1.bsyse.wsu.edu There are five directories which may
- be of interest to TV programmers: ../pub/rvision (Pascal and C++
- library), ../pub/rlib ../pub/language ../pub/latex2hyp
- (LaTeX2hyp) and ../pub/ucscu
- Nelson, Roger
- http://www.eecs.wsw.edu/coea The URL for WWW access to the site
- referenced above.
- Sierwald, Joern <sierwald@tu-harburg.d400.de>
- ftp://uni-stuttgart.de/pub/systems/os2/programming/support
- Patches to support TV with compilers other than Borland C++.
- Werthy, William (Bill) <billw@eskimo.com>
- ftp://ftp.eskimo.com This site contains NEWSWERTHY, a TV offline
- reader.
-
- TVPLUS FTP SITE
-
- TV files mentioned in TVPlus, and a few others besides, are
- available from this site. The original file collection resulted
- from the research of Rachel Polanskis and is presented with our
- compliments; others have added to it.
-
- ftp://ftp.zeta.org.au
- At present, limited access. TVPlus is archived here; there
- is a selection of TV C++ files, some related C++ files and other
- programming tools available from this site.
-
- File list
-
- The + indicates a new addition since the last change.
-
- altf1.zip: allows user to go back one page in help window
- b31tv2.zip: use TV2 with BC++ 3.1 (not protected mode)
- bc31tv2.zip: use TV2 with BC++ 3.1
- bc40tv.zip: use TV1.03 with BC++ 4.x
- blakbl.zip: implements black text on a black background
-
- clkclk.zip: click alternates clock between 12 and 24 h time
- colord.zip: permits you to change the palette easily
- colorsel.zip: selector dialog for application colours
- csdude.zip: demo of TV and PXEngine, use with pmapp.zip to test
- dbfram.zip: TV and PXEngine sample classes for input/output
-
- desklogo.zip: draw a background logo on desktop
- dlgdsn46.zip: dialog design tool
- dpmxcp.zip: DPMI Exception Handler Library for TV 2.0
- dskstr.zip: how to stream desktop objects to file
- dumb.zip: class for a dumb terminal object
-
- dyntxt.zip: dynamic version of TStaticText
- ezhint.zip: demonstrates how to put hints on the status line
- facetv.zip: advanced gadgets for TV; very interesting
- farvt.zip: how to use far virtual tables in TV
- fredtv.zip: TV library from BI (not tested)
-
- gfx210.zip: excellent graphics library for Turbo Vision
- gvision.zip: Oliver Suciu's port of TV to g++
- inplis.zip: edit a TListBox item using a TInputLine
- kvbugs.zip: a bug list with many fixes for TV and BC
- listvi.zip: control multiple lists with a common scrollbar
-
- makerez.zip: sample code for making resource file
- mdbeep.zip: TV2, beeps on mouse click outside specified area
- menunest.zip: example of cascading menu items
- mibxb3.zip: message input box replacement, many features - BC3.1
- mibxb4.zip: message input box replacement, many features - BC4.x
-
- mmagic.zip: generates menus
- msgcls.zip: a status box like the IDE's and a message window
- msglin.zip: messages put to the status line
- msgs.zip: message passing from a dialog to a window
- multbo.zip: mark multiple items in a collection - toggle values
-
- ntest.zip: for TVDT users, TMemo shoehorned into TView
- option.zip: TCollection for a picklist similar to THistory
- passwd.zip: password dialog and simple algorithm
- phelp.zip: complete shareware replacement for TV's help system
- pmapp.zip: TV1.03 and BC3.1 in protected mode - complete sources
-
- printq.zip: background printer object
- progba.zip: progress bar utility
- pxlist.zip: how to implement pxeng with TListBox
- radio.zip: fix memory problem for large radio button cluster
- readrez.zip: sample code reading a resource file
-
- savepal.zip: save and restore palette as resource
- scrnsave.zip: demonstrates a screen saver using ISR routines
- sdlg.zip: scrolling dialog box
- sdlg2.zip: scrolling dialog box - revision
- sg.zip: Turbo Vision Study Guide - teaches TV
-
- spread.zip: spreadsheet like object
- strmfx.zip: TObjstrm patch for the library
- sysfix.zip: sysint.asm patch for the library
- sysint.zip: sysint.asm patch for the library
- tcombo.zip: a streamable combo box
-
- techinfo.zip: the Borland TechInfo series on TV
- testhelp.zip: demo of help system with commentary
- tde.zip: class extensions from TInputLine
- tdtxt1.zip: updates tde.zip
- tkeys_h.zip: uses CTRL- key hotkey combinations
-
- togmnu.zip: allows toggled items to appear in a menu
- tlang.zip: how to change language at runtime dynamically
- tpictu.zip: derived from TInputLine, a PDX style picture class
- tprogb.zip: another progress bar utility
- tpicture.zip: input line Paradox style
-
- ttlbar.zip: adds a title bar above the menu bar
- ttywin.zip: TTY style class implementation
- tv_bc4.zip: how to patch TV1.03/BC4.x
- tv-mc3.zip: how to use Memcheck with TV1.03
- tv_may.zip: patches TV1.03 for PharLap DOS extender
-
- tv103inf.zip: differences between TV 1.0 and TV 1.03
- tv286_v6.zip: pharlap DOS extender patches for TV1.03
- tv286_v7.zip: similar to above but in diff format
- tv2dll.zip: patches source code to convert TV to DLL
- tv2dll2.zip: further source code on converting TV to DLL
-
- tv2dll3.zip: further comment on converting TV to DLL
- + tv2bug.zip: the latest bug release for TV2 (1995.06.07)
- tv2pat.exe: more patches for TV2.0
- tv2val.zip: validation classes for TV2.0
- tvalid.zip: field validation object
-
- tvalid2.zip: field validation object - later version
- tvalt.zip: graphics library for Turbo Vision
- tvalt2tx.zip: alternate to tvalt.zip (originally tvalt2.txt)
- tvapform.txt: plain text proforma - applications catalogue entry
- tvbugs.zip: the current bug list for TV 1.03 February 1994
-
- tvcolr.zip: dynamic selection of palette
- tvdbf.zip: scrollbar using long, not ushort - PXEngine demo
- + tvdpmxcp.zip: TV DPMI exception handler for BC4.x and TV2
- tvdprj.zip: project file for BC4.x
- tvfix.zip: older patches for TV1.03
- tvg121.zip: library of graphics routines
-
- tvhint.zip: demonstrates how to put hints on the status line
- tvicon.zip: example of making windows iconic
- tvmemchk.zip: memory checking utility for compiling
- tvmemo.zip: memo implementation of THistory
- tvoprj.zip: BC4.x project for TV1.03 overlays
-
- tvpal.zip: palette routines for TV
- tvpatch.zip: Joern Sierwald's patches
- tvplus01.zip: TVPlus 1(1995)1 ie, as at January 1995
- tvplus02.zip: TVPlus 1(1995)2 ie, as at Febuary 1995
- tvplus03.zip: TVPlus 1(1995)3 ie, as at March 1995
-
- tvplus04.zip: TVPlus 1(1995)4 ie, as at April 1995
- tvplus05.zip: TVPlus 1(1995)5 ie, as at May 1995
- tvplus06.zip: TVPlus 1(1995)6 ie, as at June 1995
- tvplus07.zip: TVPlus 1(1995)7 ie, as at July 1995
- tvplus08.zip: latest TVPlus for use with a browser offline
-
- tvrw.zip: resource workshop
- tvspawn.zip: spawns programmes without destroying desktop
- tvtool17.zip: library of extensions and miscellaneous
- tvtoys.zip: improves TV help and VGA and VESA
- tvwork.zip: TVWorkshop - generates C++ source
-
- txtxit.zip: print text to screen after exiting TV
- user.zip: TListBox and PXEng example
- uses.zip: all the defines for TV1.03 in one header file
- ve2tv1.zip: virtual memory editor for TV1.03, BC3.1 & BC4.x
- ve2tv2.zip: virtual memory editor for TV2.0
-
- vtv.zip: demonstration menu bar generator
- welstead.zip: examples of scientific data dialog box
- xpwndg.zip: exploding windows and dialog boxes
-
-
- -----------------------------------------------------------------------
- The World Wide Web
- -----------------------------------------------------------------------
-
- We trust that these links to other World Wide Web pages contribute to
- the usefulness of TVPlus.
-
- ON THE C++ LANGUAGE
-
- The C++ Virtual Library
- This site <http://info.desy.de/user/projects/> contains
- information about C++ products, libraries, tutorials, tools and
- utilities.
- The Yahoo Database (C/C++ list)
- This listing whose URL is <http://www.yahoo.com/Computer/Languages/>
- is from the well known Web database, Yahoo
- The Captain's Log (C/C++ FAQ)
- The URL for this home page, which is found at the University of
- Liverpool (UK), <http://hpux.csc.liv.ac.uk/users/workexp/wk/>
- deals with C++ and object oriented programming - and C.
- The DESY user information
- This page whose URL is <http://info.desy.de/general/> is devoted
- to object oriented programming and presented by Deutsches
- Electronen-Synchrotron in Hamburg, Germany.
- The Borland WebPage
- Borland's effort on the WWW is at <http://www.borland.com/>. It
- covers a great deal more than just Turbo Vision material.
-
- ON VARIOUS TOPICS
-
- FAQs on various topics
- This home page at <http://www.cis.ohio-state.edu/hypertext/faq/>
- for Ohio State (US) presents FAQs in hypertext format.
-
-
- -----------------------------------------------------------------------
- Selected answers on programming
- -----------------------------------------------------------------------
-
- Although the division of the subject matter into the two headings listed
- here is somewhat artificial (because written explanations are often
- accompanied by code examples), we are adopting such a division to cater
- for both methods, only one of which may be used to illustrate the point
- in question.
-
- Articles
- Code snippets
-
- At this stage, it is proposed that material in these two headings be
- divided into twelve sections but this depends very much on the material
- that comes to hand. Select here if you want to get an overview.
-
- PLEASE NOTE: There are very few articles in this section of TVPlus at
- present. It is our aim, with your help, to provide a reasonably
- comprehensive collection of the FAQs.
-
- If you have a contribution to or comments on this chapter, please see
- the section, 'Wanted!'.
-
- -----------------------------------------------------------------------
- ARTICLES
- -----------------------------------------------------------------------
-
-
- Choose from this list for your selected topic:
-
- Application and desktop
- Menus and statusline*
- Dialog boxes
- Windows and editors
- Online help*
- Palettes
- Streams*
- Collections and resource files*
- Graphics
- Databases and interfacing Turbo Vision*
- Overlays and memory
-
- [* the heading requires elaboration]
-
- ----------------------------------------------------------------------
-
- APPLICATION AND DESKTOP
-
- Child programme re-direction
-
- -----------------------------------------------------------------------
-
- Child Programme Standard-Device Redirection
-
- Version None specified
- Terms None used
-
- This article outlines one approach to simultating a DOS box under
- MS-Windows so that, when the utility runs, its stdout is redirect to a
- window in the TV application.
-
- First write a character device driver that places standard output on the
- screen where you want it.
-
- Then from within your programme
-
- duplicate the standard-device handle with Interrupt 21H function 45h;
- save the duplicate handle;
- open the new device;
- with the new device handle retreived in step 3, modify the standard -
- device handle by using Force Duplicate Handle, Interupt 21H function
- 46H;
- run the child process;
- restore the standard-device handle saved in step 2 with Force
- Duplicate Handle, Interupt 21H function 46H; and
- close new device.
-
- You will need to refer to your Borland C++ Manual and a MS-DOS
- Programmer's reference for the details.
-
- -----------------------------------------------------------------------
-
- DIALOG BOXES
-
- Arranging input layout
- Chaining dialog boxes
- Scrolling dialog boxes
- Paging dialog boxes
- Progress Bar
-
- -----------------------------------------------------------------------
-
- Arranging input layout
-
- Version None specified
- Terms TDialog
-
- There have been a number of alternative methods proposed to put data
- entry fields to a dialog box that does not easily accommodate them:
-
- scrolling dialog box
-
- see article on scrolling dialog box
- see code SDLG2.ZIP in TVPlus file collection
-
- chaining dialog boxes
-
- see article on chaining dialog boxes
- see code in TI1158 in Borland TI series
-
- paging dialog boxes
-
- see article on paging dialog boxes
-
- ---------------------------------------------------------------------
-
- Chaining dialog boxes
-
- Version None specified
- Terms None specified
-
- This article suggests a way to chain dialog boxes where information from
- the user is too much for one screen alone.
-
- Create global instance variables of the dialog boxes in your main
- program. Then attach commands to the appropriate buttons in the dialog
- boxes, and make sure they are all different.
-
- Create an event handler for each box, so that when it sees the button
- command, it issues a broadcast message to the desktop using that event
- as part of the broadcast.
-
- Create an event handler for the desktop which can respond to the
- broadcast messages, and depending on the particular message, the desktop
- will create the appropriate dialog box.
-
- -----------------------------------------------------------------------
-
- Scrolling dialog box
-
- Version None specified
- Terms TDialog; TView::origin; TView::size; TGroup::redraw;
-
- One way to manage more input fields than would normally fit into one
- dialog box is to make the dialog scroll. This can be done because a
- subview of a view can have "bounds" that place all or part of it outside
- the bounds of the owner - the portion outside of the owner simply does
- not get drawn.
-
- Thus you can rig it so that the dialog responds to a "down arrow" press
- by decreasing origin.y for all of the subviews by 1, the "page down" key
- decreases origin.y for all of the subviews by the TDialog->size.y - 2
- (the minus 2 because of the line at the top and bottom used by the
- frame), and so on. After changing each TViews->origin.y, call
- TDialog->redraw.
-
- You can also place restrictions on how far up/down the scrolling is
- allowed to go. For example, to stop scrolling downwards when the
- "bottom" view is entirely visible, test for TVPBottomView->origin.y +
- TVPBottomView->size.y = TDialog->size.y.
-
- Do not blindly scroll every subview - some things, such as the frame,
- should stay where they are - i.e., set the GrowMode flag for every view
- appropriately and test it before adjusting its origin/size fields.
-
- The contributor had not used a scroll bar for this, but claimed it works
- very well with the arrow keys and the page up/down keys.
-
- ----------------------------------------------------------------------
-
- Paging dialog box
-
- Version None specified
- Terms TDialog; TView::hide; TNSCollection
-
- You can have a "paged" dialog by inserting all of the controls into the
- dialog in pages. At any one time, only one page's controls would be
- visible; you hide() the others.
-
- This probably sounds complex, but its actually pretty simple. Create a
- collection that stores TView pointers - the only real added
- functionality is NOT to destroy the views:
-
- class TNSViewCollection : public TNSCollection {
- public:
- TNSViewCollection( ccIndex lim, ccIndex d )
- : TNSCollection( lim, d ) {
- shouldDelete = False; }
- };
-
- Now consider if you have a "collection-of-collections". Here, the major
- reason for subclassing is that freeItem() correctly destroys the
- contained collections:
-
- class TNSCollCollection : public TNSCollection {
- public:
- TNSCollCollection( ccIndex lim, ccIndex d )
- : TNSCollection( lim, d ) {}
- private:
- virtual void freeItem( void* item ) {
- destroy( (TNSCollection*) item );
- }
- };
-
- Now you can subclass a dialog which has a collection-of- collections
- with each item representing a page in the dialog. Each contained
- collection holds pointers to all the TViews that make up that page. An
- example base class might look like:
-
- class TPagedDialog : public TDialog {
- public:
- TPagedDialog( const TRect& r, const char* s,
- int nrPages ) :
- TWindowInit( TPagedDialog::initFrame ),
- TDialog( r, s ),
- pageList( new TNSCollCollection(nrPages,0) ),
- curPage(0) {
- for( int i = 0; i < nrPages; i++ )
- pageList->insert( new TNSViewCollection(0,5) );
- }
- virtual void shutDown() {
- TDialog::shutDown();
- destroy( pageList );
- pageList = 0;
- }
- virtual void displayPage( int pageNumber ) {
- if( pageNumber >= 0 &&
- pageNumber < pageList->getCount() &&
- pageNumber != curPage ) {
- lock();
- ((TNSCollection*) pageList->at(curPage))->
- forEach( hideView, 0 );
- curPage = pageNumber;
- ((TNSCollection*) pageList->at(curPage))->
- forEach( showView, 0 );
- unlock();
- }
- }
- static void hideView( void* v, void* ) {
- ((TView*)v)->hide();
- }
- static void showView( void* v, void* ) {
- ((TView*)v)->show();
- }
- void pageInsert( TView* view ) {
- insert( view );
- ((TNSCollection*) pageList->at(curPage))->
- insert( view );
- }
- TNSCollection* pageList;
- };
- // The author has written all these members as inline.
- // In use, you would put them in a source file.
-
- For this base class, you start with page[0] as the active page stored in
- curPage. When you want to hide this page and display a different one,
- you call TPagedDialog::displayPage(pg) with the new page number.
-
- The author also put in TPagedDialog::pageInsert() so that it is easy to
- build the dialog. You start by pageInserting all the controls for page
- [0]. When you are done, you set page[1] as active by calling
- displayPage(1) and pageInsert the views for page[1]; etc.
-
- The member function TPagedDialog::displayPage() goes through the list of
- the views that are currently visible and hides them, and then goes
- through the list of views for the new page and shows them. This may not
- leave the focus where you want it when a new page is displayed - so you
- need to add code to do that.
-
- If you want a view to permanently be in the dialog, i.e. visible in all
- the pages, insert() it directly and do not use TPagedDialog::
- pageInsert(). Note, however, that it may end up being a bit goofy as far
- as the tabbing order goes. If it is the first view inserted (counting
- the ones in the pages), then it is OK - it will always be the first tab
- view. If it is at the end of the first page, the view is equivalent to
- being first in all the subsequent pages (which, tab- wise, is also OK).
-
- So, for example, you could subclass from TPagedDialog and have two
- "permanent" buttons (views) - a Prev button, and a Next button. You
- would start out with the Prev button disabled, and Next enabled. You
- would then override TPagedDialog::displayPage() so that it updates the
- buttons. For example:
-
- virtual void displayPage( int pageNr ) {
- TPagedDialog::displayPage( pageNr );
- if( pageNr == 0 ) {
- disableCommand( cmPrevBtn );
- enableCommand( cmNextBtn );
- }
- else {
- enableCommand( cmPrevBtn );
- if( pageNr != pageList->getCount()-1 )
- enableCommand( cmNextBtn );
- else
- disableCommand( cmNextBtn );
- }
- }
-
- This assumes that cmNextBtn and cmPrevBtn are disable-able commands (in
- the range of 100-255) and are assigned to these buttons.
-
- Finally, override handleEvent() to handle page switching:
-
- void handleEvent( TEvent& event ) {
- TPagedDialog::handleEvent( event );
- if( event.what == evCommand )
- if( event.message.command == cmPrevBtn )
- displayPage( curPage-1 );
- else if( event.message.command == cmNextBtn )
- displayPage( curPage+1 );
- else
- return;
- clearEvent( event );
- }
-
- ----------------------------------------------------------------------
-
- Progress Bar
-
- Version None specified
- Terms TStaticText; TView::setData
-
- To create a progress bar, you can derive a class from TStaticText which
- will allow setting of colour and re-displaying the string (via a
- setData() member function). This can be used to display a bar and then
- periodically update it.
-
- -----------------------------------------------------------------------
-
- PALETTES
-
- Palette with LCD displays
-
- -----------------------------------------------------------------------
-
- Palette with LCD displays
-
- Version None specified
- Terms TPalette
-
- TV has three predefined palettes as the manual describes (1992, pp
- 119-126, 384-386 and 455). Normally, the appropriate palette is selected
- when you start the application, but with LCD displays it does not always
- do that. You can obtain an example of how to set the palette from the
- command line or a menu option by downloading TVCOLR.ZIP from the TVPlus
- file collection
-
- -----------------------------------------------------------------------
-
- WINDOWS AND EDITORS
-
- File Editor: TV does not support files greater than 64kb. There is a
- shareware TV extension - named ve2tv1.zip or ve2tv2.zip - which does so;
- designed by Eric Woodruff, it allows some professional file editing
- features that can make TV a useful editing platform; and the source code
- is required as some specific objects are renamed. You could also
- recompile the TV source using one of the TV ports to djgpp, gcc/emx,
- etc.
-
- Word wrapping editor: This is unsupported in TV. There is a TV extension
- - named tvwrdwrp.zip - which provides word wrapping functionality but
- requires the recompiling of the source code.
-
- ----------------------------------------------------------------------
-
- GRAPHICS
-
- Turbo Vision can be made to run in graphics mode. However, the point to
- bear in mind is that, as TV is designed from the ground up as a text
- mode application, the performance of the screen redraws can suffer.
- There are two options: if graphics has only a secondary role in your
- program, try switching screen modes and doing your graphics processing
- there; if you need a complete graphics system, use one of the TV
- libraries available.
-
- -----------------------------------------------------------------------
-
- OVERLAYS AND MEMORY
-
- TV is large. It can add 200 to 300 kb onto your application. Bear this
- in mind when you are writing a program using it. It is generally well
- behaved provided that you have made the appropriate patches to your
- compiler and you have used the destroy() operator as suggested.
-
- If you need more memory, the use of overlays can be be added. This
- involves the recompiling of the source code, to allow for the division
- of files into separate libraries. If you do not have the sources, there
- is not much you can do... Overlaying your application will present other
- factors that you will have to deal with. They can slow down execution,
- the tracking down of bugs is more difficult and you cannot compress an
- overlayed program.
-
- You can use a DOS extender. This is available in BC4.x but is not
- supported in BC31. You can try a third party DOS extender such as
- Pharlap's, but there is a fee for executables distributed with it. There
- are patches that can be used with the TV source to allow Pharlap's
- extender to be used with TV.
-
-
- -----------------------------------------------------------------------
- CODE SNIPPETS
- -----------------------------------------------------------------------
-
- The basis of selecting code for inclusion within this heading is its
- useful in demonstrating TV coding techniques. This is the practical
- aspect of the questions covered in the section, Articles.
-
- Choose from this list to view code snippets on your selected topic
-
- Application and desktop
- Menus and statusline*
- Dialog boxes
- Windows and editors*
- Online help*
- Palettes
- Streams*
- Collections and resource files
- Graphics*
- Databases and interfacing Turbo Vision*
- Overlays and memory*
-
- [* the heading requires elaboration]
-
- -----------------------------------------------------------------------
-
- APPLICATION AND DESKTOP
-
- Spawning programmes
-
- -----------------------------------------------------------------------
-
- Spawning programmes
-
- Version None specified
- Author Frank Hohmann <mailto:fhohmann@rols1.oec.uni-osnabrueck.de>
- Terms TApplication::suspend; TApplication::resume; overload
-
- /*
- TVSPAWN.CPP
- This is a demo for calling programs from within the TV environment
- without destroying the desktop.
- The approach is as follows:
- - overload TApplication::suspend() and TApplication::resume().
- We must do this to avoid TScreen::suspend() and TScreen::resume()
- to be executed.
- - display a non-movable, non-resizable TWindow on the screen
- (see class TSwanWindow)
- - define a window() (see conio.h) that covers the client
- area of our TSpawnWindow and set "directvideo=1"
- - redirect INT 29h "fast console output" to an own interrupt
- routine (INT 29h is called everytime a character is written to
- stdout). This routine calls cprintf() to display the character
- - proceed with spawning a child process as described in
- Borland examples
- - restore INT 29h to the original
-
- I tested the above on different standard text modes and encountered
- no problems. Nevertheless this example comes without any warranty.
-
- Please report any experiences/errors/enhancements to
- Frank Hohmann
- University of Osnabrueck, Germany
- e-mail: fhohmann@rols1.oec.uni-osnabrueck.de
- */
-
- #include <stdlib.h> // for system()
- #include <dos.h> // for setvect(), getvect()
- #include <conio.h> // cprintf(), window()
- #include <stdio.h>
-
- #define Uses_TEvent
- #define Uses_TProgram
- #define Uses_TApplication
- #define Uses_TKeys
- #define Uses_TRect
- #define Uses_TMenuBar
- #define Uses_TSubMenu
- #define Uses_TMenuItem
- #define Uses_TStatusLine
- #define Uses_TStatusItem
- #define Uses_TStatusDef
- #define Uses_TDeskTop
- #define Uses_TWindow
- #define Uses_TSystemError
- #define Uses_TEventQueue
-
- #include <tv.h>
-
- #define INT_NUMBER 0x29 // interrupt for "fast console output"
- #define DOS_CMD "MEM /C" // command to spawn for test purpose
-
- const int cmNewSpawnWin = 100;
- const int cmSpawn = 1000;
-
-
- class TVApp : public TApplication {
- public:
- TVApp();
- static TStatusLine *initStatusLine( TRect r );
- static TMenuBar *initMenuBar( TRect r );
- virtual void handleEvent( TEvent& event);
- void mySpawnWindow();
- virtual void suspend();
- virtual void resume();
- };
-
- class TSpawnWindow : public TWindow {
- public:
- TSpawnWindow( const TRect& r, const char *aTitle, short aNumber );
- virtual void handleEvent(TEvent& event);
- void spawn();
- };
-
- // ------------------- TVApp
- TVApp::TVApp() :
- TProgInit( &TVApp::initStatusLine,
- &TVApp::initMenuBar,
- &TVApp::initDeskTop) {
- }
-
- TStatusLine *TVApp::initStatusLine(TRect r) {
- r.a.y = r.b.y - 1; // move top to 1 line above bottom
- return new TStatusLine( r,
- *new TStatusDef( 0, 0xFFFF ) +
- *new TStatusItem( 0, kbF10, cmMenu ) +
- *new TStatusItem( 0, kbAltF3, cmClose ) +
- *new TStatusItem( "~Alt-X~ Exit", kbAltX, cmQuit ) );
- }
-
- TMenuBar *TVApp::initMenuBar( TRect r ) {
- r.b.y = r.a.y + 1; // set bottom line 1 line below top line
- TMenuBar *m =
- new TMenuBar( r,
- *new TSubMenu( "~S~pawn", kbAltF )+
- *new TMenuItem( "~T~est", cmNewSpawnWin, kbF4, hcNoContext, "F4" )+
- newLine()+
- *new TMenuItem( "E~x~it", cmQuit, cmQuit, hcNoContext, "Alt-X" ) );
- return m;
- }
-
- void TVApp::handleEvent(TEvent& event) {
- TApplication::handleEvent(event);
- if( event.what == evCommand ) {
- switch( event.message.command ) {
- case cmNewSpawnWin:
- mySpawnWindow();
- break;
- default:
- return;
- }
- clearEvent( event ); // clear event after handling
- }
- }
-
- void TVApp::mySpawnWindow() {
- TRect r( 2, 2, 78, 21 );
-
- // insert a new TSpawnWindow
- TSpawnWindow *window = new TSpawnWindow ( r, "Output", wnNoNumber);
- deskTop->insert(window);
- // ... and let it do its job
- message(window, evBroadcast, cmSpawn, NULL);
- }
-
- // We must override TApplication::suspend()
- // since we don't want TScreen::suspend() to be executed
- void TVApp::suspend() {
- TSystemError::suspend();
- TEventQueue::suspend();
- }
-
- // We must override TApplication::resume()
- // since we don't want TScreen::resume() to be executed
- void TVApp::resume() {
- TEventQueue::resume();
- TSystemError::resume();
- }
-
- // ------------------- TSpawnWindow
- TSpawnWindow::TSpawnWindow( const TRect& r, const char *aTitle,
- short aNumber) : TWindow( r, aTitle, aNumber),
- TWindowInit( &TSpawnWindow::initFrame) {
-
- flags = 0; // no Zoom/close/move style bits
- }
-
- #pragma argsused
- void interrupt NewInt29( unsigned bp, unsigned di, unsigned si,
- unsigned ds, unsigned es, unsigned dx, unsigned cx,
- unsigned bx, unsigned ax, unsigned ip, unsigned cs,
- unsigned flags ) {
- // the character to be outputted must be taken from AL
- cprintf("%c", (ax &~ 0xFF00));
- // signal end of interrupt (EOI)
- outportb(0x20, 0x20);
- }
-
- void TSpawnWindow::spawn() {
- // first call our new suspend()
- TProgram::application->suspend();
-
- // ... then save old INT 29h vector and replace it with our own
- void interrupt (*OldInt29)(...) = getvect(INT_NUMBER);
- setvect(INT_NUMBER, (void interrupt (*)(...))NewInt29);
-
- // ... define a conio window that matches our TSpawnWindow's client area,
- // activate direct video and set the appropiate color
- window(origin.x+3, origin.y+3, origin.x + size.x -2, origin.y + size.y);
- directvideo = 1;
- textattr(getColor(2));
-
- // ... call some DOS commands (spawn() or system())
- printf("Executing %s\n", DOS_CMD);
- system(DOS_CMD);
- system("pause");
-
- // ... and restore our old environment
- setvect(INT_NUMBER, OldInt29);
- TProgram::application->resume();
-
- // finally close our TSpawnWindow
- close();
- }
-
- void TSpawnWindow::handleEvent(TEvent& event) {
- if( event.what == evBroadcast && event.message.command == cmSpawn ) {
- spawn();
- clearEvent(event);
- }
- else
- TWindow::handleEvent(event);
- }
-
- int main() {
- TVApp tvApp;
- tvApp.run();
- return 0;
- }
-
- -----------------------------------------------------------------------
-
- DIALOG BOXES
-
- Cursor control
- Default value
- Exit method (1)
- Exit method (2)
- Password (1)
- Password (2)
-
- -----------------------------------------------------------------------
-
- Cursor movement
-
- Version Not specified
- Terms TDialog; TInputLine
-
- The standard behaviour in Turbo Vision for moving from one field to
- another within a dialog box is to use the TAB. The following code
- snippet shows how to modify this behaviour so that you can instead use
- ENTER or arrow keys to move to another field.
-
- // Override handleEvent for your dialog class with
- // the following:
-
- void TVDialog::handleEvent (TEvent &event) {
- if (event.what == evKeyDown) {
- switch (ctrlToArrow (event.keyDown.keyCode)) {
- case kbUp: {
- if (valid (cmCheck)) {
- selectNext (True);
- }
- clearEvent (event);
- break;
- }
- case kbEnter: {
- if (valid (cmCheck)) {
- selectNext (False);
- }
- clearEvent (event);
- break;
- }
- case kbTab:
- clearEvent (event);
- break;
- }
- }
- TDialog::handleEvent (event);
- return;
- }
-
- NB. There are a number of class extensions available
- which provide code along such lines.
-
- -------------------------------------------------------------
-
- Default values
-
- Version None specified
- Terms TDialog; TInputLine
-
- This code example shows how to display a default value in a dialog box.
-
- TInputLine *control = new TInputLine(......);
- control->setData(buffer);
- // other stuff
- execView(dialog_with_TInputLine);
-
- Here, buffer is the pointer to the text to be inserted into the
- TInputLine.
-
- -------------------------------------------------------------
-
- Exit method (1)
-
- Version Not specified
- Author William Werth <billw@eskimo.com>
- Terms TDialog; TButton
-
- //To exit a modal TDialog by pressing a
- //TButton hat does not send cmExit, cmQuit
- //or equivalent but sends cmSearch instead, and
- //to call another TDialog.
- TVDialog::TVDialog ()
- : TDialog (...), TWindowInit (...) {
- // other stuff
- insert (new TButton
- (TRect(40,20,50,22), "~S~earch", cmSearch,
- bfDefault) );
- selectNext (False);
- };
- //There are two ways to do this
- //1) Overload the handleEvent function in TVDialog
- void TVDialog::handleEvent(TEvent& ev) {
- if (ev.what == evCommand &&
- ev.message.command == cmSearch) {
- clearEvent(ev);
- ev.message.comand = cmOk;
- // change event to one that will exit
- searchFlag = 1;
- // set a flag or somehow note cmSearch event
- }
- TDialog::handleEvent(ev);
- }
- //2) Overload the handleEvent, but as follows:
- void TVDialog::handleEvent(TEvent& ev) {
- if (ev.what == evCommand &&
- ev.message.command == cmSearch) {
- endModal(ev.message.command);
- clearEvent(ev);
- }
- else
- TDialog::handleEvent(ev);
- }
-
- -------------------------------------------------------------
-
- Exit method (2)
-
- Version Not specified
- Terms TDialog
-
- This procedure does not use an OK or Cancel button to close the dialog
- because the specified action is accomplished before the dialog is
- closed.
-
- // To trigger some action
- const ushort cmTVCommand = 100;
-
- void TVDialog::doSomething(void) {
- // Insert your tasks here; messageBox() for
- // demonstration only
- messageBox("Doing something", mfInformation |
- mfOKButton);
- }
-
- // Virtual function: if the event type is a command
- // which is yours and the dialog is valid
- void TVDialog::handleEvent(TEvent& event) {
- TEvent newEvent;
-
- if (event.what == evCommand &&
- event.message.command = cmTVCommand &&
- valid(cmOK)) {
- doSomething();
- clearEvent(event);
- newEvent.what = evCommand;
- newEvent.message.command = cmOK;
- newEvent.message.infoPtr = NULL;
- putEvent(newEvent);
- return;
- }
-
- TDialog::handleEvent(event);
- }
-
- Whether or not to put the newEvent event into the event queue
- could depend on the result from doSomething().
-
- Either way, the next time around you will have performed your
- tasks (which, by the way, cannot include posting another event
- -- only one can be posted at a time without processing the
- other) and handleEvent will get the cmOK command, and treat it
- normally.
-
- -------------------------------------------------------------
-
- Password Object (1)
-
- Version TV2
- Author Pat Reilly <71333.2764@compuserve.com>
- Terms TDialog; TInputLine
-
- //Here is a simple password object and
- //implementation -
- class TPassword : public TInputLine {
- public:
- TPassword( const TRect& r, int aMaxLen,
- TValidator* aValid = 0 ) :
- TInputLine ( r, aMaxLen, aValid ) {}
- virtual void draw();
- };
- void TPassword::draw() {
- char* oldData = newStr(data);
- for ( char* p = data; *p != EOS; p++ )
- *p = '*';
- TInputLine::draw();
- strcpy( data, oldData );
- delete [] oldData;
- }
- //...
- strcpy( data, oldData );
- delete [] oldData;
- // ...
- }
-
- -------------------------------------------------------------
-
- Password (2)
-
- Version Not specified
- Terms TDialog; TInputLine; TPasswordInput; TPasswordInput:: draw()
-
- To enter a password in a dialog box and to avoid having that password
- displayed can be achieved with the following code
-
- #define chrPassword '*'
-
- TPasswordInput::TPasswordInput( const TRect& bounds, int maxLen ) :
- TInputLine( bounds, maxLen), starData( new char[ maxLen] ) {
- memset( starData, chrPassword, maxLen); // fill with stars
- *(starData+maxLen-1) = EOS; // end of line
- }
-
- TPasswordInput::~TPasswordInput() {
- delete [] starData;
- }
-
- void TPasswordInput::draw( void) {
- char *origData;
- char *curEnd = starData + strlen( data); // length of string
-
- *curEnd = EOS; // make '*'-string correct length
- origData = data; // remember pointer;
- data = starData; // point to new data (all stars)
-
- TInputLine::draw(); // draw myself
-
- data = origData; // restore pointer
- *curEnd = chrPassword; // restore original '*'-string
- }
-
- -----------------------------------------------------------------------
-
- PALETTES
-
- Saving colours
-
- Version Not specified
- Terms TPalette; fpstream; fpstream::readBytes; fpstream::writeBytes;
- opstream
-
- // Here's how to save the colors.
- void TVApp::saveColors(void) {
- fpstream *f = new fpstream("ANYFILE", ios::trunc |
- ios::binary);
-
- opstream &strm = *f;
-
- // Store the palettes
- short curr_palette = appPalette;
- for(short i = 0; i < 3; i++) {
- appPalette = i;
- TPalette *palette = &getPalette();
- strm.writeBytes(palette->data, palette->data[0] + 1);
- }
- appPalette = curr_palette;
- }
-
- // Here's how to load the colors.
- void TVApp::loadColors(void) {
- fpstream *f = new fpstream("ANYFILE", ios::in |
- ios::nocreate | ios::binary);
- ipstream &strm = *f;
-
- // Read palettes from the configuration file.
- short curr_palette = appPalette;
- for(short i = 0; i < apTotalPalettes; i++) {
- appPalette = i;
- TPalette *palette = &getPalettes();
- strm.readBytes(palette->data, palette->data[0] + 1);
- }
- appPalette = curr_palette;
- }
-
- -----------------------------------------------------------------------
-
- COLLECTIONS AND RESOURCE FILES
-
- TListBox and arrays
-
- Version None specified
- Terms TListBox; TNSCollection::insert; ::newStr; arrays
-
- // From file:
- FILE *f;
- char buf[80];
- int n, cnt=0;
- while (fgets(buf,80,f))
- // could use strdup()?
- collection->insert(newStr(buf));
-
- while (fread(&n,2,1,f)) {
- sprintf(buf,"Counter %u = %u",cnt++,n);
- collection->insert(newStr(buf));
- }
- // From array is similar
-
- Comment: There may be difficulty reading streamable file from other
- language programs.
-
- ====================== END OF TEXT PART 2 =============================
- --
- Rachel Polanskis grove@zeta.org.au Robert Hazeltine
- http://www.zeta.org.au/~grove/grove.html
- r.polanskis@nepean.uws.edu.au
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-