summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graemeg@gmail.com>2013-04-10 00:09:29 +0100
committerGraeme Geldenhuys <graemeg@gmail.com>2013-04-10 00:09:29 +0100
commitd24464c8646ffd19e9b02de93626dd20054e2da5 (patch)
treeafaaf3caa81c9d15084d03be62b3f8f57d3444d8
parentde7e463e6210c28b56ba853ec2c2fdfd404a7a1f (diff)
parent6fa2f7ef71b16815e64e6ff547c9fcd6562be87b (diff)
downloadfpGUI-d24464c8646ffd19e9b02de93626dd20054e2da5.tar.xz
Merge branch 'release-1.0'
-rw-r--r--CHANGELOG.txt27
-rw-r--r--docs/branching_model/branching_model.infbin0 -> 19175 bytes
-rw-r--r--docs/branching_model/branching_model.ipf644
-rw-r--r--docview/TODO.txt2
-rw-r--r--docview/docs/codepage_2_unicode_mapping/readme.txt (renamed from docview/docs/codepage_2_unicode_mapping/reame.txt)0
-rw-r--r--docview/docs/docview.ipf145
-rw-r--r--docview/src/HelpBitmap.pas340
-rw-r--r--docview/src/HelpFile.pas25
-rw-r--r--docview/src/HelpTopic.pas2
-rw-r--r--docview/src/NewViewConstantsUnit.pas37
-rw-r--r--docview/src/docview.lpi62
-rw-r--r--docview/src/docview.lpr9
-rw-r--r--docview/src/docview.rc8
-rw-r--r--docview/src/dvHelpers.pas3
-rw-r--r--docview/src/dvconstants.pas13
-rw-r--r--docview/src/frm_bookmarks.pas312
-rw-r--r--docview/src/frm_main.pas180
-rw-r--r--docview/src/frm_note.pas17
-rw-r--r--docview/src/lzwdecompress.pas263
-rw-r--r--examples/apps/debugserver/fpgDebugServer.lpi2
-rw-r--r--examples/apps/docedit/docedit.lpi22
-rw-r--r--examples/apps/docedit/frm_main.pas4
-rw-r--r--examples/corelib/aggcanvas/agg_canvas_test.lpi71
-rw-r--r--examples/corelib/aggcanvas/agg_canvas_test.lpr389
-rw-r--r--examples/corelib/aggcanvas/arial.ttfbin0 -> 275572 bytes
-rw-r--r--examples/corelib/aggcanvas/arialbd.ttfbin0 -> 286620 bytes
-rw-r--r--examples/corelib/aggcanvas/extrafpc.cfg5
-rw-r--r--examples/corelib/aggcanvas/times.ttfbin0 -> 409280 bytes
-rw-r--r--examples/corelib/aggcanvas/timesi.ttfbin0 -> 248368 bytes
-rw-r--r--prototypes/keyboard_symbols.txt37
-rw-r--r--src/VERSION_FILE.inc2
-rw-r--r--src/corelib/fpg_base.pas14
-rw-r--r--src/corelib/fpg_imgfmt_bmp.pas236
-rw-r--r--src/corelib/fpg_imgfmt_png.pas16
-rw-r--r--src/corelib/fpg_widget.pas2
-rw-r--r--src/corelib/render/software/Agg2D.pas82
-rw-r--r--src/gui/fpg_menu.pas6
-rw-r--r--src/gui/fpg_tree.pas111
38 files changed, 2515 insertions, 573 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index f6667de3..2edd6a61 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -2,6 +2,33 @@
Release notes for fpGUI
=======================
+v1.0 (2013-04-09)
+ - Docview improvements: Bookmark maintenance, keyboard shortcuts,
+ image support in INF files, cross link support.
+ - Many improvements to the experimental Maximus IDE.
+ - More widget themeing improvements.
+ - Keyboard shortcut handling improvements.
+ - AggPas 2D graphics library merged into fpGUI as a new
+ cross-platform graphics backend. This is the first step in
+ adding AggPas support, and this is still work in progress, but
+ most functionality works already. Also added some 64-bit fixes
+ to the AggPas code.
+ - Many PDF report engine improvements. Also enhanced the look and
+ functionality of the Print Preview dialog.
+ - Lots more documentation added. This is an ongoing task.
+ - Big improvements to the TextEdit widget, that is used by Maximus
+ and the Nanoedit example project.
+ - Many improvements to the RichView component and it's supported
+ syntax - used by Docview. This widget is now also useable
+ in other projects, not just Docview.
+ - Improved fpGUI language translations.
+ - The UI Designer (forms designer) has also seen many improvements,
+ like new widgets added to the palette, more published properties
+ added to the Object Inspector window etc.
+ - Many, many more bug fixes and improvements. For a full list run:
+ git log v1.0...v0.8
+
+
v0.8 (2011-12-02)
- New widget demos and many improvements to existing demos.
- New application examples
diff --git a/docs/branching_model/branching_model.inf b/docs/branching_model/branching_model.inf
new file mode 100644
index 00000000..6f03331c
--- /dev/null
+++ b/docs/branching_model/branching_model.inf
Binary files differ
diff --git a/docs/branching_model/branching_model.ipf b/docs/branching_model/branching_model.ipf
new file mode 100644
index 00000000..da500297
--- /dev/null
+++ b/docs/branching_model/branching_model.ipf
@@ -0,0 +1,644 @@
+.* Created by Graeme Geldenhuys <graemeg@gmail.com> - 2013-04-08
+.* This document is encoded as IBM code page 850.
+.*
+:userdoc.
+:docprof toc=123.
+:title.fpGUI Branching Model
+
+:h1.fpGUI branching model
+:p.In this post I present the development model that I've introduced for all of
+my projects (both at work and private) about a year ago, and which has turned
+out to be very successful. I've been meaning to write about it for a while now,
+but I've never really found the time to do so thoroughly, until now. I won't
+talk about any of the projects' details, merely about the branching strategy
+and release management.
+
+:cgraphic.
+ :hp2.Time increases to the right:ehp2.
+
+ 0.1 0.2 1.0 1.5
+ master ĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶ>
+ \Ä, / / /
+ | \ / / /
+ hotfixes ÄÄÄÄ|ÄÄÄoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ/ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ/ÄÄÄÄÄÄÄÄÄÄÄ>
+ | \ / /
+ | \ / /
+ release ÄÄÄÄ|ÄÄÄÄÄÄ\ÄÄÄÄÄÄÄÄÄÄÄÄÄoĶĶĶoĶĶĶoĶĶĶoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄoÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>
+ branches | \ / \ \ / \
+ \ \ / \ \ / \
+ develop ĶĶĶĶĶĶoĶĶĶoĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶoĶĶĶoĶĶĶĶĶoĶĶĶoĶĶĶĶĶĶĶ>
+ \Ä, / \ / /
+ | \ / \ / /
+ feature1 ÄÄÄÄÄÄÄ|ÄÄÄoĶĶĶoĶĶĶoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄoĶĶĶoĶĶĶoÄÄÄ/ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>
+ | /
+ \ /
+ feature2 ÄÄÄÄÄÄÄÄÄoĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>
+
+
+
+ :hp2.Key::ehp2.
+ ĶĶĶ and diagonal lines represent active development
+ ÄÄÄ represents no development, just time that has passed
+ o is a commit in the repository
+ 0.1 Numbers above the master branch is release tags
+:ecgraphic.
+
+:p.
+Here is an :link reftype=hd res=123.alternative overview graph:elink., which
+hides the "time has passed" lines.
+
+:p.
+It focuses around Git [http://git-scm.com/] as the tool for the versioning of all of our source code.
+
+.* -------------------------------------
+:h2 res=123 hide.Alternative overview graph
+:cgraphic.
+ :hp2.Time increases to the right:ehp2.
+
+ 0.1 0.2 1.0 1.5
+ master ĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶ>
+ \Ä, / / /
+ | \ / / /
+ hotfixes | o / /
+ | \ / /
+ | \ / /
+ release | \ oĶĶĶoĶĶĶoĶĶĶo o
+ branches | \ / \ \ / \
+ \ \ / \ \ / \
+ develop ĶĶĶĶĶĶoĶĶĶoĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶoĶĶĶĶĶoĶĶĶoĶĶĶĶĶoĶĶĶoĶĶĶĶĶĶĶ>
+ \Ä, / \ / /
+ | \ / \ / /
+ feature1 | oĶĶĶoĶĶĶo oĶĶĶoĶĶĶo /
+ | /
+ \ /
+ feature2 oĶĶĶoĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶĶoĶĶĶĶĶĶĶĶĶĶo
+
+
+
+ :hp2.Key::ehp2.
+ ĶĶĶ and diagonal lines represent active development
+ o is a commit in the repository
+ 0.1 Numbers above the master branch is release tags
+:ecgraphic.
+
+.* -------------------------------------
+:h2.Why Git?
+:p.
+For a thorough discussion on the pros and cons of Git compared to centralized
+source code control systems, see [http://whygitisbetterthanx.com/] the web [http://git.or.cz/gitwiki/GitSvnComparsion]. There are plenty of flame wars going
+on there. As a developer, I prefer Git above all other tools around today. Git
+really changed the way developers think of merging and branching. From the
+classic CVS/Subversion world I came from, merging/branching has always been
+considered a bit scary ("beware of merge conflicts, they bite you!") and
+something you only do every once in a while.
+
+:p.
+But with Git, these actions are extremely cheap and simple, and they are
+considered one of the core parts of your daily workflow, really. For example,
+in CVS/Subversion books, branching and merging is first discussed in the later
+chapters (for advanced users), while in every Git book, it's already covered
+in chapter 3 (basics).
+
+:p.
+As a consequence of its simplicity and repetitive nature, branching and merging
+are no longer something to be afraid of. Version control tools are supposed to
+assist in branching/merging more than anything else.
+
+:p.
+Enough about the tools, let's head onto the development model. The model that
+I'm going to present here is essentially no more than a set of procedures that
+every team member has to follow in order to come to a managed software
+development process.
+
+.* -------------------------------------
+:h2.Decentralised but centralised
+:p.
+The repository setup that we use and that works well with this branching model,
+is that with a central "truth" repo. Note that this repo is only considered to
+be the central one (since Git is a DVCS, there is no such thing as a central
+repo at a technical level). We will refer to this repo as origin, since this
+name is familiar to all Git users.
+
+.* :artwork align=center name='centr-decentr.bmp'.
+:cgraphic.
+ ŚÄÄÄÄÄÄÄÄÄÄæ ŚÄÄÄÄÄÄÄÄÄÄæ
+ ³ ³ ³ ³
+ ³ alice ³<ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>³ david ³
+ ³ ³ ³ ³
+ ³ ³<ÄÄÄÄæ ŚÄÄÄÄÄÄ>³ ³
+ ĄÄÄÄÄÄÄÄÄÄÄŁ ³ ³ ĄÄÄÄÄÄÄÄÄÄÄŁ
+ ^ ³ ŚÄÄÄÄÄÄÄÄÄÄæ ³ ^
+ ³ ĄÄÄÄÄ>³ ³<ÄÄÄÄÄŁ ³
+ ³ ³ origin ³ ³
+ ³ ³ ³ ³
+ ³ ŚÄÄÄÄ>³ ³<ÄÄÄÄÄæ ³
+ v ³ ĄÄÄÄÄÄÄÄÄÄÄŁ ³ v
+ ŚÄÄÄÄÄÄÄÄÄÄæ ³ ³ ŚÄÄÄÄÄÄÄÄÄÄæ
+ ³ ³<ÄÄÄÄŁ ĄÄÄÄÄÄÄ>³ ³
+ ³ bob ³ ³ clair ³
+ ³ ³<ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>³ ³
+ ³ ³ ³ ³
+ ĄÄÄÄÄÄÄÄÄÄÄŁ ĄÄÄÄÄÄÄÄÄÄÄŁ
+:ecgraphic.
+
+:p.
+Each developer pulls and pushes to origin. But besides the centralized push-pull
+ relationships, each developer may also pull changes from other peers to form
+sub teams. For example, this might be useful to work together with two or more
+developers on a big new feature, before pushing the work in progress to origin
+prematurely. In the figure above, there are subteams of Alice and Bob, Alice
+and David, and Clair and David.
+
+:p.
+Technically, this means nothing more than that Alice has defined a Git remote,
+named bob, pointing to Bob's repository, and vice versa.
+
+
+.* -------------------------------------
+:h2.The main branches
+:p.
+At the core, the development model is greatly inspired by existing models out
+there. The central repo holds two main branches with an infinite lifetime:
+
+:ul compact.
+:li.master
+:li.develop
+:eul.
+
+:cgraphic.
+ (1) (2) (3)
+ master ÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄFÄÄÄÄÄÄÄIÄÄÄÄÄÄÄÄÄÄÄÄ>
+ \ / /
+ develop ÄÄÄÄÄBÄÄÄCÄÄÄDÄÄÄEÄÄÄGÄÄÄHÄÄÄJÄÄÄKÄÄÄÄÄÄ>
+ (4)
+
+
+ 1) Initial production version
+ 2) Next production version
+ 3) Next production version
+ 4) Work in progress on "next release"
+:ecgraphic.
+
+.* :cgraphic.
+.* develop master
+.* | |
+.* | o Initial production version
+.* | /|
+.* | ,-------------' |
+.* |/ |
+.* o |
+.* | |
+.* o |
+.* | |
+.* o |
+.* | |
+.* o |
+.* |\ |
+.* | `-------------, |
+.* o \|
+.* | o Next production version
+.* o |
+.* |\ |
+.* | `-------------, |
+.* o \|
+.* | o Next production version
+.* Work in o |
+.* progress on | |
+.* "next release" | |
+.* | |
+.* v v
+.* :ecgraphic.
+
+:p.
+The :hp8.master:ehp8. branch at :hp8.origin:ehp8. should be familiar to every Git user. Parallel to
+the :hp8.master:ehp8. branch, another branch exists called :hp8.develop:ehp8..
+
+:p.
+We consider :hp8.origin/master:ehp8. to be the main branch where the source code of HEAD
+always reflects a production-ready state.
+
+:p.
+We consider :hp8.origin/develop:ehp8. to be the main branch where the source code of HEAD
+always reflects a state with the latest delivered development changes for the
+next release. Some would call this the "integration branch". This is where any
+automatic nightly builds are built from.
+
+:p.
+When the source code in the :hp8.develop:ehp8. branch reaches a stable point and is ready
+to be released, all of the changes should be merged back into :hp8.master:ehp8. somehow
+and then tagged with a release number. How this is done in detail will be
+discussed further on.
+
+:p.
+Therefore, each time when changes are merged back into :hp8.master:ehp8., this is a new
+production release by :hp1.definition:ehp1.. We tend to be very strict at this, so that
+theoretically, we could use a Git hook script to automatically build and
+roll-out our software to our production servers everytime there was a commit
+on :hp8.master:ehp8..
+
+
+.* -------------------------------------
+:h2.Supporting branches
+:p.
+Next to the main branches master and develop, our development model uses a
+variety of supporting branches to aid parallel development between team members,
+ease tracking of features, prepare for production releases and to assist in
+quickly fixing live production problems. Unlike the main branches, these
+branches always have a limited life time, since they will be removed eventually.
+
+:p.
+The different types of branches we may use are:
+
+:ul compact.
+:li.Feature branches
+:li.Release branches
+:li.Hotfix branches
+:eul.
+
+:p.
+Each of these branches have a specific purpose and are bound to strict rules
+as to which branches may be their originating branch and which branches must
+be their merge targets. We will walk through them in a minute.
+
+:p.
+By no means are these branches "special" from a technical perspective. The
+branch types are categorized by how we use them. They are of course plain old
+Git branches.
+
+.* -------------------------------------
+:h2.Feature branches
+.* :artwork align=center name='feature-branch.bmp'.
+:cgraphic.
+ develop ÄÄÄAÄÄÄBÄÄÄGÄÄÄHÄÄÄÄÄÄÄIÄÄÄJÄÄÄ>
+ \ /
+ feature ÄÄÄÄÄÄÄÄÄCÄÄÄDÄÄÄEÄÄÄFÄÄÄÄÄÄÄÄÄ>
+ branches
+:ecgraphic.
+
+
+.* :cgraphic.
+.* feature
+.* branches develop
+.* | |
+.* | o
+.* | |
+.* | o
+.* | /|
+.* | ,-------------' |
+.* |/ o
+.* o |
+.* | |
+.* o o
+.* | |
+.* o |
+.* |\ |
+.* | `-------------, |
+.* | \|
+.* | o
+.* | |
+.* | |
+.* v v
+.* :ecgraphic.
+
+:p.
+May branch off from: :hp8.develop:ehp8.
+.br
+Must merge back into: :hp8.develop:ehp8.
+.br
+Branch naming convention: anything except :hp8.master:ehp8., :hp8.develop:ehp8.,
+:hp8.release-*:ehp8., or :hp8.hotfix-*:ehp8.
+
+:p.
+Feature branches (or sometimes called topic branches) are used to develop new
+features for the upcoming or a distant future release. When starting development
+of a feature, the target release in which this feature will be incorporated may
+well be unknown at that point. The essence of a feature branch is that it
+exists as long as the feature is in development, but will eventually be merged
+back into develop (to definitely add the new feature to the upcoming release)
+or discarded (in case of a disappointing experiment).
+
+:p.
+Feature branches typically exist in developer repos only, not in :hp8.origin:ehp8..
+
+:h3.Creating a feature branch
+:p.
+When starting work on a new feature, branch off from the develop branch.
+
+:lm margin=5.
+:xmp.
+$ git checkout -b myfeature develop
+Switched to a new branch "myfeature"
+:exmp.
+:lm margin=1.
+
+:h3.Incorporating a finished feature on develop
+:p.
+Finished features may be merged into the develop branch definitely add them to
+the upcoming release:
+
+:lm margin=5.
+:xmp.
+$ git checkout develop
+Switched to branch 'develop'
+$ git merge --no-ff myfeature
+Updating ea1b82a..05e9557
+(Summary of changes)
+$ git branch -d myfeature
+Deleted branch myfeature (was 05e9557).
+$ git push origin develop
+:exmp.
+:lm margin=1.
+
+:p.
+The :hp2.--no-ff:ehp2. flag causes the merge to always create a new commit object, even
+if the merge could be performed with a fast-forward. This avoids losing
+information about the historical existence of a feature branch and groups
+together all commits that together added the feature. Compare:
+
+:cgraphic.
+
+ :hp2.git merge --no--ff:ehp2.
+
+ develop ÄÄÄAÄÄÄBÄÄÄÄÄÄÄÄÄÄÄFÄÄÄÄÄÄÄ>
+ \ /
+ feature ÄÄÄÄÄÄÄÄÄCÄÄÄDÄÄÄEÄÄÄÄÄÄÄÄÄ>
+ branches
+
+
+ :hp2.git merge:ehp2.
+ (plain)
+
+ develop ÄÄÄAÄÄÄBÄÄÄCÄÄÄDÄÄÄEÄÄÄFÄÄÄ>
+
+
+ where C, D and E are the feature commits
+:ecgraphic.
+
+:p.
+In the latter case, it is impossible to see from the Git history which of the
+commit objects together have implemented a feature -- you would have to manually
+read all the log messages. Reverting a whole feature (i.e. a group of commits),
+is a true headache in the latter situation, whereas it is easily done if the
+:hp2.--no-ff:ehp2. flag was used.
+
+:p.
+Yes, it will create a few more (empty) commit objects, but the gain is much
+bigger that that cost.
+
+:p.
+Unfortunately, I have not found a way to make :hp2.--no-ff:ehp2. the default behaviour of
+:hp2.git merge:ehp2. yet, but it really should be.
+
+
+.* -------------------------------------
+:h2.Release branches
+:p.
+May branch off from: :hp8.develop:ehp8.
+.br
+Must merge back into: :hp8.develop:ehp8. and :hp8.master:ehp8.
+.br
+Branch naming convention: :hp8.release-*:ehp8.
+
+:p.
+Release branches support preparation of a new production release. They allow
+for last-minute dotting of i's and crossing t's. Furthermore, they allow for
+minor bug fixes and preparing meta-data for a release (version number, build
+dates, etc.). By doing all of this work on a release branch, the :hp8.develop:ehp8. branch
+is cleared to receive features for the next big release.
+
+:p.
+The key moment to branch off a new release branch from :hp8.develop:ehp8. is when develop
+(almost) reflects the desired state of the new release. At least all features
+that are targeted for the release-to-be-built must be merged in to develop at
+this point in time. All features targeted at future releases may not -- they must
+wait until after the release branch is branched off.
+
+:p.
+It is exactly at the start of a release branch that the upcoming release gets
+assigned a version number -- not any earlier. Up until that moment, the :hp8.develop:ehp8.
+branch reflected changes for the "next release", but it is unclear whether
+that "next release" will eventually become 0.3 or 1.0, until the release branch
+is started. That decision is made on the start of the release branch and is
+carried out by the project's rules on version number bumping.
+
+:h3.Creating a release branch
+:p.
+Release branches are created from the develop branch. For example, say version
+1.1.5 is the current production release and we have a big release coming up.
+The state of develop is ready for the "next release" and we have decided that
+this will become version 1.2 (rather than 1.1.6 or 2.0). So we branch off and
+give the release branch a name reflecting the new version number:
+
+:lm margin=5.
+:xmp.
+$ git checkout -b release-1.2 develop
+Switched to a new branch "release-1.2"
+$ ./bump-version.sh 1.2
+Files modified successfully, version bumped to 1.2.
+$ git commit -a -m "Bumped version number to 1.2"
+[release-1.2 74d9424] Bumped version number to 1.2
+1 files changed, 1 insertions(+), 1 deletions(-)
+:exmp.
+:lm margin=1.
+
+:p.
+After creating a new branch and switching to it, we bump the version number.
+Here, :hp2.bump-version.sh:ehp2. is a fictional shell script that changes some files in
+the working copy to reflect the new version. (This can of course be a manual
+change -- the point being that some files change.) Then, the bumped version number
+is committed.
+
+:p.
+This new branch may exist there for a while, until the release may be rolled
+out definitely. During that time, bug fixes may be applied in this branch
+(rather than on the :hp8.develop:ehp8. branch). Adding large new features here is strictly
+prohibited. They must be merged into :hp8.develop:ehp8., and therefore, wait for the next
+big release.
+
+:h3.Finishing a release branch
+:p.
+When the state of the release branch is ready to become a real release, some
+actions need to be carried out. First, the release branch is merged into :hp8.master:ehp8.
+(since every commit on :hp8.master:ehp8. is a new release by definition, remember). Next,
+that commit on :hp8.master:ehp8. must be tagged for easy future reference to this
+historical version. Finally, the changes made on the release branch need to be
+merged back into :hp8.develop:ehp8., so that future releases also contain these bug fixes.
+
+:p.
+The first two steps in Git:
+
+:lm margin=5.
+:xmp.
+$ git checkout master
+Switched to branch 'master'
+$ git merge --no-ff release-1.2
+Merge made by recursive.
+(Summary of changes)
+$ git tag -a 1.2
+:exmp.
+:lm margin=1.
+
+:p.
+The release is now done, and tagged for future reference. You might as well
+use the -s or -u <key> flags to sign your tag cryptographically.
+
+:p.
+To keep the changes made in the release branch, we need to merge those back
+into :hp8.develop:ehp8., though. In Git:
+
+:lm margin=5.
+:xmp.
+$ git checkout develop
+Switched to branch 'develop'
+$ git merge --no-ff release-1.2
+Merge made by recursive.
+(Summary of changes)
+:exmp.
+:lm margin=1.
+
+:p.
+This step may well lead to a merge conflict (probably even, since we have
+changed the version number). If so, fix it and commit.
+
+:p.
+Now we are really done and the release branch may be removed, since we don't
+need it anymore:
+
+:lm margin=5.
+:xmp.
+$ git branch -d release-1.2
+Deleted branch release-1.2 (was ff452fe).
+:exmp.
+:lm margin=1.
+
+
+
+.* -------------------------------------
+:h2.Hotfix branches
+:p.
+May branch off from: :hp8.master:ehp8.
+.br
+Must merge back into: :hp8.develop:ehp8. and :hp8.master:ehp8.
+.br
+Branch naming convention: :hp8.hotfix-*:ehp8.
+
+:p.
+Hotfix branches are very much like release branches in that they are also meant
+to prepare for a new production release, albeit unplanned. They arise from the
+necessity to act immediately upon an undesired state of a live production version.
+When a critical bug in a production version must be resolved immediately, a
+hotfix branch may be branched off from the corresponding tag on the master
+branch that marks the production version.
+
+:p.
+The essence is that work of team members (on the :hp8.develop:ehp8. branch) can continue,
+while another person is preparing a quick production fix.
+
+
+:h3.Creating the hotfix branch
+:p.
+Hotfix branches are created from the :hp8.master:ehp8. branch. For example, say version
+1.2 is the current production release running live and causing troubles due
+to a severe bug. But changes on :hp8.develop:ehp8. are yet unstable. We may then branch
+off a hotfix branch and start fixing the problem:
+
+:lm margin=5.
+:xmp.
+$ git checkout -b hotfix-1.2.1 master
+Switched to a new branch "hotfix-1.2.1"
+$ ./bump-version.sh 1.2.1
+Files modified successfully, version bumped to 1.2.1.
+$ git commit -a -m "Bumped version number to 1.2.1"
+[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
+1 files changed, 1 insertions(+), 1 deletions(-)
+:exmp.
+:lm margin=1.
+
+:p.
+Don't forget to bump the version number after branching off!
+
+:p.
+Then, fix the bug and commit the fix in one or more separate commits.
+
+:lm margin=5.
+:xmp.
+$ git commit -m "Fixed severe production problem"
+[hotfix-1.2.1 abbe5d6] Fixed severe production problem
+5 files changed, 32 insertions(+), 17 deletions(-)
+:exmp.
+:lm margin=1.
+
+
+:h3.Finishing a hotfix branch
+:p.
+When finished, the bugfix needs to be merged back into :hp8.master:ehp8., but also needs
+to be merged back into :hp8.develop:ehp8., in order to safeguard that the bugfix is
+included in the next release as well. This is completely similar to how
+release branches are finished.
+
+:p.
+First, update :hp8.master:ehp8. and tag the release.
+
+:lm margin=5.
+:xmp.
+$ git checkout master
+Switched to branch 'master'
+$ git merge --no-ff hotfix-1.2.1
+Merge made by recursive.
+(Summary of changes)
+$ git tag -a 1.2.1
+:exmp.
+:lm margin=1.
+
+:p.
+You might as well use the -s or -u <key> flags to sign your tag cryptographically.
+
+:p.
+Next, include the bugfix in :hp8.develop:ehp8., too:
+
+:lm margin=5.
+:xmp.
+$ git checkout develop
+Switched to branch 'develop'
+$ git merge --no-ff hotfix-1.2.1
+Merge made by recursive.
+(Summary of changes)
+:exmp.
+:lm margin=1.
+
+:p.
+The one exception to the rule here is that, :hp2.when a release branch currently
+exists, the hotfix changes need to be merged into that release branch, instead
+of develop:ehp2.. Back-merging the bugfix into the release branch will eventually
+result in the bugfix being merged into :hp8.develop:ehp8. too, when the release branch is
+finished. (If work in :hp8.develop:ehp8. immediately requires this bugfix and cannot wait
+for the release branch to be finished, you may safely merge the bugfix into
+:hp8.develop:ehp8. now already as well.)
+
+:p.
+Finally, remove the temporary branch:
+
+:lm margin=5.
+:xmp.
+$ git branch -d hotfix-1.2.1
+Deleted branch hotfix-1.2.1 (was abbe5d6).
+:exmp.
+:lm margin=1.
+
+
+:h2.Summary
+:p.
+While there is nothing really shocking new to this branching model, the "big
+picture" figure that this post began with has turned out to be tremendously
+useful in our projects. It forms an elegant mental model that is easy to
+comprehend and allows team members to develop a shared understanding of the
+branching and releasing processes.
+
+:p.
+This document is based on an article found at http://nvie.com/posts/a-successful-git-branching-model/
+
+
+
+
+:euserdoc.
+
diff --git a/docview/TODO.txt b/docview/TODO.txt
index 886161c8..d0cccc7c 100644
--- a/docview/TODO.txt
+++ b/docview/TODO.txt
@@ -23,11 +23,11 @@ Todo list
[ ] - RichTextView component issue. Incompatible with original OS/2 VIEW. When
resetting a font style (eg: italics to normal), it should not affect a
previously set font color, unless a new font color is explicitly set.
-[ ] - External links are not supported yet.
[o] - Implement Image support in INF or HLP files.
+[x] - External links are not supported yet.
[x] - Access Violation when the application terminates.
[x] - Settings / Customization dialog is needed.
[x] - Create help file for DocView listing all supported features etc..
diff --git a/docview/docs/codepage_2_unicode_mapping/reame.txt b/docview/docs/codepage_2_unicode_mapping/readme.txt
index 33b26a53..33b26a53 100644
--- a/docview/docs/codepage_2_unicode_mapping/reame.txt
+++ b/docview/docs/codepage_2_unicode_mapping/readme.txt
diff --git a/docview/docs/docview.ipf b/docview/docs/docview.ipf
index 567ef1bd..94099582 100644
--- a/docview/docs/docview.ipf
+++ b/docview/docs/docview.ipf
@@ -422,6 +422,7 @@ search result. Searches are :hp2.not:ehp2. case-sensitive.
.* Notes
.* ************************************************************
:h2 res=7 id='notes'.Notes
+:i1.Annotate
:hp2.Adding and Using Notes:ehp2.
:p.
&dv. allows you to add notes (annotations) to your help
@@ -568,7 +569,6 @@ you open a new or additional help file.
.* ************************************************************
:h1 res=8 id='bookmarks'.Bookmarks
:hp2.Bookmarks:ehp2.
-:note.:hp8.*** This feature is partially implemented. ***:ehp8.
:p.
&dv. allows you to bookmark particular topics within the current help
file. Simply click the bookmark toolbar button
@@ -579,16 +579,16 @@ To jump to a bookmark, go to the "Bookmarks" menu, and click on
the bookmark you want to open.
:p.
You can view or delete all your bookmarks by clicking on "Edit..." in
-the "Bookmarks" menu. This window can remain open while you read, so
-that you can quickly look through your bookmarks.
+the "Bookmarks" menu.
:p.
Bookmarks are saved in a file with the extension ".bookmarks", in the &dv. config
directory. This is in the user's home profile directory where there is read/write
access. Under Linux it is normally "~/.config/docview/" and under Windows it is
normally "C:\Documents and Settings\<user>\Local Settings\Application Data\docview".
-I will probably add a setting in &dv., so the user can configure a
-preferred storage location for bookmarks (eg: some users prefer it like OS/2's View program did,
-by storing notes in the same directory as the help file).
+.* TODO
+.* I will probably add a setting in &dv., so the user can configure a
+.* preferred storage location for bookmarks (eg: some users prefer it like OS/2's View program did,
+.* by storing notes in the same directory as the help file).
.* ************************************************************
@@ -817,55 +817,90 @@ file names), so the environment variable "MYHELP" is not equal to "myhelp".
.* ************************************************************
.* Keyboard Shortcuts
.* ************************************************************
-.* TODO
-.* :h1 res=10 id='KeyboardShortcuts'.
-.* Keyboard Shortcuts
-.* :p.:hp2.Keyboard Shortcuts:ehp2.
-.* :p.Most keyboard shortcuts are visible in the menu&comma. but a few are not&per.
-.* The additional shortcuts are&colon.
-.* :p.:hp2.Alt&plus.F4:ehp2. Exit
-.* :p.:hp2.Ctrl&plus.C:ehp2. Copy selected text to clipboard
-.* :p.:hp2.F7:ehp2. Back
-.* :p.:hp2.F8:ehp2. Forward
-.* :p.:hp2.Ctrl&plus.Left:ehp2. Back
-.* :p.:hp2.F11:ehp2. Previous in contents
-.* :p.:hp2.F12:ehp2. Next in contents
-.* :p.
-.* :p.:hp2.Shortcuts visible in the menu:ehp2.
-.* :p.:hp2.Ctrl&plus.O:ehp2. Open files
-.* :p.:hp2.Ctrl&plus.E:ehp2. Open files from help paths
-.* :p.:hp2.Ctrl&plus.N:ehp2. Open a new window
-.* :p.:hp2.Ctrl&plus.P:ehp2. Print topic
-.* :p.:hp2.F3:ehp2. Exit
-.* :p.
-.* :p.
-.* :p.:hp2.Ctrl&plus.A:ehp2. Select all text in topic
-.* :p.:hp2.Ctrl&plus.Ins:ehp2. Copy selected text to clipboard
-.* :p.
-.* :p.:hp2.Ctrl&plus.F:ehp2. Find within current topic
-.* :p.:hp2.Ctrl&plus.G:ehp2. Repeat last find
-.* :p.
-.* :p.:hp2.Ctrl&plus.S:ehp2. Open global search tool
-.* :p.
-.* :p.:hp2.Alt&plus.C:ehp2. Change to the contents tab
-.* :p.:hp2.Alt&plus.I:ehp2. Change to the index tab
-.* :p.:hp2.Alt&plus.S:ehp2. Change to the search tab
-.* :p.:hp2.Alt&plus.N:ehp2. Change to the notes tab
-.* :p.:hp2.Alt&plus.P:ehp2. Toggle the left panel &lpar.tabs&rpar. on and off
-.* :p.:hp2.F5:ehp2. Expand all contents
-.* :p.:hp2.F6:ehp2. Collapse all contents
-.* :p.
-.* :p.:hp2.Esc:ehp2. Back
-.* :p.:hp2.Ctrl&plus.Right:ehp2. Forward
-.* :p.:hp2.Ctrl&plus.Up:ehp2. Previous topic in contents
-.* :p.:hp2.Ctrl&plus.Down:ehp2. Next topic in contents
-.* :p.
-.* :p.:hp2.Ctrl&plus.D:ehp2. Edit bookmarks
-.* :p.:hp2.Ctrl&plus.B:ehp2. Bookmark current topic
-.* :p.
-.* :p.:hp2.Ctrl&plus.M:ehp2. Add note at cursor position
-.* :p.
-.* :p.:hp2.F1:ehp2. Help for &dv.
+:h1 res=10 id='KeyboardShortcuts'.Keyboard Shortcuts
+:p.:hp2.Keyboard Shortcuts:ehp2.
+:p.Most keyboard shortcuts are visible in the menu, but a few are not.
+Here is a list of keyboard shortcuts supported by &dv.:
+
+:table rules=vert frame=box cols='45 20'.
+:row.
+:c.:hp2.TASK:ehp2.
+:c.:hp2.PRESS:ehp2.
+
+:row.
+:c.----------
+:c.----------
+
+:row.
+:c.Open File
+:c.Ctrl+O
+
+:row.
+:c.Open Additional Files
+:c.Ctrl+Shift+O
+
+:row.
+:c.Open Special (eg: environment variable)
+:c.Ctrl+L
+
+:row.
+:c.Save Current Top
+:c.Ctrl+S
+
+:row.
+:c.Quit &dv.
+:c.Ctrl+Q
+
+:row.
+:c.Switch to Contents tab
+:c.F5
+
+:row.
+:c.Switch to Index tab
+:c.F6
+
+:row.
+:c.Switch to Search tab
+:c.F7
+
+:row.
+:c.Switch to Notes tab
+:c.F8
+
+:row.
+:c.Switch to History tab
+:c.F9
+
+:row.
+:c.Navigate Back
+:c.Ctrl+left arrow
+
+:row.
+:c.Navigate Forward
+:c.Ctrl+right arrow
+
+:row.
+:c.Navigate to previous topic in contents
+:c.Ctrl+up arrow
+
+:row.
+:c.Navigate to next topic in contents
+:c.Ctrl+down arrow
+
+:row.
+:c.Bookmark current topic
+:c.Ctrl+B
+
+:row.
+:c.Edit Bookmarks
+:c.Ctrl+M
+
+:row.
+:c.Add note (annotations) at cursor position
+:c.Ctrl+M
+
+:etable.
+
.* ************************************************************
diff --git a/docview/src/HelpBitmap.pas b/docview/src/HelpBitmap.pas
index 0931ce82..692bf64d 100644
--- a/docview/src/HelpBitmap.pas
+++ b/docview/src/HelpBitmap.pas
@@ -1,14 +1,32 @@
+{
+ fpGUI - Free Pascal GUI Toolkit
+
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Description:
+ Encapsulates a bitmap as stored in a IPF file. Once created from
+ file data they can be used as a normal bitmap.
+}
+
unit HelpBitmap;
{$mode objfpc}{$H+}
-interface
+// Debug purposes only
+{.$define LZW_DEBUG}
-// Encapsulates a bitmap as stored in a IPF file.
-// Once created from file data they can be used as a normal bitmap.
+interface
uses
- Classes, SysUtils, fpg_main, ctypes,
+ Classes, SysUtils, fpg_main,
IPFFileFormatUnit;
type
@@ -65,7 +83,6 @@ type
_UncompressedBlockSize: longint;
function GetPaletteSize: longint;
procedure BitmapError(Msg: string);
- procedure DecompressLZW(var Buffer: Pointer; const Count: integer; var NewBuffer: PByte; var NewCount: integer);
procedure ReadBitmapData( Blocks: TList; TotalSize: longint );
public
constructor CreateFromHelpFile(var AFileHandle: TFileStream; Offset: longint);
@@ -73,19 +90,13 @@ type
end;
-var
- LZWDecompressBlock: function( pInput: PBYTE;
- pOutput: PBYTE;
- bytesIn: uint32;
- Var bytesOut: uint32;
- Var FinalCode: byte ): Boolean;
-// APIENTRY;
-// 'newview' index 1;
-
implementation
uses
- nvUtilities, Math, fpg_imgfmt_bmp;
+ nvUtilities,
+ Math,
+ LZWDecompress,
+ fpg_imgfmt_bmp;
const
BFT_bMAP =$4d62; // 'bM'
@@ -102,9 +113,15 @@ type
_Size: uint16;
_CompressionType: uint8;
_Data: PBYTE;
+ constructor Create;
destructor Destroy; override;
end;
+constructor TBitmapBlock.Create;
+begin
+ _Data := nil;
+end;
+
destructor TBitmapBlock.Destroy;
begin
FreeMem( _Data );
@@ -119,7 +136,6 @@ var
BytesRead: longint;
Block: TBitmapBlock;
- p: pointer;
Blocks: TList;
BlockIndex: longint;
ImageType: uint16;
@@ -154,7 +170,8 @@ begin
if _Header.usType <> BFT_bMAP then
raise EHelpBitmapException.Create( 'Invalid bitmap header' );
- _Header.usType := $4d42; // sibyl only accepts 'BM' not 'bM'
+// Graeme: we don't need to do this any more. It was only for Sybil
+// _Header.usType := $4d42; // sibyl only accepts 'BM' not 'bM'
// We can only parse bitmaps with 1 colour plane
// (I can't be bothered and have never seen bitmaps
@@ -174,19 +191,19 @@ begin
_BitsSize := LineSize * _Header.cy;
// Correct header offset - it is wrong in the header (why?)
- _Header.OffBits := sizeof( _Header ) + GetPaletteSize; // TODO: Graeme, double check this!
+ _Header.OffBits := sizeof( _Header ) + GetPaletteSize;
// Load palette
if _Header.cBitCount <= 8 then
begin
_pPalette := GetMem( GetPaletteSize );
- bytes := FileHandle.Read(_pPalette, GetPaletteSize);
+ bytes := FileHandle.Read(_pPalette^, GetPaletteSize);
if bytes <> GetPaletteSize then
raise EHelpBitmapException.Create( 'Failed to read Palette.' );
end;
// Read data header
- FillChar( DataHeader, sizeof( DataHeader ), 0 );
+// FillChar( DataHeader, sizeof( DataHeader ), 0 );
bytes := FileHandle.Read(DataHeader, SizeOf(DataHeader));
if bytes <> SizeOf(DataHeader) then
raise EHelpBitmapException.Create( 'Failed to read DataHeader.' );
@@ -214,7 +231,7 @@ begin
// Now read the block
Block._Data := GetMem( Block._Size );
- FileHandle.Read(Block._Data, Block._Size);
+ FileHandle.Read(Block._Data^, Block._Size);
inc( BytesRead, Block._Size );
Blocks.Add( Block );
@@ -250,227 +267,7 @@ begin
inherited Destroy;
end;
-procedure THelpBitmap.DecompressLZW(var Buffer: Pointer; const Count: Integer; var NewBuffer: PByte; var NewCount: integer);
-type
- TLZWString = packed record
- Count: integer;
- Data: PByte;
- end;
- PLZWString = ^TLZWString;
-const
- ClearCode = 256; // clear table, start with 9bit codes
- EoiCode = 257; // end of input
-var
-// NewBuffer: PByte;
-// NewCount: PtrInt;
- NewCapacity: PtrInt;
- SrcPos: PtrInt;
- SrcPosBit: integer;
- CurBitLength: integer;
- Code: Word;
- Table: PLZWString;
- TableCapacity: integer;
- TableCount: integer;
- OldCode: Word;
-
- function GetNextCode: Word;
- var
- v: Integer;
- begin
- Result:=0;
- // CurBitLength can be 9 to 12
- //writeln('GetNextCode CurBitLength=',CurBitLength,' SrcPos=',SrcPos,' SrcPosBit=',SrcPosBit,' ',hexstr(PByte(Buffer)[SrcPos],2),' ',hexstr(PByte(Buffer)[SrcPos+1],2),' ',hexstr(PByte(Buffer)[SrcPos+2],2));
- // read two or three bytes
- if CurBitLength+SrcPosBit>16 then begin
- // read from three bytes
- if SrcPos+3>Count then BitmapError('LZW stream overrun');
- v:=PByte(Buffer)[SrcPos];
- inc(SrcPos);
- v:=(v shl 8)+PByte(Buffer)[SrcPos];
- inc(SrcPos);
- v:=(v shl 8)+PByte(Buffer)[SrcPos];
- v:=v shr (24-CurBitLength-SrcPosBit);
- end else begin
- // read from two bytes
- if SrcPos+2>Count then BitmapError('LZW stream overrun');
- v:=PByte(Buffer)[SrcPos];
- inc(SrcPos);
- v:=(v shl 8)+PByte(Buffer)[SrcPos];
- if CurBitLength+SrcPosBit=16 then
- inc(SrcPos);
- v:=v shr (16-CurBitLength-SrcPosBit);
- end;
- Result:=v and ((1 shl CurBitLength)-1);
- SrcPosBit:=(SrcPosBit+CurBitLength) and 7;
- //writeln('GetNextCode END SrcPos=',SrcPos,' SrcPosBit=',SrcPosBit,' Result=',Result,' Result=',hexstr(Result,4));
- end;
-
- procedure ClearTable;
- var
- i: Integer;
- begin
- for i:=0 to TableCount-1 do
- ReAllocMem(Table[i].Data,0);
- TableCount:=0;
- end;
-
- procedure InitializeTable;
- begin
- CurBitLength:=9;
- ClearTable;
- end;
-
- function IsInTable(Code: word): boolean;
- begin
- Result:=Code<258+TableCount;
- end;
-
- procedure WriteStringFromCode(Code: integer; AddFirstChar: boolean = false);
- var
- s: TLZWString;
- b: byte;
- begin
- //WriteLn('WriteStringFromCode Code=',Code,' AddFirstChar=',AddFirstChar,' x=',(NewCount div 4) mod IDF.ImageWidth,' y=',(NewCount div 4) div IDF.ImageWidth,' PixelByte=',NewCount mod 4);
- if Code<256 then begin
- // write byte
- b:=Code;
- s.Data:=@b;
- s.Count:=1;
- end else if Code>=258 then begin
- // write string
- if Code-258>=TableCount then
- BitmapError('LZW code out of bounds');
- s:=Table[Code-258];
- end else
- BitmapError('LZW code out of bounds');
- if NewCount+s.Count+1>NewCapacity then begin
- NewCapacity:=NewCapacity*2+8;
- ReAllocMem(NewBuffer,NewCapacity);
- end;
- System.Move(s.Data^,NewBuffer[NewCount],s.Count);
- //for i:=0 to s.Count-1 do write(HexStr(NewBuffer[NewCount+i],2)); // debug
- inc(NewCount,s.Count);
- if AddFirstChar then begin
- NewBuffer[NewCount]:=s.Data^;
- //write(HexStr(NewBuffer[NewCount],2)); // debug
- inc(NewCount);
- end;
- //writeln(',WriteStringFromCode'); // debug
- end;
-
- procedure AddStringToTable(Code, AddFirstCharFromCode: integer);
- // add string from code plus first character of string from code as new string
- var
- b1, b2: byte;
- s1, s2: TLZWString;
- p: PByte;
- begin
- //WriteLn('AddStringToTable Code=',Code,' FCFCode=',AddFirstCharFromCode,' TableCount=',TableCount,' TableCapacity=',TableCapacity);
- // grow table
- if TableCount>=TableCapacity then begin
- TableCapacity:=TableCapacity*2+128;
- ReAllocMem(Table,TableCapacity*SizeOf(TLZWString));
- end;
- // find string 1
- if Code<256 then begin
- // string is byte
- b1:=Code;
- s1.Data:=@b1;
- s1.Count:=1;
- end else if Code>=258 then begin
- // normal string
- if Code-258>=TableCount then
- BitmapError('LZW code out of bounds');
- s1:=Table[Code-258];
- end else
- BitmapError('LZW code out of bounds');
- // find string 2
- if AddFirstCharFromCode<256 then begin
- // string is byte
- b2:=AddFirstCharFromCode;
- s2.Data:=@b2;
- s2.Count:=1;
- end else begin
- // normal string
- if AddFirstCharFromCode-258>=TableCount then
- BitmapError('LZW code out of bounds');
- s2:=Table[AddFirstCharFromCode-258];
- end;
- // set new table entry
- Table[TableCount].Count:=s1.Count+1;
- p:=nil;
- GetMem(p,s1.Count+1);
- Table[TableCount].Data:=p;
- System.Move(s1.Data^,p^,s1.Count);
- // add first character from string 2
- p[s1.Count]:=s2.Data^;
- // increase TableCount
- inc(TableCount);
- case TableCount+259 of
- 512,1024,2048: inc(CurBitLength);
- 4096: BitmapError('LZW too many codes');
- end;
- end;
-
-begin
- if Count=0 then exit;
- //WriteLn('TFPReaderTiff.DecompressLZW START Count=',Count);
- //for SrcPos:=0 to 19 do
- // write(HexStr(PByte(Buffer)[SrcPos],2));
- //writeln();
-
- NewBuffer:=nil;
- NewCount:=0;
- NewCapacity:=Count*2;
- ReAllocMem(NewBuffer,NewCapacity);
-
- SrcPos:=0;
- SrcPosBit:=0;
- CurBitLength:=9;
- Table:=nil;
- TableCount:=0;
- TableCapacity:=0;
- try
- repeat
- Code:=GetNextCode;
- //WriteLn('TFPReaderTiff.DecompressLZW Code=',Code);
- if Code=EoiCode then break;
- if Code=ClearCode then begin
- InitializeTable;
- Code:=GetNextCode;
- //WriteLn('TFPReaderTiff.DecompressLZW after clear Code=',Code);
- if Code=EoiCode then break;
- if Code=ClearCode then
- BitmapError('LZW code out of bounds');
- WriteStringFromCode(Code);
- OldCode:=Code;
- end else begin
- if Code<TableCount+258 then begin
- WriteStringFromCode(Code);
- AddStringToTable(OldCode,Code);
- OldCode:=Code;
- end else if Code=TableCount+258 then begin
- WriteStringFromCode(OldCode,true);
- AddStringToTable(OldCode,OldCode);
- OldCode:=Code;
- end else
- BitmapError('LZW code out of bounds');
- end;
- until false;
- finally
- ClearTable;
- ReAllocMem(Table,0);
- end;
-
- ReAllocMem(NewBuffer,NewCount);
-// FreeMem(Buffer);
-// Buffer:=NewBuffer;
-// Count:=NewCount;
-end;
-
-
-procedure THelpBitmap.ReadBitmapData( Blocks: TList;
- TotalSize: longint );
+procedure THelpBitmap.ReadBitmapData( Blocks: TList; TotalSize: longint );
var
BytesWritten: longint;
BytesWrittenFromBlock: longword;
@@ -483,16 +280,22 @@ var
BlockIndex: longint;
BitmapData: PBYTE;
ptr: PByte;
+ i: integer;
+ img: TfpgImage;
begin
+ BitmapOutputPointer := nil;
+ BitmapData := nil;
+ ptr := nil;
+
// Allocate memory to store the bitmap
- Bitmapdata := GetMem( TotalSize );
+ BitmapData := GetMem( TotalSize );
// Copy header to bitmap
- MemCopy( _Header, BitmapData, sizeof( _Header ) );
+ MemCopy( _Header, BitmapData^, sizeof( _Header ) );
// Copy palette into bitmap
ptr := BitmapData + sizeof( _Header );
- MemCopy( _pPalette, ptr, GetPaletteSize );
+ MemCopy( _pPalette^, ptr^, GetPaletteSize );
BytesWritten := 0;
@@ -506,23 +309,18 @@ begin
case Block._CompressionType of
0,1: // uncompressed (I'm not sure about 1)
begin
- MemCopy( Block._Data, BitmapOutputPointer, Block._Size );
+ MemCopy( Block._Data^, BitmapOutputPointer^, Block._Size );
BytesWrittenFromBlock := Block._Size;
inc( BytesWritten, BytesWrittenFromBlock );
end;
2: // LZW compression
begin
- // decompress block
- if not Assigned( LZWDecompressBlock )then
- raise EHelpBitmapException.Create( 'Cannot decode bitmap - DLL not found' );
-
-// DecompressLZW(Block._Data, Block._Size);
- //LZWDecompressBlock( Block._Data,
- // BitmapOutputPointer,
- // Block._Size,
- // BytesWrittenFromBlock,
- // lastOutByte );
+ LZWDecompressBlock( Block._Data,
+ Block._Size,
+ BitmapOutputPointer,
+ BytesWrittenFromBlock,
+ lastOutByte );
inc( BytesWritten, BytesWrittenFromBlock );
@@ -555,15 +353,37 @@ begin
> BitmapData + TotalSize ) then
assert( false );
- inc( BitmapOutputPointer, BytesWrittenFromBlock );
+{ NOTE: This doesn't seem right. It moves the pointer so later the moving of data to
+ ImageData will be wrong! }
+// inc( BitmapOutputPointer, BytesWrittenFromBlock ); TPersistentObjectState
end;
+ i := TotalSize + SizeOf(_Header) + GetPaletteSize;
+ img := CreateImage_BMP(BitmapData, i);
AllocateImage(32, _Header.cx, _Header.cy);
- if TotalSize <> ImageDataSize then
- writeln('Warning: INF Bitmap size and allocated bitmap size are different. ', TotalSize, ' vs ', ImageDataSize);
- Move(BitmapData^, ImageData^, TotalSize);
+
+ {$IFDEF LZW_DEBUG}
+ writeln('Width = ', Width);
+ writeln('Height = ', Height);
+ writeln('ImageDataSize = ', ImageDataSize);
+ writeln('------------- START -------------');
+ for i := 1 to ImageDataSize do
+ begin
+ write(HexStr(BitmapOutputPointer[i-1],2)+' ');
+ if (i mod 16 = 0) then
+ writeln('')
+ else if (i mod 4 = 0) then
+ write (' | ');
+ end;
+ Writeln('');
+ writeln('------------- END -------------');
+ {$ENDIF}
+
+// Move(BitmapOutputPointer^, ImageData^, ImageDataSize);
+ Move(img.ImageData^, self.ImageData^, img.ImageDataSize);
UpdateImage;
+ img.Free;
FreeMem( BitmapData, TotalSize );
end;
diff --git a/docview/src/HelpFile.pas b/docview/src/HelpFile.pas
index cc4657d9..ce3d9f8a 100644
--- a/docview/src/HelpFile.pas
+++ b/docview/src/HelpFile.pas
@@ -321,29 +321,6 @@ const
entries.AddObject(anIndexEntry.getLabel, anIndexEntry);
end;
-
-
-
-//Procedure OnLanguageEvent( Language: TLanguageFile;
-// const Apply: boolean );
-//var
-// tmpPrefix : String;
-//begin
-// tmpPrefix := 'HelpFile' + LANGUAGE_LABEL_DELIMITER;
-//
-// Language.LL( Apply, FileErrorNotFound, tmpPrefix + 'FileErrorNotFound', 'File not found' );
-// Language.LL( Apply, FileErrorAccessDenied, tmpPrefix + 'FileErrorAccessDenied', 'Access denied' );
-// Language.LL( Apply, FileErrorInUse, tmpPrefix + 'FileErrorInUse', 'File in use by another program' );
-// Language.LL( Apply,
-// FileErrorInvalidHeader,
-// tmpPrefix + 'FileErrorInvalidHeader',
-// 'File doesn''t appear to be an OS/2 Help document (header ID not correct)' );
-// Language.LL( Apply,
-// ErrorCorruptHelpFile,
-// tmpPrefix + 'ErrorCorruptHelpFile',
-// 'File is corrupt' );
-//end;
-
Function TopicFile( Topic: TTopic ): THelpFile;
Begin
Result := Topic.HelpFile as THelpFile;
@@ -1119,9 +1096,7 @@ begin
+ ': '
+ e.Message );}
begin
-// Bitmap := THelpBitmap.Create;
Bitmap := THelpBitmap(fpgImages.GetImage('stdimg.dlg.critical'));
-// Bitmap.LoadFromResourceName( 'MissingBitmap' ); // TODO: Add image resource to DocView
end;
end;
diff --git a/docview/src/HelpTopic.pas b/docview/src/HelpTopic.pas
index 5a8245a7..a9b981f1 100644
--- a/docview/src/HelpTopic.pas
+++ b/docview/src/HelpTopic.pas
@@ -231,7 +231,7 @@ implementation
uses
SysUtils
- ,NewViewConstantsUnit
+ ,dvConstants
,nvUtilities
,ACLStringUtility
,SettingsUnit
diff --git a/docview/src/NewViewConstantsUnit.pas b/docview/src/NewViewConstantsUnit.pas
deleted file mode 100644
index 2aed1cd0..00000000
--- a/docview/src/NewViewConstantsUnit.pas
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- fpGUI - Free Pascal GUI Toolkit
-
- Copyright (C) 2006 - 2010 See the file AUTHORS.txt, included in this
- distribution, for details of the copyright.
-
- See the file COPYING.modifiedLGPL, included in this distribution,
- for details about redistributing fpGUI.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- Description:
- Common used constants for DocView
-}
-unit NewViewConstantsUnit;
-
-{$mode objfpc}{$H+}
-
-interface
-
-const
- PARAM_LINK_NOTE = 'note';
- PARAM_LINK_PROGRAM = 'program';
- PARAM_LINK_URL = 'url';
- PARAM_LINK_EXTERNAL = 'external';
-
- PRGM_EXPLORER = 'explore'; // web explorer
- PRGM_NETSCAPE = 'netscape';
- PRGM_MOZILLA = 'mozilla';
- PRGM_FIREFOX = 'firefox';
-
-
-implementation
-
-end.
diff --git a/docview/src/docview.lpi b/docview/src/docview.lpi
index 30c8e7ff..6fc2c4cb 100644
--- a/docview/src/docview.lpi
+++ b/docview/src/docview.lpi
@@ -23,6 +23,7 @@
<RunParams>
<local>
<FormatVersion Value="1"/>
+ <CommandLineParams Value="/data/devel/tests/inf_test/test2.inf"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
@@ -31,7 +32,7 @@
<PackageName Value="fpgui_toolkit"/>
</Item1>
</RequiredPackages>
- <Units Count="36">
+ <Units Count="37">
<Unit0>
<Filename Value="docview.lpr"/>
<IsPartOfProject Value="True"/>
@@ -132,80 +133,85 @@
<UnitName Value="HelpWindowDimensions"/>
</Unit19>
<Unit20>
- <Filename Value="NewViewConstantsUnit.pas"/>
+ <Filename Value="SettingsUnit.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="NewViewConstantsUnit"/>
+ <UnitName Value="SettingsUnit"/>
</Unit20>
<Unit21>
- <Filename Value="SettingsUnit.pas"/>
+ <Filename Value="dvconstants.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="SettingsUnit"/>
+ <UnitName Value="dvConstants"/>
</Unit21>
<Unit22>
- <Filename Value="dvconstants.pas"/>
+ <Filename Value="dvHelpers.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="dvConstants"/>
+ <UnitName Value="dvHelpers"/>
</Unit22>
<Unit23>
- <Filename Value="dvHelpers.pas"/>
+ <Filename Value="HelpWindow.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="dvHelpers"/>
+ <UnitName Value="HelpWindow"/>
</Unit23>
<Unit24>
- <Filename Value="HelpWindow.pas"/>
+ <Filename Value="../TODO.txt"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="HelpWindow"/>
</Unit24>
<Unit25>
- <Filename Value="../TODO.txt"/>
+ <Filename Value="frm_configuration.pas"/>
<IsPartOfProject Value="True"/>
+ <UnitName Value="frm_configuration"/>
</Unit25>
<Unit26>
- <Filename Value="frm_configuration.pas"/>
+ <Filename Value="arrows.inc"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="frm_configuration"/>
</Unit26>
<Unit27>
- <Filename Value="arrows.inc"/>
+ <Filename Value="HelpBitmap.pas"/>
<IsPartOfProject Value="True"/>
+ <UnitName Value="HelpBitmap"/>
</Unit27>
<Unit28>
- <Filename Value="HelpBitmap.pas"/>
+ <Filename Value="missing.inc"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="HelpBitmap"/>
</Unit28>
<Unit29>
- <Filename Value="missing.inc"/>
+ <Filename Value="frm_text.pas"/>
<IsPartOfProject Value="True"/>
+ <UnitName Value="frm_text"/>
</Unit29>
<Unit30>
- <Filename Value="frm_text.pas"/>
+ <Filename Value="docview.rc"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="frm_text"/>
</Unit30>
<Unit31>
- <Filename Value="docview.rc"/>
+ <Filename Value="../docs/docview.ipf"/>
<IsPartOfProject Value="True"/>
</Unit31>
<Unit32>
- <Filename Value="../docs/docview.ipf"/>
+ <Filename Value="frm_note.pas"/>
<IsPartOfProject Value="True"/>
+ <UnitName Value="frm_note"/>
</Unit32>
<Unit33>
- <Filename Value="frm_note.pas"/>
+ <Filename Value="HelpNote.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="frm_note"/>
+ <UnitName Value="HelpNote"/>
</Unit33>
<Unit34>
- <Filename Value="HelpNote.pas"/>
+ <Filename Value="HelpBookmark.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="HelpNote"/>
+ <UnitName Value="HelpBookmark"/>
</Unit34>
<Unit35>
- <Filename Value="HelpBookmark.pas"/>
+ <Filename Value="frm_bookmarks.pas"/>
<IsPartOfProject Value="True"/>
- <UnitName Value="HelpBookmark"/>
+ <UnitName Value="frm_bookmarks"/>
</Unit35>
+ <Unit36>
+ <Filename Value="lzwdecompress.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="LZWDecompress"/>
+ </Unit36>
</Units>
</ProjectOptions>
<CompilerOptions>
diff --git a/docview/src/docview.lpr b/docview/src/docview.lpr
index e49aa4c3..0bee1dbe 100644
--- a/docview/src/docview.lpr
+++ b/docview/src/docview.lpr
@@ -7,12 +7,13 @@ uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
- Classes, fpg_main, frm_main, IPFEscapeCodes, HelpTopic, CompareWordUnit, SearchTable,
- TextSearchQuery, nvUtilities, HelpFile, SearchUnit, fpg_cmdlineparams,
- IPFFileFormatUnit, HelpWindowDimensions, NewViewConstantsUnit, SettingsUnit,
+ Classes, fpg_main, frm_main, IPFEscapeCodes, HelpTopic, CompareWordUnit,
+ SearchTable, TextSearchQuery, nvUtilities, HelpFile, SearchUnit,
+ fpg_cmdlineparams, IPFFileFormatUnit, HelpWindowDimensions, SettingsUnit,
RichTextStyleUnit, CanvasFontManager, ACLStringUtility, RichTextDocumentUnit,
RichTextView, RichTextLayoutUnit, RichTextDisplayUnit, dvconstants, dvHelpers,
- frm_configuration, HelpBitmap, frm_text, frm_note, HelpNote, HelpBookmark;
+ frm_configuration, HelpBitmap, frm_text, frm_note, HelpNote, HelpBookmark,
+ frm_bookmarks, LZWDecompress;
{$IFDEF WINDOWS}
{$R docview.rc}
diff --git a/docview/src/docview.rc b/docview/src/docview.rc
index 87597a3f..34ed0c18 100644
--- a/docview/src/docview.rc
+++ b/docview/src/docview.rc
@@ -1,8 +1,8 @@
MAINICON ICON "../images/docview-48x48.ico"
1 VERSIONINFO
-FILEVERSION 0, 8, 0, 0
-PRODUCTVERSION 0, 8, 0, 0
+FILEVERSION 1, 0, 0, 0
+PRODUCTVERSION 1, 0, 0, 0
FILEFLAGSMASK 0
FILEOS 0x40000
FILETYPE 1
@@ -13,12 +13,12 @@ FILETYPE 1
{
VALUE "CompanyName", "fpGUI Toolkit"
VALUE "FileDescription", "fpGUI's INF Documentation Viewer"
- VALUE "FileVersion", "0.8.0"
+ VALUE "FileVersion", "1.0.0"
VALUE "InternalName", "docview"
VALUE "LegalCopyright", "GNU Public License"
VALUE "OriginalFilename", "docview"
VALUE "ProductName", "fpGUI Toolkit"
- VALUE "ProductVersion", "0.8.0"
+ VALUE "ProductVersion", "1.0.0"
}
}
BLOCK "VarFileInfo"
diff --git a/docview/src/dvHelpers.pas b/docview/src/dvHelpers.pas
index 28dc7809..2aaf710a 100644
--- a/docview/src/dvHelpers.pas
+++ b/docview/src/dvHelpers.pas
@@ -7,9 +7,6 @@ interface
uses
Classes, SysUtils, fpg_base;
-const
- OWN_HELP_MARKER = '[DOCVIEWHELP]';
-
function GetOwnHelpFileName: String;
// Given a filename, which may or may not contain a path or extension,
diff --git a/docview/src/dvconstants.pas b/docview/src/dvconstants.pas
index 9e0073be..e549bfe8 100644
--- a/docview/src/dvconstants.pas
+++ b/docview/src/dvconstants.pas
@@ -36,6 +36,7 @@ const
NOTES_FILE_EXTENSION = ExtensionSeparator + 'notes';
BOOKMARK_FILE_EXTENSION = ExtensionSeparator + 'bookmark';
BOOKMARK_SECTION = '[BOOKMARK]';
+ OWN_HELP_MARKER = '[DOCVIEWHELP]';
cDocViewHelpFile = 'docview.inf';
@@ -60,6 +61,18 @@ const
hcConfigGeneralTab = 510;
hcConfigFontsColorTab = 520;
+const
+ PARAM_LINK_NOTE = 'note';
+ PARAM_LINK_PROGRAM = 'program';
+ PARAM_LINK_URL = 'url';
+ PARAM_LINK_EXTERNAL = 'external';
+
+ PRGM_EXPLORER = 'explore'; // web explorer
+ PRGM_NETSCAPE = 'netscape';
+ PRGM_MOZILLA = 'mozilla';
+ PRGM_FIREFOX = 'firefox';
+
+
implementation
diff --git a/docview/src/frm_bookmarks.pas b/docview/src/frm_bookmarks.pas
new file mode 100644
index 00000000..4180b74f
--- /dev/null
+++ b/docview/src/frm_bookmarks.pas
@@ -0,0 +1,312 @@
+unit frm_bookmarks;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils,
+ Classes,
+ fpg_base,
+ fpg_main,
+ fpg_form,
+ fpg_listbox,
+ fpg_button,
+ HelpBookmark;
+
+type
+ TBookmarkCallback = procedure(Bookmark: TBookmark) of object;
+
+ TBookmarksForm = class(TfpgForm)
+ private
+ {@VFD_HEAD_BEGIN: BookmarksForm}
+ lbBookmarks: TfpgListBox;
+ btnRename: TfpgButton;
+ btnDelete: TfpgButton;
+ btnGoTo: TfpgButton;
+ btnHelp: TfpgButton;
+ btnClose: TfpgButton;
+ {@VFD_HEAD_END: BookmarksForm}
+ FBookmarkList: TList;
+ FOnBookmarksChanged: TNotifyEvent;
+ FOnGotoBookmark: TBookmarkCallback;
+ procedure lbBookmarksKeyPressed(Sender: TObject; var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
+ procedure FormShow(Sender: TObject);
+ procedure lbBookmarksDoubleClicked(Sender: TObject; AButton: TMouseButton; AShift: TShiftState; const AMousePos: TPoint);
+ procedure btnRenameClicked(Sender: TObject);
+ procedure btnDeleteClicked(Sender: TObject);
+ procedure btnGotoClicked(Sender: TObject);
+ procedure btnHelpClicked(Sender: TObject);
+ procedure btnCloseClicked(Sender: TObject);
+ function SelectedObject(ListBox: TfpgListBox): TObject;
+ procedure UpdateControls;
+ function GetSelectedBookmark: TBookmark;
+ procedure GotoSelectedBookmark;
+ public
+ procedure AfterCreate; override;
+ procedure RefreshList;
+ published
+ property BookmarkList: TList read FBookmarkList write FBookmarkList;
+ property OnBookmarksChanged: TNotifyEvent read FOnBookmarksChanged write FOnBookmarksChanged;
+ property OnGotoBookmark: TBookmarkCallback read FOnGotoBookmark write FOnGotoBookmark;
+ end;
+
+{@VFD_NEWFORM_DECL}
+
+implementation
+
+uses
+ fpg_dialogs;
+
+{@VFD_NEWFORM_IMPL}
+
+procedure TBookmarksForm.lbBookmarksKeyPressed(Sender: TObject;
+ var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
+begin
+ if (KeyCode = keyEnter) or (KeyCode = keyPEnter) then
+ begin
+ GotoSelectedBookmark;
+ Close;
+ end;
+end;
+
+procedure TBookmarksForm.FormShow(Sender: TObject);
+begin
+ RefreshList;
+ lbBookmarks.SetFocus;
+end;
+
+procedure TBookmarksForm.lbBookmarksDoubleClicked(Sender: TObject;
+ AButton: TMouseButton; AShift: TShiftState; const AMousePos: TPoint);
+begin
+ GotoSelectedBookmark;
+ Close;
+end;
+
+procedure TBookmarksForm.btnRenameClicked(Sender: TObject);
+var
+ Bookmark: TBookmark;
+ lName: TfpgString;
+begin
+ Bookmark := GetSelectedBookmark;
+ if Bookmark = nil then
+ exit;
+
+ lName := Bookmark.Name;
+ if fpgInputQuery( 'Rename Bookmark', 'Enter the new name of the bookmark', lName ) then
+ begin
+ Bookmark.Name := lName;
+ if Assigned(OnBookmarksChanged) then
+ OnBookmarksChanged(self);
+ // redisplay name in list
+ lbBookmarks.Items[lbBookmarks.FocusItem] := Bookmark.Name;
+ lbBookmarks.Invalidate;
+ end;
+end;
+
+procedure TBookmarksForm.btnDeleteClicked(Sender: TObject);
+var
+ Bookmark: TBookmark;
+ BookmarkIndex: integer;
+begin
+ Bookmark := GetSelectedBookmark;
+ if Bookmark = nil then
+ exit;
+
+ if TfpgMessageDialog.Question('Delete Bookmark',
+ Format('Delete the bookmark named "%s"?', [Bookmark.Name])) = mbYes then
+ begin
+ BookmarkIndex := BookmarkList.IndexOf( Bookmark );
+ lbBookmarks.Items.Delete( BookmarkIndex );
+ BookmarkList.Delete( BookmarkIndex );
+
+ if BookmarkIndex > BookmarkList.Count - 1 then
+ BookmarkIndex := BookmarkList.Count - 1;
+
+ lbBookmarks.FocusItem := BookmarkIndex;
+
+ Bookmark.Free;
+ if Assigned(OnBookmarksChanged) then
+ OnBookmarksChanged(self);
+ lbBookmarks.Invalidate;
+
+ UpdateControls;
+ end;
+end;
+
+procedure TBookmarksForm.btnGotoClicked(Sender: TObject);
+begin
+ GotoSelectedBookmark;
+end;
+
+procedure TBookmarksForm.btnHelpClicked(Sender: TObject);
+begin
+ InvokeHelp;
+end;
+
+procedure TBookmarksForm.btnCloseClicked(Sender: TObject);
+begin
+ Close;
+end;
+
+function TBookmarksForm.SelectedObject(ListBox: TfpgListBox): TObject;
+begin
+ if (ListBox.FocusItem >= 0) and (ListBox.FocusItem < ListBox.Items.Count) then
+ Result := ListBox.Items.Objects[ListBox.FocusItem]
+ else
+ Result := nil;
+end;
+
+procedure TBookmarksForm.UpdateControls;
+var
+ Selected: Boolean;
+begin
+ Selected := GetSelectedBookmark <> nil;
+ btnRename.Enabled := Selected;
+ btnDelete.Enabled := Selected;
+ btnGoto.Enabled := Selected;
+ if not btnGoto.Enabled then
+ btnGoto.Default := false;
+end;
+
+function TBookmarksForm.GetSelectedBookmark: TBookmark;
+begin
+ if SelectedObject(lbBookmarks) = nil then
+ result := nil
+ else
+ result := SelectedObject(lbBookmarks) as TBookmark;
+end;
+
+procedure TBookmarksForm.GotoSelectedBookmark;
+begin
+ if Assigned(FOnGotoBookmark) then
+ if GetSelectedBookmark <> nil then
+ FOnGotoBookmark(GetSelectedBookmark);
+end;
+
+procedure TBookmarksForm.AfterCreate;
+begin
+ {%region 'Auto-generated GUI code' -fold}
+ {@VFD_BODY_BEGIN: BookmarksForm}
+ Name := 'BookmarksForm';
+ SetPosition(553, 246, 393, 247);
+ WindowTitle := 'Bookmarks';
+ Hint := '';
+ HelpType := htContext;
+ HelpContext := 8;
+ OnShow := @FormShow;
+
+ lbBookmarks := TfpgListBox.Create(self);
+ with lbBookmarks do
+ begin
+ Name := 'lbBookmarks';
+ SetPosition(8, 12, 272, 227);
+ Anchors := [anLeft,anRight,anTop,anBottom];
+ FontDesc := '#List';
+ Hint := '';
+ TabOrder := 1;
+ OnDoubleClick := @lbBookmarksDoubleClicked;
+ OnKeyPress := @lbBookmarksKeyPressed;
+ end;
+
+ btnRename := TfpgButton.Create(self);
+ with btnRename do
+ begin
+ Name := 'btnRename';
+ SetPosition(288, 16, 96, 23);
+ Anchors := [anRight,anTop];
+ Text := 'Rename...';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 2;
+ OnClick := @btnRenameClicked;
+ end;
+
+ btnDelete := TfpgButton.Create(self);
+ with btnDelete do
+ begin
+ Name := 'btnDelete';
+ SetPosition(288, 44, 96, 23);
+ Anchors := [anRight,anTop];
+ Text := 'Delete';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 3;
+ OnClick := @btnDeleteClicked;
+ end;
+
+ btnGoTo := TfpgButton.Create(self);
+ with btnGoTo do
+ begin
+ Name := 'btnGoTo';
+ SetPosition(288, 72, 96, 23);
+ Anchors := [anRight,anTop];
+ Text := 'Goto';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 4;
+ Default := True;
+ OnClick := @btnGotoClicked;
+ end;
+
+ btnHelp := TfpgButton.Create(self);
+ with btnHelp do
+ begin
+ Name := 'btnHelp';
+ SetPosition(288, 100, 96, 23);
+ Anchors := [anRight,anTop];
+ Text := 'Help';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 5;
+ OnClick := @btnHelpClicked;
+ end;
+
+ btnClose := TfpgButton.Create(self);
+ with btnClose do
+ begin
+ Name := 'btnClose';
+ SetPosition(288, 217, 96, 23);
+ Anchors := [anRight,anBottom];
+ Text := 'Close';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 6;
+ OnClick := @btnCloseClicked;
+ end;
+
+ {@VFD_BODY_END: BookmarksForm}
+ {%endregion}
+end;
+
+procedure TBookmarksForm.RefreshList;
+var
+ i: integer;
+ Bookmark: TBookmark;
+Begin
+ lbBookmarks.Items.BeginUpdate;
+
+ lbBookmarks.Items.Clear;
+
+ if not Assigned(BookmarkList) then
+ exit;
+
+ for i := 0 to BookmarkList.Count - 1 do
+ begin
+ Bookmark := TBookmark(BookmarkList[i]);
+ lbBookmarks.Items.AddObject(Bookmark.Name, Bookmark);
+ end;
+
+ if lbBookmarks.Items.Count > 0 then
+ lbBookmarks.FocusItem := 0;
+
+ lbBookmarks.Items.EndUpdate;
+ UpdateControls;
+End;
+
+end.
diff --git a/docview/src/frm_main.pas b/docview/src/frm_main.pas
index ddad88d8..97a9fd04 100644
--- a/docview/src/frm_main.pas
+++ b/docview/src/frm_main.pas
@@ -58,6 +58,7 @@ type
RichView: TRichTextView;
MainMenu: TfpgMenuBar;
miFile: TfpgPopupMenu;
+ miActions: TfpgPopupMenu;
miSettings: TfpgPopupMenu;
miBookmarks: TfpgPopupMenu;
miView: TfpgPopupMenu;
@@ -129,9 +130,19 @@ type
procedure miFileOpenAdditionalFileClicked(Sender: TObject);
procedure miFileOpenSpecialClicked(Sender: TObject);
procedure miFileCloseClicked(Sender: TObject);
+ procedure miActionsContentsClicked(Sender: TObject);
+ procedure miActionsIndexClicked(Sender: TObject);
+ procedure miActionsSearchClicked(Sender: TObject);
+ procedure miActionsNotesClicked(Sender: TObject);
+ procedure miActionsHistoryClicked(Sender: TObject);
+ procedure miActionsBackClicked(Sender: TObject);
+ procedure miActionsForwardClicked(Sender: TObject);
+ procedure miActionsPrevTopicClicked(Sender: TObject);
+ procedure miActionsNextTopicClicked(Sender: TObject);
procedure miConfigureClicked(Sender: TObject);
procedure miViewExpandAllClicked(Sender: TObject);
procedure miViewCollapseAllClicked(Sender: TObject);
+ procedure miOpenBookmarksMenuClicked(Sender: TObject);
procedure miBookmarksMenuItemClicked(Sender: TObject);
procedure miHelpProdInfoClicked(Sender: TObject);
procedure miHelpAboutFPGui(Sender: TObject);
@@ -234,7 +245,6 @@ type
procedure ClearBookmarks;
procedure OnBookmarksChanged(Sender: TObject);
procedure BuildBookmarksMenu;
- procedure UpdateBookmarksDisplay;
procedure NavigateToBookmark(Bookmark: TBookmark);
public
constructor Create(AOwner: TComponent); override;
@@ -265,7 +275,7 @@ uses
,frm_configuration
,frm_text
,frm_note
- ,NewViewConstantsUnit
+ ,frm_bookmarks
,CanvasFontManager
,HelpNote
,RichTextDocumentUnit
@@ -298,6 +308,26 @@ begin
end
end;
+procedure TMainForm.miActionsBackClicked(Sender: TObject);
+begin
+ btnBack.Click;
+end;
+
+procedure TMainForm.miActionsForwardClicked(Sender: TObject);
+begin
+ btnFwd.Click;
+end;
+
+procedure TMainForm.miActionsPrevTopicClicked(Sender: TObject);
+begin
+ btnPrev.Click;
+end;
+
+procedure TMainForm.miActionsNextTopicClicked(Sender: TObject);
+begin
+ btnNext.Click;
+end;
+
procedure TMainForm.Splitter1DoubleClicked(Sender: TObject;
AButton: TMouseButton; AShift: TShiftState; const AMousePos: TPoint);
begin
@@ -420,9 +450,12 @@ end;
procedure TMainForm.RichViewClickLink(Sender: TRichTextView; Link: string);
var
+ LinkDetails: TfpgString;
LinkIndex: integer;
lLink: THelpLink;
lHelp: THelpFile;
+ f: THelpFile;
+ lHelpFileName: TfpgString;
i: integer;
lTopic: TTopic;
lFound: Boolean;
@@ -441,7 +474,32 @@ begin
end
else if pos(PARAM_LINK_EXTERNAL, Link) > 0 then
begin
- TfpgMessageDialog.Warning('', 'External links are not supported in DocView yet. Please try again with a later build.')
+ LinkDetails := StrRightFrom( Link, 10 ); // 10 is starting pos of data, after 'external '
+ LinkIndex := StrToInt( ExtractNextValue( LinkDetails, ' ' ) );
+ lHelp := CurrentTopic.HelpFile as THelpFile;
+
+ lHelpFileName := lHelp.ReferencedFiles[ LinkIndex ];
+
+ { Only open the external file once. So see if it is already openned. }
+ lFound := False;
+ for i := 0 to CurrentOpenFiles.Count-1 do
+ begin
+ f := THelpFile(CurrentOpenFiles[i]);
+ if SameText(fpgExtractFileName(f.Filename), lHelpFileName) then
+ lFound := True;
+ end;
+ if not lFound then
+ begin
+ OpenAdditionalFile := True;
+ OpenFile(lHelpFileName, '', false);
+ OpenAdditionalFile := False;
+ end;
+
+ { Not sure if we have an ID or Resource Name, so lets try both if possible }
+ if TryStrToInt(LinkDetails, i) then
+ DisplayTopicByResourceID(i)
+ else
+ DisplayTopicByName(LinkDetails);
end
else if pos(PARAM_LINK_URL, Link) > 0 then
begin
@@ -578,6 +636,31 @@ begin
CloseFile;
end;
+procedure TMainForm.miActionsContentsClicked(Sender: TObject);
+begin
+ PageControl1.ActivePage := tsContents;
+end;
+
+procedure TMainForm.miActionsIndexClicked(Sender: TObject);
+begin
+ PageControl1.ActivePage := tsIndex;
+end;
+
+procedure TMainForm.miActionsSearchClicked(Sender: TObject);
+begin
+ PageControl1.ActivePage := tsSearch;
+end;
+
+procedure TMainForm.miActionsNotesClicked(Sender: TObject);
+begin
+ PageControl1.ActivePage := tsNotes;
+end;
+
+procedure TMainForm.miActionsHistoryClicked(Sender: TObject);
+begin
+ PageControl1.ActivePage := tsHistory;
+end;
+
procedure TMainForm.miConfigureClicked(Sender: TObject);
begin
ShowConfigForm;
@@ -594,6 +677,21 @@ begin
tvContents.FullCollapse;
end;
+procedure TMainForm.miOpenBookmarksMenuClicked(Sender: TObject);
+var
+ frm: TBookmarksForm;
+begin
+ frm := TBookmarksForm.Create(nil);
+ try
+ frm.BookmarkList := Bookmarks;
+ frm.OnGotoBookmark := @NavigateToBookmark;
+ frm.OnBookmarksChanged := @OnBookmarksChanged;
+ frm.ShowModal;
+ finally
+ frm.Free;
+ end;
+end;
+
procedure TMainForm.miBookmarksMenuItemClicked(Sender: TObject);
var
t: PtrInt;
@@ -2465,8 +2563,7 @@ begin
if ImageIndices.Count > 0 then
begin
- { TODO -oGraeme : We do not support images yet }
-// THelpFile(CurrentTopic.HelpFile).GetImages(ImageIndices, FImages);
+ THelpFile(CurrentTopic.HelpFile).GetImages(ImageIndices, FImages);
end;
ImageIndices.Free;
@@ -2531,6 +2628,7 @@ var
begin
inherited Create(AOwner);
fpgApplication.OnException := @MainFormException;
+ fpgApplication.HelpFile := cDocViewHelpFile;
OnShow := @MainFormShow;
OnDestroy := @MainFormDestroy;
// Files := TList.Create;
@@ -3078,17 +3176,34 @@ begin
begin
Name := 'miFile';
SetPosition(292, 96, 132, 20);
- AddMenuItem('Open...', 'Ctrl+O', @miFileOpenClicked);
- AddMenuItem('Open additional file...', 'Ctrl+Shift+O', @miFileOpenAdditionalFileClicked);
- AddMenuItem('Open Special...', 'Ctrl+L', @miFileOpenSpecialClicked);
- AddMenuItem('Save current Topic to IPF...', 'Ctrl+S', @miFileSaveTopicAsIPF);
- AddMenuItem('Close', 'Ctrl+W', @miFileCloseClicked);
- AddMenuitem('-', '', nil);
+ AddMenuItem('Open...', rsKeyCtrl+'O', @miFileOpenClicked);
+ AddMenuItem('Open additional file...', rsKeyCtrl+rsKeyShift+'O', @miFileOpenAdditionalFileClicked);
+ AddMenuItem('Open Special...', rsKeyCtrl+'L', @miFileOpenSpecialClicked);
+ AddMenuItem('Save current Topic to IPF...', rsKeyCtrl+'S', @miFileSaveTopicAsIPF);
+ AddMenuItem('Close', rsKeyCtrl+'W', @miFileCloseClicked);
+ AddSeparator;
FFileOpenRecent := AddMenuItem('Open Recent...', '', nil);
AddMenuitem('-', '', nil);
AddMenuItem('Quit', 'Ctrl+Q', @miFileQuitClicked);
end;
+ miActions := TfpgPopupMenu.Create(self);
+ with miActions do
+ begin
+ Name := 'miActions';
+ SetPosition(282, 96, 132, 20);
+ AddMenuItem('Contents', 'F5', @miActionsContentsClicked);
+ AddMenuItem('Index', 'F6', @miActionsIndexClicked);
+ AddMenuItem('Search', 'F7', @miActionsSearchClicked);
+ AddMenuItem('Notes', 'F8', @miActionsNotesClicked);
+ AddMenuItem('History', 'F9', @miActionsHistoryClicked);
+ AddSeparator;
+ AddMenuItem('Back', rsKeyCtrl+'Left', @miActionsBackClicked);
+ AddMenuItem('Forward', rsKeyCtrl+'Right', @miActionsForwardClicked);
+ AddMenuItem('Previous Topic', rsKeyCtrl+'Up', @miActionsPrevTopicClicked);
+ AddMenuItem('Next Topic', rsKeyCtrl+'Down', @miActionsNextTopicClicked);
+ end;
+
miSettings := TfpgPopupMenu.Create(self);
with miSettings do
begin
@@ -3102,8 +3217,10 @@ begin
begin
Name := 'miBookmarks';
SetPosition(292, 144, 132, 20);
- AddMenuItem('Add..', '', nil).Enabled := False;
- AddMenuItem('Show', '', nil).Enabled := False;
+ AddMenuItem('Add', rsKeyCtrl+'B', @btnBookmarkClick);
+ AddMenuItem('Edit...', rsKeyCtrl+'D', @miOpenBookmarksMenuClicked);
+ AddSeparator;
+ AddMenuItem('Add note at cursor position', rsKeyCtrl+'M', @btnNotesAddClick);
end;
miView := TfpgPopupMenu.Create(self);
@@ -3113,7 +3230,7 @@ begin
SetPosition(292, 216, 132, 20);
AddMenuItem('Expand All', '', @miViewExpandAllClicked);
AddMenuItem('Collapse All', '', @miViewCollapseAllClicked);
- AddMenuItem('-', '', nil);
+ AddSeparator;
AddMenuItem('Topic Properties', '', @miTopicPropertiesClicked);
end;
@@ -3137,9 +3254,9 @@ begin
begin
Name := 'miHelp';
SetPosition(292, 168, 132, 20);
- AddMenuItem('Help using DocView', '', @miHelpUsingDocView);
- AddMenuItem('Command line parameters', '', @miHelpCmdLineParams);
- AddMenuItem('-', '', nil);
+ AddMenuItem('Help using DocView', rsKeyCtrl+'F1', @miHelpUsingDocView);
+ AddMenuItem('Command line parameters', rsKeyCtrl+rsKeyShift+'F1', @miHelpCmdLineParams);
+ AddSeparator;
AddMenuItem('About fpGUI Toolkit...', '', @miHelpAboutFPGui);
AddMenuItem('Product Information...', '', @miHelpProdInfoClicked);
end;
@@ -3375,6 +3492,7 @@ begin
// hook up the sub-menus.
MainMenu.AddMenuItem('&File', nil).SubMenu := miFile;
MainMenu.AddMenuItem('&Settings', nil).SubMenu := miSettings;
+ MainMenu.AddMenuItem('&Actions', nil).SubMenu := miActions;
MainMenu.AddMenuItem('&Bookmarks', nil).SubMenu := miBookmarks;
MainMenu.AddMenuItem('&Tools', nil).SubMenu := miTools;
MainMenu.AddMenuItem('&Help', nil).SubMenu := miHelp;
@@ -3842,7 +3960,6 @@ end;
procedure TMainForm.OnBookmarksChanged(Sender: TObject);
begin
BuildBookmarksMenu;
-// UpdateBookmarksForm;
SaveBookmarks;
end;
@@ -3870,33 +3987,6 @@ begin
end;
end;
-procedure TMainForm.UpdateBookmarksDisplay;
-var
- i: integer;
- Bookmark: TBookmark;
-Begin
-(*
- BookmarksListBox.Items.BeginUpdate;
- BookmarksListBox.Clear;
-
- if not Assigned( BookmarkList ) then
- exit;
-
- for i := 0 to BookmarkList.Count - 1 do
- begin
- Bookmark := BookmarkList[ i ];
- BookmarksListBox.Items.AddObject( Bookmark.Name,
- Bookmark );
- end;
-
- if BookmarksListBox.Items.Count > 0 then
- BookmarksListBox.ItemIndex := 0;
-
- BookmarksListBox.Items.EndUpdate;
- UpdateControls;
-*)
-end;
-
procedure TMainForm.NavigateToBookmark(Bookmark: TBookmark);
begin
DisplayTopic(Bookmark.ContentsTopic);
diff --git a/docview/src/frm_note.pas b/docview/src/frm_note.pas
index 2e280a89..310cc252 100644
--- a/docview/src/frm_note.pas
+++ b/docview/src/frm_note.pas
@@ -5,7 +5,13 @@ unit frm_note;
interface
uses
- SysUtils, Classes, fpg_base, fpg_main, fpg_form, fpg_memo, fpg_button;
+ SysUtils,
+ Classes,
+ fpg_base,
+ fpg_main,
+ fpg_form,
+ fpg_memo,
+ fpg_button;
type
@@ -23,6 +29,7 @@ type
function GetText: TfpgString;
procedure SetText(const AValue: TfpgString);
procedure SetCanDelete(const AValue: boolean);
+ procedure btnHelpClicked(Sender: TObject);
public
procedure AfterCreate; override;
property Text: TfpgString read GetText write SetText;
@@ -56,6 +63,11 @@ begin
btnDelete.Enabled := FCanDelete;
end;
+procedure TNoteForm.btnHelpClicked(Sender: TObject);
+begin
+ InvokeHelp;
+end;
+
procedure TNoteForm.AfterCreate;
begin
{%region 'Auto-generated GUI code' -fold}
@@ -65,6 +77,8 @@ begin
WindowTitle := 'Notes';
Hint := '';
OnShow := @FormShow;
+ HelpType := htContext;
+ HelpContext := 7;
Memo1 := TfpgMemo.Create(self);
with Memo1 do
@@ -102,6 +116,7 @@ begin
Hint := '';
ImageName := '';
TabOrder := 3;
+ OnClick := @btnHelpClicked;
end;
btnCancel := TfpgButton.Create(self);
diff --git a/docview/src/lzwdecompress.pas b/docview/src/lzwdecompress.pas
new file mode 100644
index 00000000..0ebba38c
--- /dev/null
+++ b/docview/src/lzwdecompress.pas
@@ -0,0 +1,263 @@
+{
+ fpGUI - Free Pascal GUI Toolkit
+
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Description:
+ LZW decompression code for uncompressing IPF bitmaps.
+}
+
+unit LZWDecompress;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, types;
+
+procedure LZWDecompressBlock( pbInput: pByte;
+ number_bytes: LongWord;
+ pbOutput: PBYTE;
+ Var bytesOut: LongWord;
+ Var FinalCode: byte );
+
+Implementation
+
+(*
+/********************************************************************
+ * *
+ * LZW decompression *
+ * *
+ *******************************************************************/
+
+/*
+ * This is based on code (W) by Peter Fitzsimmons, pfitz@ican.net.
+ * His liner notes in the original:
+ * has its roots in a June 1990
+ * DDJ article "LZW REVISITED", by Shawn M. Regan
+ * --=>revision history<=--
+ * 1 lzw.c 21-Aug-96,2:24:36,`PLF' ;
+ * 2 lzw.c 24-Aug-96,2:27:24,`PLF' wip
+ *
+ * The code has been modified to take the input not from an
+ * open file, but from any memory region. For this, a double
+ * pointer is used, which must be passed to LZWDecompressBlock.
+ * I've also added a few comments for clarity.
+ *
+ * Ported to Sibyl Pascal by Aaron Lawrence
+ * Variables renamed etc to make things clearer.
+ */
+*)
+// -- Stuff for LZW decompression -- */
+const INIT_BITS = 9;
+const MAX_BITS = 12; //PLF Tue 95-10-03 02:16:56*/
+const HASHING_SHIFT = MAX_BITS - 8;
+
+{if MAX_BITS == 15
+const TABLE_SIZE 36768
+#elif MAX_BITS == 14
+const TABLE_SIZE 18041
+#elif MAX_BITS == 13
+const TABLE_SIZE 9029
+#else}
+// For max_bits = 12:
+const TABLE_SIZE = 5021;
+
+const CLEAR_TABLE = 256;
+const TERMINATOR = 257;
+const FIRST_CODE = 258;
+
+function MaxValNBits( N: word ): word;
+begin
+ Result:= ( 1 shl n ) - 1;
+end;
+
+var
+ prefix_code: array[ 0..TABLE_SIZE ] of longword;
+ append_character: array[ 0..TABLE_SIZE ] of Byte;
+ decode_stack: array[ 0..10000 ] of byte;
+ bitsPerCode: longint;
+ maxDictionaryCode: longint;
+
+(*
+ * decode_string:
+ *
+ *)
+function decode_string( buffer: PByte; code: longword ): PByte;
+var
+ i: longint;
+begin
+ i:= 0;
+
+ while Code > 255 do
+ begin
+ buffer^:= append_character[ Code ];
+ inc( Buffer );
+ code:= prefix_code[ code ];
+
+ inc( i );
+ if i > High( decode_stack ) then
+ assert( false, 'Out of space decompressing bitmap!' );
+ end;
+
+ buffer^ := code;
+ Result:= buffer;
+end;
+
+(*
+ * input_code:
+ * this function reads in bytes from the input
+ * stream.
+ *)
+
+var
+ bytes_out: longword = 0;
+ input_bit_count: longword = 0;
+ input_bit_buffer: longword = 0;
+
+// I think this simply reads the next bitsPerCode bits of the input data
+// returning the resulting code.
+function input_code( var pbInput: PBYTE; bytes_to_read: longword ): longword;
+var
+ return_value: longword;
+begin
+ while input_bit_count <= 24 do
+ begin
+ if bytes_out <= bytes_to_read then
+ begin
+ input_bit_buffer:= input_bit_buffer
+ or
+ ( ( longword( pbInput^ ) shl (24 - input_bit_count) ) );
+ inc( pbInput );
+ end
+ else
+ input_bit_buffer:= input_bit_buffer
+ or
+ ( longword( 0 ) shl ( 24 - input_bit_count ) );
+ inc( bytes_out );
+ inc( input_bit_count, 8 );
+ end;
+
+ return_value:= input_bit_buffer shr (32 - bitsPerCode);
+ input_bit_buffer:= input_bit_buffer shl bitsPerCode;
+ dec( input_bit_count, bitsPerCode );
+
+ if bytes_out > bytes_to_read then
+ begin
+ // flush static vars and quit */
+ bytes_out:= 0;
+ input_bit_count:= 0;
+ input_bit_buffer:= 0;
+ Result:= TERMINATOR;
+ end
+ else
+ Result:= return_value;
+end;
+
+// LZWDecompressBlock:
+// this takes one of the INF bitmap blocks
+// and decompresses it using LZW algorithms.
+
+procedure LZWDecompressBlock( pbInput: pByte;
+ number_bytes: LongWord;
+ pbOutput: PBYTE;
+ Var bytesOut: LongWord;
+ Var FinalCode: byte );
+var
+ nextAvailableCode: LongWord;
+ currentCode: LongWord;
+ lastCode: LongWord;
+ character: longword;
+ clear_flag: boolean;
+ theString: pByte;
+begin
+ clear_flag:= true;
+
+ nextAvailableCode:= FIRST_CODE;
+ bitsPerCode:= INIT_BITS;
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+
+ bytesOut:= 0;
+ input_bit_count:= 0;
+ input_bit_buffer:= 0;
+
+ // read the first code from input
+ currentCode:= input_code( pbInput, number_bytes );
+ while currentCode <> TERMINATOR do
+ begin
+ if clear_flag then
+ begin
+ clear_flag:= false;
+ lastCode:= currentCode;
+ character:= currentCode;
+
+ pbOutput^:= currentCode;
+ inc( pbOutput );
+ FinalCode:= currentCode;
+ inc( BytesOut );
+ end
+ else if currentCode = CLEAR_TABLE then
+ begin
+ clear_flag:= true;
+ nextAvailableCode:= FIRST_CODE;
+ bitsPerCode:= INIT_BITS;
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+ end
+ else
+ begin
+ if currentCode >= nextAvailableCode then
+ begin
+ decode_stack[ 0 ]:= character;
+ theString:= decode_string( Addr( decode_stack[ 1 ] ),
+ lastCode );
+ end
+ else
+ theString:= decode_string( Addr( decode_stack[ 0 ] ),
+ currentCode );
+
+ character:= longword( theString^ );
+ while theString >= Addr( decode_stack[ 0 ] ) do
+ begin
+ FinalCode:= theString^;
+
+ pbOutput^:= theString^;
+ inc( pbOutput );
+ dec( TheString );
+
+ inc( BytesOut );
+ end;
+
+ if nextAvailableCode <= maxDictionaryCode then
+ begin
+ prefix_code[ nextAvailableCode ]:= lastCode;
+ append_character[ nextAvailableCode ]:= character;
+
+ inc( nextAvailableCode );
+
+ if ( nextAvailableCode = maxDictionaryCode ) and ( bitsPerCode < MAX_BITS ) then
+ begin
+ // expand dictionary
+ inc( bitsPerCode );
+ maxDictionaryCode:= MaxValNBits( bitsPerCode );
+ end;
+ end;
+
+ lastCode:= currentCode;
+ end;
+
+ // Read next code from input
+ currentCode:= input_code( pbInput, number_bytes );
+ end;
+end;
+
+
+End.
diff --git a/examples/apps/debugserver/fpgDebugServer.lpi b/examples/apps/debugserver/fpgDebugServer.lpi
index da1b22f2..f26f35ee 100644
--- a/examples/apps/debugserver/fpgDebugServer.lpi
+++ b/examples/apps/debugserver/fpgDebugServer.lpi
@@ -54,7 +54,7 @@
<CompilerOptions>
<Version Value="11"/>
<Target>
- <Filename Value="fpgDebugServer"/>
+ <Filename Value="dbugsrv"/>
</Target>
<SearchPaths>
<UnitOutputDirectory Value="units/$(TargetCPU)-$(TargetOS)"/>
diff --git a/examples/apps/docedit/docedit.lpi b/examples/apps/docedit/docedit.lpi
index 640d3114..3e06fdd7 100644
--- a/examples/apps/docedit/docedit.lpi
+++ b/examples/apps/docedit/docedit.lpi
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
- <Version Value="7"/>
+ <Version Value="9"/>
<General>
<Flags>
<SaveOnlyProjectUnits Value="True"/>
@@ -9,11 +9,13 @@
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
- <TargetFileExt Value=""/>
</General>
<VersionInfo>
- <ProjectVersion Value=""/>
+ <StringTable ProductVersion=""/>
</VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
@@ -69,9 +71,19 @@
</Units>
</ProjectOptions>
<CompilerOptions>
- <Version Value="8"/>
+ <Version Value="11"/>
+ <Target>
+ <Filename Value="docedit"/>
+ </Target>
+ <SearchPaths>
+ <UnitOutputDirectory Value="units"/>
+ </SearchPaths>
+ <Parsing>
+ <SyntaxOptions>
+ <UseAnsiStrings Value="False"/>
+ </SyntaxOptions>
+ </Parsing>
<Other>
- <CustomOptions Value="-FUunits"/>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
diff --git a/examples/apps/docedit/frm_main.pas b/examples/apps/docedit/frm_main.pas
index f6404b79..884a2d5b 100644
--- a/examples/apps/docedit/frm_main.pas
+++ b/examples/apps/docedit/frm_main.pas
@@ -63,7 +63,9 @@ type
implementation
uses
- fpg_dialogs, frm_options;
+ fpg_dialogs,
+ fpg_constants,
+ frm_options;
const
diff --git a/examples/corelib/aggcanvas/agg_canvas_test.lpi b/examples/corelib/aggcanvas/agg_canvas_test.lpi
new file mode 100644
index 00000000..f02ac5df
--- /dev/null
+++ b/examples/corelib/aggcanvas/agg_canvas_test.lpi
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="9"/>
+ <General>
+ <Flags>
+ <MainUnitHasCreateFormStatements Value="False"/>
+ <MainUnitHasTitleStatement Value="False"/>
+ <LRSInOutputDirectory Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <Title Value="agg_canvas_test"/>
+ </General>
+ <VersionInfo>
+ <StringTable ProductVersion=""/>
+ </VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </RunParams>
+ <RequiredPackages Count="1">
+ <Item1>
+ <PackageName Value="fpgui_toolkit"/>
+ </Item1>
+ </RequiredPackages>
+ <Units Count="1">
+ <Unit0>
+ <Filename Value="agg_canvas_test.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="agg_canvas_test"/>
+ </Unit0>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <Target>
+ <Filename Value="agg_canvas_test"/>
+ </Target>
+ <SearchPaths>
+ <UnitOutputDirectory Value="units"/>
+ </SearchPaths>
+ <Parsing>
+ <SyntaxOptions>
+ <UseAnsiStrings Value="False"/>
+ </SyntaxOptions>
+ </Parsing>
+ <CodeGeneration>
+ <Optimizations>
+ <OptimizationLevel Value="0"/>
+ </Optimizations>
+ </CodeGeneration>
+ <Other>
+ <CompilerMessages>
+ <UseMsgFile Value="True"/>
+ </CompilerMessages>
+ <CustomOptions Value="-dAggCanvas"/>
+ <CompilerPath Value="$(CompPath)"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/examples/corelib/aggcanvas/agg_canvas_test.lpr b/examples/corelib/aggcanvas/agg_canvas_test.lpr
new file mode 100644
index 00000000..63ba1d53
--- /dev/null
+++ b/examples/corelib/aggcanvas/agg_canvas_test.lpr
@@ -0,0 +1,389 @@
+{
+ fpGUI - Free Pascal GUI Toolkit
+
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Description:
+ This demo was simply to test the Agg2D unit and the TAgg2D canvas
+ class. In this demo the AggPas TAgg2D canvas does all the painting.
+
+ *** IMPORTANT ***
+ For this demo to work, the fpGUI Toolkit MUST be compiled with
+ the AggCanvas compiler define enabled.
+}
+
+program agg_canvas_test;
+
+{$mode objfpc}{$H+}
+
+uses
+ Classes, SysUtils,
+ fpg_base,
+ fpg_main,
+ fpg_form,
+ fpg_imgfmt_bmp,
+ fpg_widget,
+ Agg2D,
+ fpg_dialogs;
+
+
+type
+ TMainForm = class(TfpgForm)
+ private
+ {@VFD_HEAD_BEGIN: MainForm}
+ {@VFD_HEAD_END: MainForm}
+ procedure FormKeyPressed(Sender: TObject; var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
+ procedure FormPaint(Sender: TObject);
+ procedure CustomPaintJob;
+ public
+ procedure AfterCreate; override;
+ end;
+
+
+
+{ TMainForm }
+
+procedure TMainForm.FormKeyPressed(Sender: TObject; var KeyCode: word;
+ var ShiftState: TShiftState; var Consumed: boolean);
+begin
+ if KeyCode = keyF1 then
+ begin
+ ShowMessage('This is a simple Canvas primitives painting test.');
+ end;
+end;
+
+procedure TMainForm.FormPaint(Sender: TObject);
+begin
+ CustomPaintJob;
+end;
+
+// We can now call all the paint methods from HandlePaint or
+// the OnPaint event.fpgcanvas
+procedure TMainForm.CustomPaintJob;
+var
+ r: TfpgRect;
+ fnt: TfpgFont;
+ y: integer;
+ ac: TAgg2D;
+ c1, c2: TAggColor;
+ d: double;
+ i: integer;
+
+ procedure DrawMacLionButton(const x, y: double; const astate: byte; const atext: ansistring);
+ { AState values are interpreted as follows:
+ 0: normal state
+ 1: hover state
+ 2: clicked state }
+ var
+ x1, y1, x2, y2, h, w: double;
+ c1, c2: TAggColor;
+ begin
+ h := 21;
+ w := 100;
+ x1 := x;
+ y1 := y;
+ x2 := x1 + w;
+ y2 := y1 + h;
+
+ ac.NoLine;
+
+ // Top vertical gradient
+ case astate of
+ 0: begin
+ c1.Construct(255, 255, 255, 255);
+ c2.Construct(243, 243, 243, 255);
+ end;
+ 1: begin
+ c1.Construct(204, 229, 252, 255);
+ c2.Construct(161, 209, 249, 255);
+ end;
+ 2: begin
+ c1.Construct(144, 195, 241, 255);
+ c2.Construct(113, 180, 239, 255);
+ end;
+ end;
+ ac.FillLinearGradient(x1, y1, x1, y1+(h/2), c1, c2);
+ ac.RoundedRect(x1+1, y1+1, x2+0.5, y2-(h/2)+0.5, 0.3, 3/2, 0.3, 3/2);
+
+ // Bottom vertical gradient
+ case astate of
+ 0: begin
+ c1.Construct(236, 236, 236, 255);
+ c2.Construct(242, 242, 242, 255);
+ end;
+ 1: begin
+ c1.Construct(143, 202, 251, 255);
+ c2.Construct(207, 245, 253, 255);
+ end;
+ 2: begin
+ c1.Construct(97, 173, 240, 255);
+ c2.Construct(147, 206, 241, 255);
+ end;
+ end;
+ ac.FillLinearGradient(x1, y1+(h/2)+1, x1, y2, c1, c2);
+ ac.RoundedRect(x1+1, y1+(h/2)+0.5, x2+0.5, y2+0.5, 0.3, 3/2, 0.3, 3/2);
+
+ // outer rounded rectangle
+ ac.NoFill;
+ case astate of
+ 0: begin
+ ac.LineColor($9a, $9a, $9a);
+ end;
+ 1,
+ 2: begin
+ ac.LineColor(86, 87, 143);
+ end;
+ end;
+ ac.LineWidth(1.0);
+ ac.RoundedRect(x1+0.5, y1+0.5, x2+0.5, y2+0.5, 3, 3);
+
+ // Slight shadow under the button
+ ac.LineColor($df, $df, $df, $ff);
+ ac.Line(x1+0.5, y2+1.5, x2-0.5, y2+1.5);
+
+ // button text
+ c1.Construct(0,0,0);
+ ac.FillColor(c1);
+ ac.NoLine;
+ ac.Font('arialbd.ttf', 13);
+ ac.TextAlignment(AGG_AlignCenter ,AGG_AlignCenter );
+ ac.Text(
+ (x1 + x2 ) / 2.0 ,
+ (y1 + y2 ) / 2.0 ,
+ atext,
+ true ,0.0 ,0.0 );
+
+ end;
+begin
+ // casting so we have full access to the Agg2D canvas functions
+ ac := TAgg2D(Canvas);
+
+ ac.LineWidth(1.0);
+// ac.ClearAll($ed, $ed, $ed); // mac os x window background color
+ ac.ClearAll(255, 255, 255);
+
+ // Testing Rectangles
+ Canvas.SetColor(clBlack);
+ r.SetRect(0, 0, 1, 1); // 1x1 (this is really a dot)
+ Canvas.DrawRectangle(r);
+ Canvas.SetColor(clRed);
+ r.SetRect(0, 1, 1, 5); // 1x5 (this is really a vertical line)
+ Canvas.DrawRectangle(r);
+ Canvas.SetColor(clMagenta);
+ r.SetRect(1, 0, 5, 1); // 5x1 (this is really a horizontal line)
+ Canvas.DrawRectangle(r);
+
+ Canvas.SetColor(clBlack);
+ r.Top := 5;
+ r.Left := 60;
+ r.Width := 50;
+ r.Height := 50;
+ Canvas.DrawRectangle(r);
+
+ r.Left := 120;
+ Canvas.SetLineStyle(2, lsDash);
+ Canvas.DrawRectangle(r);
+
+ r.Left := 180;
+ Canvas.SetColor(clGreen);
+ Canvas.SetLineStyle(1, lsDot);
+ Canvas.DrawRectangle(r);
+
+ r.Left := 240;
+ Canvas.SetColor(clBlue);
+ Canvas.SetLineStyle(1, lsSolid);
+ Canvas.FillRectangle(r);
+
+ // Testing line drawing
+ ac.NoFill;
+ Canvas.SetColor(clBlue);
+ Canvas.DrawLine(5, 5, 54, 54);
+ Canvas.DrawLine(54, 5, 5, 54);
+ Canvas.SetColor(clRed);
+ { Diagonal line }
+ r.SetRect(60, 5, 50, 50);
+ Canvas.DrawLine(r.Left, r.Top, r.Right, r.Bottom);
+ { Horizontal line }
+ Canvas.DrawLine(r.Left, r.Top-2, r.Right, r.Top-2);
+ { Vertical line }
+ Canvas.DrawLine(r.Left-2, r.Top, r.Left-2, r.Bottom);
+
+
+ // Testing Text and Fonts
+ y := 60;
+ Canvas.SetTextColor(clBlack);
+ Canvas.DrawString(5, y, 'This text must be black and default font');
+
+ // red dot indicates top/left corner of where previous text was started
+ Canvas.Pixels[5,y] := clRed;
+// Canvas.DrawLine(5,y-4, 5,y+5);
+// Canvas.DrawLine(1,y, 10, y);
+
+ Canvas.SetTextColor(clRed);
+ y := y + Canvas.Font.Height; // fonts are different sizes on differet OS's
+ Canvas.DrawString(5, y, 'This text must be red.');
+ Canvas.SetTextColor(clBlack);
+ y := y + Canvas.Font.Height;
+ Canvas.DrawString(5, y, 'Russian (UTF-8) text: ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ сŠ¾Š·Š“Š°Ń‚ŃŒ Š“ŠøрŠµŠŗтŠ¾Ń€Šøю');
+ y := y + Canvas.Font.Height;
+ fnt := fpgApplication.GetFont('Times-14:bold');
+ Canvas.Font := fnt;
+ Canvas.DrawString(5, y, 'Font used is ' + Canvas.Font.FontDesc);
+ y := y + Canvas.Font.Height;
+
+
+ // Testing basic style drawings
+ Canvas.Font := fpgApplication.DefaultFont;
+ Canvas.DrawString(320, 3, 'DrawButtonFace():');
+
+ r.SetRect(300, 20, 75, 25);
+ Canvas.DrawButtonFace(r, []);
+ Canvas.DrawString(385, 20, '= []');
+ r.Top := 50;
+ Canvas.DrawButtonFace(r, [btfIsDefault]);
+ Canvas.DrawString(385, 50, '= [btnIsDefault]');
+ r.Top := 80;
+ Canvas.DrawButtonFace(r, [btfIsPressed]);
+ Canvas.DrawString(385, 80, '= [btnIsPressed]');
+ r.Top := 110;
+ Canvas.DrawButtonFace(r, [btfIsEmbedded, btfIsPressed]);
+ Canvas.DrawString(385, 110, '= [embed & press]');
+ r.Top := 140;
+ Canvas.DrawButtonFace(r, [btfIsEmbedded]);
+ Canvas.DrawString(385, 140, '= [btnIsEmbedded]');
+
+ Canvas.DrawString(45, y, 'DrawControlFrame():');
+ y := y + Canvas.Font.Height;
+ Canvas.DrawControlFrame(5, y, 150, 23);
+
+ // A Vector Text example
+ //----------------------
+ ac.LineWidth(1 );
+ ac.TextAlignment(AGG_AlignLeft ,AGG_AlignBottom );
+ // Normal Text
+ ac.LineColor($00 ,$00 ,$8B );
+ ac.FillColor($1E ,$90 ,$FF );
+ ac.Font('times.ttf' ,45);
+ ac.Text(20 ,250 , 'Vectors are cool !' );
+ // Upside-down Text
+ ac.FlipText(true );
+ ac.LineColor($C0 ,$C0 ,$C0 );
+ ac.FillColor($C0 ,$C0 ,$C0 );
+ ac.Text(20 ,255 ,'Vectors are cool !' );
+
+ // reset the text flip effect
+ ac.FlipText(False);
+
+ // Cool new button styles are now possible
+ DrawMacLionButton(65, 300, 0, 'Normal');
+ DrawMacLionButton(65, 330, 1, 'Hover');
+ DrawMacLionButton(65, 360, 2, 'Clicked');
+ // nice display of virtical text
+ c1.Construct(0,0,0);
+ ac.FillColor(c1);
+ ac.TextHints(true);
+ ac.NoLine;
+ ac.Font('arial.ttf', 13, false,
+ false, AGG_VectorFontCache, 45.0);
+ ac.Text(190, 310, 'Mac OS X Lion buttons', true ,0.0 ,0.0 );
+ // reset text alignment to normal behaviour
+ ac.TextAlignment(AGG_AlignLeft ,AGG_AlignBottom );
+
+
+ // Star shape
+ ac.LineCap(AGG_CapRound);
+ ac.LineWidth(5);
+ ac.LineColor($32 ,$cd ,$32 );
+ c1.Construct(0, 0 , 255, 200);
+ c2.Construct(0, 0, 255, 50);
+ ac.FillLinearGradient(100, 100, 150, 150, c1, c2);
+ ac.Star(100 ,150 ,30 ,70 ,55 ,5 );
+
+ // Draw Arc from 45 degrees to 270 degrees
+ ac.LineColor($FF ,$00 ,$00 );
+ ac.LineWidth(5 );
+ ac.Arc(300 ,320 ,80 ,50 ,Deg2Rad(45 ) ,Deg2Rad(270 ) );
+
+
+ // Lines at various thicknesses & coordinate translation
+ ac.LineColor(0, 0, 0);
+ ac.LineCap(AGG_CapRound);
+ d := 0.1;
+ for i := 1 to 10 do
+ begin
+ ac.LineWidth(d);
+ ac.Line(350, 240, 410, 180);
+ ac.Translate(8, 0);
+ d := d + 0.3;
+ end;
+ ac.ResetTransformations;
+
+
+
+ ac.LineWidth(20 );
+ ac.ResetPath;
+ ac.MoveTo(360 ,310 );
+ ac.LineTo(400 ,270 );
+ ac.LineTo(440 ,310 );
+
+ // Default AGG_JoinRound
+ ac.Translate(10 ,-10 );
+ ac.DrawPath(AGG_StrokeOnly );
+
+ // Change to AGG_JoinMiter
+ ac.LineJoin (AGG_JoinMiter );
+ ac.Translate(0 ,50 );
+ ac.DrawPath (AGG_StrokeOnly );
+
+ // Change to AGG_JoinBevel
+ ac.LineJoin (AGG_JoinBevel );
+ ac.Translate(0 ,50 );
+ ac.DrawPath (AGG_StrokeOnly );
+
+ ac.ResetTransformations;
+end;
+
+procedure TMainForm.AfterCreate;
+begin
+ {%region 'Auto-generated GUI code' -fold}
+ {@VFD_BODY_BEGIN: MainForm}
+ Name := 'MainForm';
+ SetPosition(357, 214, 500, 400);
+ WindowTitle := 'fpGUI with AGG-powered Canvas test';
+ Hint := '';
+ WindowPosition := wpOneThirdDown;
+ OnKeyPress := @FormKeyPressed;
+ OnPaint := @FormPaint;
+
+ {@VFD_BODY_END: MainForm}
+ {%endregion}
+
+ fpgApplication.HelpKey := keyNul;
+end;
+
+
+procedure MainProc;
+var
+ frm: TMainForm;
+begin
+ fpgApplication.Initialize;
+
+ frm := TMainForm.Create(nil);
+ frm.Show;
+ fpgApplication.Run;
+ frm.Free;
+end;
+
+
+begin
+ MainProc;
+end.
+
diff --git a/examples/corelib/aggcanvas/arial.ttf b/examples/corelib/aggcanvas/arial.ttf
new file mode 100644
index 00000000..7ff88f22
--- /dev/null
+++ b/examples/corelib/aggcanvas/arial.ttf
Binary files differ
diff --git a/examples/corelib/aggcanvas/arialbd.ttf b/examples/corelib/aggcanvas/arialbd.ttf
new file mode 100644
index 00000000..c2eb3ddd
--- /dev/null
+++ b/examples/corelib/aggcanvas/arialbd.ttf
Binary files differ
diff --git a/examples/corelib/aggcanvas/extrafpc.cfg b/examples/corelib/aggcanvas/extrafpc.cfg
new file mode 100644
index 00000000..775d592f
--- /dev/null
+++ b/examples/corelib/aggcanvas/extrafpc.cfg
@@ -0,0 +1,5 @@
+-FUunits
+-Fu../../../lib/$fpctarget
+-Xs
+-XX
+-CX
diff --git a/examples/corelib/aggcanvas/times.ttf b/examples/corelib/aggcanvas/times.ttf
new file mode 100644
index 00000000..a998feec
--- /dev/null
+++ b/examples/corelib/aggcanvas/times.ttf
Binary files differ
diff --git a/examples/corelib/aggcanvas/timesi.ttf b/examples/corelib/aggcanvas/timesi.ttf
new file mode 100644
index 00000000..28798d3c
--- /dev/null
+++ b/examples/corelib/aggcanvas/timesi.ttf
Binary files differ
diff --git a/prototypes/keyboard_symbols.txt b/prototypes/keyboard_symbols.txt
new file mode 100644
index 00000000..1bcd48a0
--- /dev/null
+++ b/prototypes/keyboard_symbols.txt
@@ -0,0 +1,37 @@
+
+
+ HTML Entity . .. GLYPH . . . NAME
+
+ &#63743;. . . . . ļ£æ . . . Apple
+
+ &#8984; . . . . . āŒ˜ . . . Command, Cmd, Clover, (formerly) Apple
+ &#8963; . . . . . āŒƒ . . . Control, Ctl, Ctrl
+ &#8997; . . . . . āŒ„ . . . Option, Opt, (Windows) Alt
+ &#8679; . . . . . ā‡§ . . . Shift
+ &#8682; . . . . . ā‡Ŗ . . . Caps lock
+ &#9167; . . . . . ā . . . Eject
+
+ &#8617; . . . . . ā†© . . . Return, Carriage Return
+ &#8629; &crarr; . ā†µ . . . Return, Carriage Return
+ &#9166; . . . . . āŽ . . . Return, Carriage Return
+ &#8996; . . . . . āŒ¤ . . . Enter
+
+ &#9003; . . . . . āŒ« . . . Delete, Backspace
+ &#8998; . . . . . āŒ¦ . . . Forward Delete
+ &#9099; . . . . . āŽ‹ . . . Escape, Esc
+
+ &#8594; &rarr; .. ā†’ . . . Right arrow
+ &#8592; &larr; .. ā† . . . Left arrow
+ &#8593; &uarr; .. ā†‘ . . . Up arrow
+ &#8595; &darr; .. ā†“ . . . Down arrow
+ &#8670; . . . . . ā‡ž . . . Page Up, PgUp
+ &#8671; . . . . . ā‡Ÿ . . . Page Down, PgDn
+ &#8598; . . . . . ā†– . . . Home
+ &#8600; . . . . . ā†˜ . . . End
+
+ &#8999; . . . . . āŒ§ . . . Clear
+ &#8677; . . . . . ā‡„ . . . Tab, Tab Right, Horizontal Tab
+ &#8676; . . . . . ā‡¤ . . . Shift Tab, Tab Left, Back-tab
+ &#9250; . . . . . ā¢ . . . Space, Blank
+ &#9251; . . . . . ā£ . .. . Space, Blank
+
diff --git a/src/VERSION_FILE.inc b/src/VERSION_FILE.inc
index f5780fb3..212d4aea 100644
--- a/src/VERSION_FILE.inc
+++ b/src/VERSION_FILE.inc
@@ -1 +1 @@
-FPGUI_VERSION = '0.8';
+FPGUI_VERSION = '1.0';
diff --git a/src/corelib/fpg_base.pas b/src/corelib/fpg_base.pas
index 5158540e..07d44191 100644
--- a/src/corelib/fpg_base.pas
+++ b/src/corelib/fpg_base.pas
@@ -22,6 +22,9 @@ unit fpg_base;
// To enable the AggPas powered Canvas
{.$define AGGCanvas}
+// For debug use only
+{.$define GDEBUG}
+
interface
uses
@@ -780,6 +783,9 @@ uses
fpg_form, // needed for fpgApplication.CreateForms()
typinfo,
process,
+ {$IFDEF GDEBUG}
+ dbugintf,
+ {$ENDIF}
dateutils;
@@ -2617,7 +2623,9 @@ begin
p.CommandLine := GetHelpViewer + ' ' + HelpFile
else
p.CommandLine := GetHelpViewer + ' ' + HelpFile + ' -n ' + IntToStr(AHelpContext);
-//writeln('DEBUG: TfpgApplicationBase.ContextHelp > ', p.CommandLine);
+ {$ifdef GDEBUG}
+ senddebug(p.CommandLine);
+ {$endif}
end
else
p.CommandLine := GetHelpViewer;
@@ -2640,7 +2648,9 @@ begin
if fpgFileExists(HelpFile) then
begin
p.CommandLine := GetHelpViewer + ' ' + HelpFile + ' -s ' + AHelpKeyword;
-//writeln('DEBUG: TfpgApplicationBase.ContextHelp > ', p.CommandLine);
+ {$ifdef GDEBUG}
+ senddebug(p.CommandLine);
+ {$endif}
end
else
p.CommandLine := GetHelpViewer;
diff --git a/src/corelib/fpg_imgfmt_bmp.pas b/src/corelib/fpg_imgfmt_bmp.pas
index 353b3216..ff354898 100644
--- a/src/corelib/fpg_imgfmt_bmp.pas
+++ b/src/corelib/fpg_imgfmt_bmp.pas
@@ -1,7 +1,7 @@
{
fpGUI - Free Pascal GUI Toolkit
- Copyright (C) 2006 - 2010 See the file AUTHORS.txt, included in this
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
distribution, for details of the copyright.
See the file COPYING.modifiedLGPL, included in this distribution,
@@ -39,6 +39,9 @@ uses
fpg_utils;
+procedure ReadImage_OS2BMP(img: TfpgImage; bmp: Pointer; bmpsize: longword); forward;
+
+
function CreateImage_BMP(bmp: Pointer; bmpsize: longword): TfpgImage;
begin
Result := TfpgImage.Create;
@@ -147,6 +150,13 @@ begin
p := bmp;
PByte(bh) := p;
+
+ if bh^.signature = $4d62 then { 'bM' }
+ begin
+ ReadImage_OS2BMP(img, bmp, bmpsize);
+ exit;
+ end;
+
ppal := nil;
if bh^.filesize <> bmpsize then
Exit; //==>
@@ -314,7 +324,229 @@ begin
until linecnt >= img.Height;
end;
else
- writeln('Unsupported BMP format!');
+ raise Exception.Create('Unsupported BMP format!');
+ end;
+
+ if ppal <> nil then
+ FreeMem(ppal);
+
+ img.UpdateImage;
+end;
+
+type
+ { These records come from the HelpBitmap unit - part of DocView }
+ INFBITMAPHEADER = packed record
+ // BITMAP FILE HEADER
+ usType: uint16; // = 'bM'
+ cbSize: uint32;
+ xHotspot: uint16;
+ yHotspot: uint16;
+ DataOffset: uint32; // =size(hdr)+size(palette)
+ // BITMAP INFO HEADER
+ cbFIx: uint32; // =size(info_hdr) (usually = 12?)
+ Width: uint16; // width size
+ Height: uint16; // height size
+ cPlanes: uint16; // planes, =1 (always seems to be one)
+ BitCount: uint16; // bits per pixel
+ // followed by RGB triples if <= 8bpp
+ end;
+
+
+procedure ReadImage_OS2BMP(img: TfpgImage; bmp: Pointer; bmpsize: longword);
+var
+ bh: ^INFBITMAPHEADER;
+ p: PByte;
+ ppal: plongword;
+ pcol: Plongword;
+ palsize: integer;
+ pdata: PByte;
+ b: byte;
+ bit: byte;
+ bcnt: byte;
+ linecnt: integer;
+ pixelcnt: integer;
+ pdest: Plongword;
+ depth: integer;
+
+ function GetPalColor(cindex: longword): longword;
+ var
+ pc: Plongword;
+ begin
+ pc := ppal;
+ Inc(pc, cindex);
+ Result := pc^;
+ end;
+
+begin
+ if img = nil then
+ Exit; //==>
+
+ img.FreeImage;
+
+ ppal := nil;
+ p := bmp;
+ PByte(bh) := p;
+
+ pdata := bmp;
+ Inc(pdata, bh^.DataOffset);
+ Inc(p, SizeOf(INFBITMAPHEADER));
+
+ depth := bh^.BitCount;
+
+ if depth > 1 then
+ img.AllocateImage(32, bh^.Width, bh^.Height)// color image (RGB or Indexed)
+ else
+ begin
+ img.AllocateImage(1, bh^.Width, bh^.Height);
+ img.AllocateMask;
+ end;
+
+ if depth <= 8 then
+ begin
+ // reading color palette
+ case depth of
+ 1: palsize := 2;
+ 4: palsize := 16;
+ else
+ palsize := 256;
+ end;
+
+ GetMem(ppal, palsize * SizeOf(longword));
+
+ pcol := ppal;
+ pixelcnt := 0;
+ // OS/2 1.x bitmap with uses 3-byte palette
+ while (p) < (pdata) do
+ begin
+ pcol^ := (LongWord($FF) shl 24) + (LongWord(p[2]) shl 16) + (LongWord(p[1]) shl 8) + LongWord(p[0]);
+ Inc(pcol);
+ inc(p, 3);
+ Inc(pixelcnt);
+ end;
+ end;
+
+ pdest := img.ImageData;
+ Inc(pdest, img.Width * (img.Height - 1)); // bottom-up line order
+ p := bmp;
+ Inc(p, bh^.DataOffset);
+
+ // reading the data...
+ case depth of
+ 1:
+ begin
+ // direct line transfer
+ //writeln('reading 1-bit color bitmap');
+ linecnt := 0;
+ bcnt := img.Width div 32;
+ if (img.Width and $1F) > 0 then
+ Inc(bcnt);
+
+ pdest := img.ImageData;
+ Inc(pdest, bcnt * (img.Height - 1)); // bottom-up line order
+ repeat
+ move(p^, pdest^, bcnt * 4);
+ Inc(p, bcnt * 4);
+ Dec(pdest, bcnt);
+ Inc(linecnt);
+ until linecnt >= img.Height;
+
+ //Writeln(linecnt,' lines loaded.');
+ move(img.ImageData^, img.MaskData^, img.ImageDataSize);
+ img.Invert(True);
+ end;
+
+ 4:
+ begin
+ //writeln('reading 4-bit color');
+ linecnt := 0;
+ repeat
+ // parse one line..
+ bit := 0;
+ pixelcnt := 0;
+ bcnt := 0;
+ repeat
+ if bit = 0 then
+ b := (p^ shr 4) and $0F
+ else
+ begin
+ b := p^ and $0F;
+ Inc(p);
+ Inc(bcnt);
+ end;
+
+ pdest^ := GetPalColor(b);
+ Inc(pdest);
+ Inc(pixelcnt);
+ bit := bit xor 1;
+ until pixelcnt >= img.Width;
+
+ while (bcnt mod 4) <> 0 do
+ begin
+ Inc(bcnt);
+ Inc(p);
+ end;
+
+ Inc(linecnt);
+ Dec(pdest, img.Width * 2); // go to next line
+ until linecnt >= img.Height;
+ end;
+
+ 8:
+ begin
+ //writeln('reading 8-bit color');
+ linecnt := 0;
+ repeat
+ // parse one line..
+ pixelcnt := 0;
+ repeat
+ pdest^ := GetPalColor(p^);
+ Inc(p);
+ Inc(pdest);
+ Inc(pixelcnt);
+ until pixelcnt >= img.Width;
+
+ while (pixelcnt mod 4) <> 0 do
+ begin
+ Inc(pixelcnt);
+ Inc(p);
+ end;
+
+ Inc(linecnt);
+ Dec(pdest, img.Width * 2); // go to next line
+ until linecnt >= img.Height;
+ end;
+
+ 24:
+ begin
+ //writeln('reading truecolor');
+ linecnt := 0;
+ repeat
+ // parse one line..
+ pixelcnt := 0;
+ repeat
+ pdest^ := p^;
+ Inc(p);
+ pdest^ := pdest^ or (longword(p^) shl 8);
+ Inc(p);
+ pdest^ := pdest^ or (longword(p^) shl 16) or ($FF shl 24) {alpha set to full opaque};
+ Inc(p);
+ Inc(pdest);
+ Inc(pixelcnt);
+ until pixelcnt >= img.Width;
+
+ pixelcnt := img.Width * 3;
+ while (pixelcnt mod 4) <> 0 do
+ begin
+ Inc(pixelcnt);
+ Inc(p);
+ end;
+
+ Inc(linecnt);
+ Dec(pdest, img.Width * 2); // go to next line
+ until linecnt >= img.Height;
+ end;
+ else
+ raise Exception.Create('Unsupported BMP format!');
end;
if ppal <> nil then
diff --git a/src/corelib/fpg_imgfmt_png.pas b/src/corelib/fpg_imgfmt_png.pas
index c0659d2e..c95150e4 100644
--- a/src/corelib/fpg_imgfmt_png.pas
+++ b/src/corelib/fpg_imgfmt_png.pas
@@ -1,7 +1,7 @@
{
fpGUI - Free Pascal GUI Toolkit
- Copyright (C) 2006 - 2012 See the file AUTHORS.txt, included in this
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
distribution, for details of the copyright.
See the file COPYING.modifiedLGPL, included in this distribution,
@@ -31,6 +31,7 @@ uses
function LoadImage_PNG(const AFileName: TfpgString): TfpgImage; overload;
function LoadImage_PNG(AStream: TStream): TfpgImage; overload;
+function LoadImage_PNG(const AImageData: Pointer; const AImageDataSize: LongWord): TfpgImage; overload;
function LoadImage_PNG(AInstance: THandle; const AResName: String; AResType: PChar): TfpgImage; overload;
function LoadImage_PNGcrop(const AMaxWidth, AMaxHeight: integer; const AFileName: TfpgString): TfpgImage;
@@ -114,6 +115,19 @@ begin
end;
end;
+function LoadImage_PNG(const AImageData: Pointer; const AImageDataSize: LongWord): TfpgImage;
+var
+ s: TMemoryStream;
+begin
+ s := TMemoryStream.Create;
+ try
+ s.Write(AImageData^, AImageDataSize);
+ Result := LoadImage_PNG(s);
+ finally
+ s.Free;
+ end;
+end;
+
function LoadImage_PNG(AInstance: THandle; const AResName: String; AResType: PChar): TfpgImage;
var
res: TResourceStream;
diff --git a/src/corelib/fpg_widget.pas b/src/corelib/fpg_widget.pas
index 67206557..a74c1b30 100644
--- a/src/corelib/fpg_widget.pas
+++ b/src/corelib/fpg_widget.pas
@@ -960,7 +960,7 @@ begin
dir := 0;
- if not consumed and (keycode = fpgApplication.HelpKey) then
+ if not consumed and (keycode = fpgApplication.HelpKey) and (shiftstate=[]) then
begin
InvokeHelp;
consumed := True;
diff --git a/src/corelib/render/software/Agg2D.pas b/src/corelib/render/software/Agg2D.pas
index 280736af..50a68fb8 100644
--- a/src/corelib/render/software/Agg2D.pas
+++ b/src/corelib/render/software/Agg2D.pas
@@ -40,51 +40,51 @@ interface
{$ENDIF}
uses
- agg_basics ,
- agg_array ,
- agg_trans_affine ,
- agg_trans_viewport ,
- agg_path_storage ,
- agg_conv_stroke ,
- agg_conv_transform ,
- agg_conv_curve ,
- agg_conv_dash ,
- agg_rendering_buffer ,
- agg_renderer_base ,
- agg_renderer_scanline ,
- agg_span_gradient ,
- agg_span_image_filter_rgba ,
- agg_span_image_resample_rgba ,
- agg_span_converter ,
- agg_span_interpolator_linear ,
- agg_span_allocator ,
- agg_rasterizer_scanline_aa ,
- agg_gamma_functions ,
- agg_scanline_u ,
- agg_arc ,
- agg_bezier_arc ,
- agg_rounded_rect ,
- agg_font_engine ,
- agg_font_cache_manager ,
- agg_pixfmt ,
- agg_pixfmt_rgb ,
- agg_pixfmt_rgba ,
- agg_color ,
- agg_math_stroke ,
- agg_image_filters ,
- agg_vertex_source ,
- agg_render_scanlines ,
+ agg_basics ,
+ agg_array ,
+ agg_trans_affine ,
+ agg_trans_viewport ,
+ agg_path_storage ,
+ agg_conv_stroke ,
+ agg_conv_transform ,
+ agg_conv_curve ,
+ agg_conv_dash ,
+ agg_rendering_buffer ,
+ agg_renderer_base ,
+ agg_renderer_scanline ,
+ agg_span_gradient ,
+ agg_span_image_filter_rgba ,
+ agg_span_image_resample_rgba ,
+ agg_span_converter ,
+ agg_span_interpolator_linear ,
+ agg_span_allocator ,
+ agg_rasterizer_scanline_aa ,
+ agg_gamma_functions ,
+ agg_scanline_u ,
+ agg_arc ,
+ agg_bezier_arc ,
+ agg_rounded_rect ,
+ agg_font_engine ,
+ agg_font_cache_manager ,
+ agg_pixfmt ,
+ agg_pixfmt_rgb ,
+ agg_pixfmt_rgba ,
+ agg_color ,
+ agg_math_stroke ,
+ agg_image_filters ,
+ agg_vertex_source ,
+ agg_render_scanlines ,
{$IFDEF AGG2D_USE_FREETYPE }
- agg_font_freetype ,
+ agg_font_freetype ,
{$ENDIF }
{$IFDEF AGG2D_USE_WINFONTS}
- agg_font_win32_tt ,
+ agg_font_win32_tt ,
{$ENDIF }
- Math ,
- Classes,
- SysUtils,
+ Math,
+ Classes,
+ SysUtils,
// This allows for platform specific uses clauses
{$define uses_interface}
@@ -98,8 +98,8 @@ uses
{$I agg_platform_x11.inc}
{$ENDIF}
- fpg_base,
- fpg_main;
+ fpg_base,
+ fpg_main;
{ GLOBAL VARIABLES & CONSTANTS }
const
diff --git a/src/gui/fpg_menu.pas b/src/gui/fpg_menu.pas
index 8da9302f..91db5992 100644
--- a/src/gui/fpg_menu.pas
+++ b/src/gui/fpg_menu.pas
@@ -135,6 +135,7 @@ type
destructor Destroy; override;
procedure Close; override;
function AddMenuItem(const AMenuName: TfpgString; const hotkeydef: string; OnClickProc: TNotifyEvent): TfpgMenuItem;
+ procedure AddSeparator;
function MenuItemByName(const AMenuName: TfpgString): TfpgMenuItem;
function MenuItem(const AMenuPos: integer): TfpgMenuItem; // added to allow for localization
property BeforeShow: TNotifyEvent read FBeforeShow write FBeforeShow;
@@ -1406,6 +1407,11 @@ begin
end;
end;
+procedure TfpgPopupMenu.AddSeparator;
+begin
+ AddMenuitem('-', '', nil);
+end;
+
function TfpgPopupMenu.MenuItemByName(const AMenuName: TfpgString): TfpgMenuItem;
var
i: integer;
diff --git a/src/gui/fpg_tree.pas b/src/gui/fpg_tree.pas
index 4a4316ac..8935ec36 100644
--- a/src/gui/fpg_tree.pas
+++ b/src/gui/fpg_tree.pas
@@ -1868,74 +1868,77 @@ var
OldSelection: TfpgTreeNode;
begin
OldSelection := Selection;
- case KeyCode of
- keyRight:
- begin
- Consumed := True;
- Selection.Expand;
- DoExpand(Selection);
- ResetScrollbar;
- RePaint;
- end;
+ if ShiftState = [] then
+ begin
+ case KeyCode of
+ keyRight:
+ begin
+ Consumed := True;
+ Selection.Expand;
+ DoExpand(Selection);
+ ResetScrollbar;
+ RePaint;
+ end;
- keyLeft:
- begin
- Consumed := True;
- Selection.Collapsed := true;
- ResetScrollbar;
- RePaint;
- end;
+ keyLeft:
+ begin
+ Consumed := True;
+ Selection.Collapsed := true;
+ ResetScrollbar;
+ RePaint;
+ end;
- keyUp:
- begin
- if Selection = nil then
- Selection := RootNode.FirstSubNode
- else
- if Selection <> RootNode then
+ keyUp:
+ begin
+ if Selection = nil then
+ Selection := RootNode.FirstSubNode
+ else
+ if Selection <> RootNode then
+ begin
+ if NodeIsVisible(selection) then
+ begin
+ h := PrevVisualNode(Selection);
+ if (h <> RootNode) and (h <> nil) then
+ Selection := h;
+ end
+ else
+ begin
+ Selection := RootNode.FirstSubNode;
+ end;
+ end;
+ Consumed := True;
+ end;
+
+ keyDown:
+ begin
+ Consumed := True;
+ if Selection = nil then
+ Selection := RootNode.FirstSubNode
+ else
begin
if NodeIsVisible(selection) then
begin
- h := PrevVisualNode(Selection);
- if (h <> RootNode) and (h <> nil) then
+ h := NextVisualNode(Selection);
+ if (h <> nil) then
Selection := h;
end
else
- begin
Selection := RootNode.FirstSubNode;
- end;
end;
- Consumed := True;
- end;
+ end;
- keyDown:
- begin
- Consumed := True;
- if Selection = nil then
- Selection := RootNode.FirstSubNode
- else
+ keyPageUp:
begin
- if NodeIsVisible(selection) then
- begin
- h := NextVisualNode(Selection);
- if (h <> nil) then
- Selection := h;
- end
- else
- Selection := RootNode.FirstSubNode;
+ FVScrollbar.PageUp;
end;
- end;
-
- keyPageUp:
- begin
- FVScrollbar.PageUp;
- end;
- keyPageDown:
- begin
- FVScrollbar.PageDown;
- end;
- else
- Consumed := False;
+ keyPageDown:
+ begin
+ FVScrollbar.PageDown;
+ end;
+ else
+ Consumed := False;
+ end;
end;
if Selection <> OldSelection then