Compare commits
17
Commits
buopt
...
displayfix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acd957aec3 | ||
|
|
f7a8d5b406 | ||
|
|
85de3929e5 | ||
|
|
0a8c6d8bc2 | ||
|
|
a00efd15c6 | ||
|
|
06c8ab6204 | ||
|
|
cd55562c46 | ||
|
|
6d142b62e7 | ||
|
|
da2f503367 | ||
|
|
a9ac66788a | ||
|
|
4cc9f9cf01 | ||
|
|
7b1898d9fd | ||
|
|
e4d297893e | ||
|
|
0173dd8c40 | ||
|
|
cf344d773e | ||
|
|
8c51c1d527 | ||
|
|
6e48ea9ddd |
@@ -61,6 +61,8 @@ changes made. See document footer for additional details.
|
||||
* fixed embedded Archer display and mode menus - Cliff Yapp
|
||||
* added Archer -h and --help command-line options - Cliff Yapp
|
||||
* fixed Archer Help opening the documentation menu - Sean Morrison
|
||||
* improved fallback methodologies for facetize pipeline - Cliff Yapp
|
||||
* improved facetize pipeline robustness - Cliff Yapp
|
||||
* added arrange nest command for packing database objects - Sean Morrison
|
||||
* new mkbuilding tool for parametric/OSM/CityJSON models - Sean Morrison
|
||||
* cross-platform BINUNIF and DSP byte-order handling - Sean Morrison
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BRL-CAD
|
||||
Release 7.44.2
|
||||
http://brlcad.org/
|
||||
BRL-CAD
|
||||
Release 7.44.2
|
||||
http://brlcad.org/
|
||||
|
||||
BRL-CAD is a powerful cross-platform open source combinatorial
|
||||
solid modeling system that includes an interactive 3D solid geometry
|
||||
|
||||
@@ -61,5 +61,4 @@ Author: Paul Mackerras (paulus@cs.anu.edu.au),
|
||||
|
||||
file:/src/libtclcad/tkImgFmtPIX.c
|
||||
file:/src/tclscripts/cad_clrpick.tcl
|
||||
file:/src/tclscripts/html_library.tcl
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ set(
|
||||
gqa.mass_mix.am.out
|
||||
gqa.mass_mix.aw.out
|
||||
gqa.mass_mix.u0.out
|
||||
gqa.missing_density.out
|
||||
gqa.mged
|
||||
gqa.overlaps.plot3
|
||||
gqa.sphere_adaptive.out
|
||||
|
||||
@@ -67,6 +67,11 @@ run_capture ( ) {
|
||||
return $ret
|
||||
}
|
||||
|
||||
expect_failure ( ) {
|
||||
"$@"
|
||||
test $? -ne 0
|
||||
}
|
||||
|
||||
extract_last_number ( ) {
|
||||
label="$1"
|
||||
file="$2"
|
||||
@@ -101,6 +106,19 @@ assert_close ( ) {
|
||||
fi
|
||||
}
|
||||
|
||||
assert_contains ( ) {
|
||||
expected="$1"
|
||||
file="$2"
|
||||
desc="$3"
|
||||
|
||||
if grep -F -q "$expected" "$file" ; then
|
||||
log "PASS: $desc"
|
||||
else
|
||||
log "FAIL: $desc"
|
||||
STATUS="`expr $STATUS + 1`"
|
||||
fi
|
||||
}
|
||||
|
||||
MGED="`ensearch mged`"
|
||||
if test ! -f "$MGED" ; then
|
||||
log "Unable to find mged, aborting"
|
||||
@@ -177,6 +195,10 @@ adjust mass_air.r GIFTmater 2
|
||||
g mass_air_only.g mass_air.r
|
||||
g mass_air_mix.g mass_solid.r mass_air.r
|
||||
|
||||
in missing_density.s rpp 2 3 0 1 0 1
|
||||
r missing_density.r u missing_density.s
|
||||
adjust missing_density.r GIFTmater 123
|
||||
|
||||
in sphere.s sph 0 0 0 1
|
||||
r sphere.r u sphere.s
|
||||
adjust sphere.r GIFTmater 5
|
||||
@@ -243,6 +265,7 @@ run_capture gqa.mass_mix.aw.out $GQABIN -u m,m^3,kg -g 250mm-50mm -Aw gqa.g mass
|
||||
run_capture gqa.mass_mix.am.out $GQABIN -u m,m^3,kg -g 250mm-50mm -Am gqa.g mass_air_mix.g
|
||||
run_capture gqa.mass_mix.u0.out $GQABIN -u m,m^3,kg -g 250mm-50mm -U 0 -Aw gqa.g mass_air_mix.g
|
||||
run_capture gqa.sphere_adaptive.out $GQABIN -u m,m^3,kg -q -Av -g 0.05m gqa.g sphere.r
|
||||
run_capture gqa.missing_density.out expect_failure $GQABIN -u m,m^3,kg -g 250mm-50mm -f density_table.txt -Aw gqa.g missing_density.r
|
||||
|
||||
MASS_AIR_AW="`extract_last_number 'Average total weight:' gqa.mass_air.aw.out`"
|
||||
MASS_AIR_AM="`extract_last_number 'Average total weight:' gqa.mass_air.am.out`"
|
||||
@@ -257,6 +280,7 @@ assert_close 1001 "$MASS_MIX_AW" 0.001 "mixed solid+air modeled weight with -Aw"
|
||||
assert_close "$MASS_MIX_AW" "$MASS_MIX_AM" 0.001 "-Aw and -Am agree on mixed modeled air"
|
||||
assert_close 1000 "$MASS_MIX_U0" 0.001 "-U 0 excludes modeled air from weight"
|
||||
assert_close 4.18879 "$SPHERE_VOLUME" 0.01 "adaptive sphere volume refines beyond symmetric first pass"
|
||||
assert_contains "Density 123 on region /missing_density.r is not defined in the density table." gqa.missing_density.out "undefined density produces an error"
|
||||
|
||||
|
||||
if [ $STATUS = 0 ] ; then
|
||||
|
||||
@@ -68,6 +68,7 @@ set(
|
||||
sca_view.mged
|
||||
search_exec.mged
|
||||
sed.mged
|
||||
sed_reset.mged
|
||||
set_perspective.mged
|
||||
setview.mged
|
||||
size.mged
|
||||
@@ -145,6 +146,10 @@ if(TARGET mged)
|
||||
elseif(TNAME STREQUAL "prim_edit")
|
||||
set(TEST_EXPECT "Primitive parameter editing testing completed")
|
||||
set(TEST_REJECT "FAIL:")
|
||||
elseif(TNAME STREQUAL "sed_reset")
|
||||
set(TEST_EXPECT "PASS: 'sed_reset' testing completed")
|
||||
set(TEST_REJECT "FAIL:")
|
||||
set(TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/regress_${testfile}")
|
||||
elseif(TNAME STREQUAL "overlap_plotting")
|
||||
set(TEST_DB "${CMAKE_SOURCE_DIR}/src/libged/tests/ged_tests.g")
|
||||
set(TEST_EXPECT "PASS overlap plotting")
|
||||
|
||||
@@ -119,4 +119,35 @@ if {![catch {get $invalid_inner}]} {
|
||||
}
|
||||
|
||||
|
||||
# ARBN uses one independent thickness per plane. Exercise unequal offsets so
|
||||
# the test also verifies the plane ordering and inward normal convention.
|
||||
set arbn_outer inside_arbn_outer.s
|
||||
set arbn_inner inside_arbn_inner.s
|
||||
set arbn_thicknesses {1 2 3 4 1.5 0.5}
|
||||
in $arbn_outer arbn 6 \
|
||||
1 0 0 10 -1 0 0 0 \
|
||||
0 1 0 10 0 -1 0 0 \
|
||||
0 0 1 10 0 0 -1 0
|
||||
if {[catch {inside $arbn_outer $arbn_inner {*}$arbn_thicknesses} result]} {
|
||||
error "inside failed for ARBN: $result"
|
||||
}
|
||||
set arbn_definition [get $arbn_inner]
|
||||
set expected_offsets {9 -2 7 -4 8.5 -0.5}
|
||||
for {set plane 0} {$plane < 6} {incr plane} {
|
||||
set equation [lindex $arbn_definition [expr {4 + 2 * $plane}]]
|
||||
set actual_offset [lindex $equation 3]
|
||||
if {abs($actual_offset - [lindex $expected_offsets $plane]) > $plane_tolerance} {
|
||||
error "ARBN inside plane $plane has offset $actual_offset: $arbn_definition"
|
||||
}
|
||||
}
|
||||
facetize -n inside_arbn_inner_nmg.s $arbn_inner
|
||||
|
||||
set invalid_arbn_inner inside_arbn_invalid.s
|
||||
if {![catch {inside $arbn_outer $invalid_arbn_inner {*}[lrepeat 6 6]}]} {
|
||||
error "ARBN inside accepted thicknesses that collapse the solid"
|
||||
}
|
||||
if {![catch {get $invalid_arbn_inner}]} {
|
||||
error "ARBN inside wrote an invalid collapsed solid"
|
||||
}
|
||||
|
||||
puts "*** 'arb' testing completed ***"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
puts "*** Testing 'sed_reset' command ***"
|
||||
|
||||
proc sed_reset_check {primitive edit_commands} {
|
||||
e $primitive
|
||||
sed $primitive
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive entered [status state], not SOL EDIT"
|
||||
}
|
||||
|
||||
set original [get_sed]
|
||||
foreach command $edit_commands {
|
||||
uplevel #0 $command
|
||||
}
|
||||
if {[get_sed] eq $original} {
|
||||
error "$primitive edit did not change the working geometry"
|
||||
}
|
||||
|
||||
sed_reset
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive reset entered [status state], not SOL EDIT"
|
||||
}
|
||||
if {[get_sed] ne $original} {
|
||||
error "$primitive reset did not restore the original geometry"
|
||||
}
|
||||
|
||||
press reject
|
||||
if {[status state] ne "VIEWING"} {
|
||||
error "$primitive reject entered [status state], not VIEWING"
|
||||
}
|
||||
d $primitive
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
in sed_reset_arb8.s arb8 \
|
||||
0 0 0 10 0 0 10 10 0 0 10 0 \
|
||||
0 0 10 10 0 10 10 10 10 0 10 10
|
||||
sed_reset_check sed_reset_arb8.s {
|
||||
{press {Move Faces}}
|
||||
{press {Move Face 1234}}
|
||||
{p 0 0 -1}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: ARB8 face move reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: ARB8 face move reset"
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
make sed_reset_cline.s cline
|
||||
sed_reset_check sed_reset_cline.s {
|
||||
{press {Move End H}}
|
||||
{p 3 4 12}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: CLINE edit reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: CLINE edit reset"
|
||||
}
|
||||
|
||||
puts "PASS: 'sed_reset' testing completed"
|
||||
@@ -50,6 +50,18 @@ proc ::mged::xmin::help::exercise_command_manual {top} {
|
||||
::gui::test::require {
|
||||
[llength $selection] == 1 && [$toc get $selection] eq "rt"
|
||||
} "man rt did not select and load the rt manual page"
|
||||
|
||||
event generate $toc <<ListboxSelect>>
|
||||
::mged::gui::test::settle
|
||||
|
||||
man search
|
||||
set html_view [$browser component browser].htmlview
|
||||
set html_widget [$html_view html]
|
||||
$html_view goto {#hierarchy_performance}
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[lindex [$html_widget yview] 0] > 0.0} \
|
||||
"manual browser did not follow an in-page hyperlink"
|
||||
|
||||
::gui::test::require {
|
||||
[catch {man xmin_page_that_does_not_exist} message] &&
|
||||
[string first "couldn't find manual page" $message] >= 0
|
||||
@@ -151,10 +163,38 @@ proc ::mged::xmin::help::exercise_html_manual {top} {
|
||||
set mged_browser [file join $::env(GUI_TEST_DIR) missing-browser]
|
||||
::mged::gui::test::invoke $top {Help Manual}
|
||||
set fallback $top.man
|
||||
set viewer $fallback.html
|
||||
::gui::test::require {
|
||||
[winfo exists $fallback] && [winfo ismapped $fallback] &&
|
||||
[string length [string trim [$fallback.text get 1.0 end]]] > 100
|
||||
[winfo exists $viewer] && [$viewer title] eq "Table of Contents"
|
||||
} "Manual did not load MGED's internal HTML viewer"
|
||||
|
||||
set special_path [file join [pwd] {manual path} {contents#1.html}]
|
||||
::gui::test::require {
|
||||
[::mged::manual::local_path \
|
||||
[::mged::manual::file_uri $special_path]] eq \
|
||||
[file normalize $special_path]
|
||||
} "internal Manual viewer did not preserve special path characters"
|
||||
|
||||
set html [$viewer html]
|
||||
set contents [$html text text]
|
||||
::gui::test::require {
|
||||
[string first "Preface" $contents] >= 0 &&
|
||||
[string first "background-color" $contents] < 0
|
||||
} "internal Manual viewer did not render its table of contents"
|
||||
|
||||
$viewer goto mged.html#csg
|
||||
::mged::gui::test::settle
|
||||
set contents [$html text text]
|
||||
::gui::test::require {
|
||||
[$viewer title] eq "Mged User's Manual" &&
|
||||
[string first "Modeling With CSG" $contents] >= 0
|
||||
} "internal Manual viewer did not follow its document links"
|
||||
|
||||
$fallback.f.back invoke
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[$viewer title] eq "Table of Contents"} \
|
||||
"internal Manual viewer Back button did not restore the prior page"
|
||||
destroy $fallback
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,20 @@
|
||||
#include "InformationGatherer.h"
|
||||
#include "bu/log.h"
|
||||
|
||||
// flush results, if we have any, then exit
|
||||
static void reportAndExit(const std::string &message, const std::string &result = "")
|
||||
{
|
||||
if (!result.empty())
|
||||
bu_log("%s%s", result.c_str(), result.back() == '\n' ? "" : "\n");
|
||||
|
||||
bu_exit(BRLCAD_ERROR, "%s", message.c_str());
|
||||
}
|
||||
|
||||
|
||||
std::string getCmdPath(std::string exeDir, const char* cmd) {
|
||||
char buf[MAXPATHLEN] = {0};
|
||||
if (!bu_dir(buf, MAXPATHLEN, exeDir.c_str(), cmd, BU_DIR_EXT, NULL))
|
||||
bu_exit(BRLCAD_ERROR, "Couldn't find %s, aborting.\n", cmd);
|
||||
reportAndExit("Couldn't find " + std::string(cmd) + ", aborting.\n");
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
@@ -58,13 +68,13 @@ getSurfaceArea(Options* opt, std::map<std::string, std::string> UNUSED(map), std
|
||||
bu_process_create(&p, rtarea_av, BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem with getSurfaceArea, aborting\n");
|
||||
reportAndExit("Problem with getSurfaceArea, aborting\n");
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
std::string result;
|
||||
int read_cnt = 0;
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 128-1, buffer)) > 0) {
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
/* NOTE: read does not ensure null-termination, thus buffersize-1 */
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
@@ -80,7 +90,7 @@ getSurfaceArea(Options* opt, std::map<std::string, std::string> UNUSED(map), std
|
||||
try {
|
||||
surfArea += stod(result);
|
||||
} catch (const std::invalid_argument& ia) {
|
||||
bu_exit(BRLCAD_ERROR, "Invalid argument for getSurfaceArea. Got (%s), aborting.\n", ia.what());
|
||||
reportAndExit("Invalid argument for getSurfaceArea. Got (" + std::string(ia.what()) + "), aborting.\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +210,7 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
struct bu_process* p;
|
||||
int read_cnt = 0;
|
||||
char buffer[1024] = {0};
|
||||
std::string result = "";
|
||||
std::string result;
|
||||
std::string ncpu(std::to_string(opt->getNCPU()));
|
||||
std::string dFile(opt->getDensityFile());
|
||||
|
||||
@@ -233,21 +243,23 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
bu_process_create(&p, const_cast<const char**>(gqa_av_vec.data()), BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem in getVerificationData gqa process creation, aborting\n");
|
||||
reportAndExit("Problem in getVerificationData gqa process creation, aborting\n");
|
||||
}
|
||||
|
||||
result = "";
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 1024-1, buffer)) > 0) {
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
}
|
||||
|
||||
if (bu_process_wait_n(&p, 0) != 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem collecting gqa volume and mass, aborting\n");
|
||||
const int gqa_status = bu_process_wait_n(&p, 0);
|
||||
|
||||
// sanity - we should have clean status code and not the "no density found" message
|
||||
const bool no_density_data = result.find(no_density_msg) != std::string::npos;
|
||||
if (gqa_status != 0 && (!no_density_data || !dFile.empty())) {
|
||||
reportAndExit("Problem collecting gqa volume and mass, aborting\n", result);
|
||||
}
|
||||
|
||||
// make sure we did not get 'no density file' error message
|
||||
if (result.find(no_density_msg) == std::string::npos) {
|
||||
if (!no_density_data) {
|
||||
// NOTE: tmp_val is zeroed at each parseLabeledNumber call
|
||||
if (parseLabeledNumber(tmp_val, result, volume_label))
|
||||
volume += tmp_val;
|
||||
@@ -263,17 +275,17 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
bu_process_create(&p, const_cast<const char**>(gqa_av_vec.data()), BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem in getVerificationData gqa process creation, aborting\n");
|
||||
reportAndExit("Problem in getVerificationData gqa process creation, aborting\n");
|
||||
}
|
||||
|
||||
result = "";
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 1024-1, buffer)) > 0) {
|
||||
result.clear();
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
}
|
||||
|
||||
if (bu_process_wait_n(&p, 0) != 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem collecting gqa volume, aborting\n");
|
||||
reportAndExit("Problem collecting gqa volume, aborting\n", result);
|
||||
}
|
||||
|
||||
if (parseLabeledNumber(tmp_val, result, volume_label))
|
||||
@@ -381,7 +393,7 @@ InformationGatherer::getMainComp()
|
||||
ged_exec_exists(g, 2, cmd);
|
||||
std::string res = bu_vls_addr(g->ged_result_str);
|
||||
if (res != "1") {
|
||||
bu_exit(BRLCAD_ERROR, "Could not find component (%s), aborting.\n", topname);
|
||||
reportAndExit("Could not find component (" + topcomp + "), aborting.\n");
|
||||
}
|
||||
|
||||
int entities = getNumEntities(opt->getTopComp());
|
||||
|
||||
+3
-2
@@ -43,6 +43,7 @@ main(int argc, char *argv[])
|
||||
int i, j;
|
||||
int db_index;
|
||||
int c;
|
||||
int ret;
|
||||
const char **av;
|
||||
struct ged *gedp;
|
||||
|
||||
@@ -103,14 +104,14 @@ main(int argc, char *argv[])
|
||||
bu_exit(1, usage, argv[0]);
|
||||
}
|
||||
|
||||
(void)ged_exec_gqa(gedp, j, av);
|
||||
ret = ged_exec_gqa(gedp, j, av);
|
||||
if (bu_vls_strlen(gedp->ged_result_str) > 0)
|
||||
bu_log("%s", bu_vls_addr(gedp->ged_result_str));
|
||||
ged_close(gedp);
|
||||
|
||||
bu_free((void *)av, "av");
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-2
@@ -891,8 +891,8 @@ Done:
|
||||
int
|
||||
ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
{
|
||||
struct gl_vars *mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
struct pogl_vars *privars = (struct pogl_vars *)dmp1->i->dm_vars.priv_vars;
|
||||
struct gl_vars *mvars;
|
||||
struct pogl_vars *privars;
|
||||
GLfloat backgnd[4];
|
||||
GLfloat vf;
|
||||
GLXContext old_glxContext;
|
||||
@@ -900,6 +900,9 @@ ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
if (dmp1 == (struct dm *)NULL)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
privars = (struct pogl_vars *)dmp1->i->dm_vars.priv_vars;
|
||||
|
||||
if (dmp2 == (struct dm *)NULL) {
|
||||
/* create a new graphics context for dmp1 with private display lists */
|
||||
|
||||
@@ -1053,6 +1056,11 @@ ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
glXDestroyContext(((struct dm_glxvars *)dmp2->i->dm_vars.pub_vars)->dpy, old_glxContext);
|
||||
}
|
||||
|
||||
struct dm *target_dmp = dmp2 ? dmp2 : dmp1;
|
||||
struct gl_vars *target_mvars = (struct gl_vars *)target_dmp->i->m_vars;
|
||||
gl_setZBuffer(target_dmp, target_mvars->zbuffer_on);
|
||||
gl_setLight(target_dmp, target_mvars->lighting_on);
|
||||
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,15 +254,9 @@ qtgl_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
|
||||
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
|
||||
bu_vls_printf(&dmp->i->dm_pathName, ".dm_qtgl%d", count);
|
||||
++count;
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
}
|
||||
/* The supplied QOpenGLWidget determines the Qt display. Keep dm_dName
|
||||
* empty unless the caller supplied -d; DISPLAY is an X11 setting and
|
||||
* cannot identify a Qt context on every supported platform. */
|
||||
|
||||
/* initialize dm specific variables */
|
||||
pubvars->devmotionnotify = 0;
|
||||
|
||||
@@ -246,15 +246,9 @@ swrast_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
|
||||
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
|
||||
bu_vls_printf(&dmp->i->dm_pathName, ".dm_swrast%d", count);
|
||||
++count;
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
}
|
||||
/* OSMesa is offscreen and has no display to discover. Leave dm_dName
|
||||
* empty unless the caller supplied -d; a window-system wrapper can then
|
||||
* select its own initialized display without inheriting X11 state. */
|
||||
|
||||
/* initialize dm specific variables */
|
||||
pubvars->devmotionnotify = 0;
|
||||
|
||||
@@ -464,6 +464,16 @@ tkswrast_open(void *ctx, void *vinterp, int argc, const char **argv)
|
||||
tv->orig_configureWin = dmp->i->dm_configureWin;
|
||||
tv->orig_close = dmp->i->dm_close;
|
||||
|
||||
/* The wrapped offscreen backend deliberately has no default display.
|
||||
* For this Tk presentation layer, use the display Tk actually opened.
|
||||
* This remains correct for X11, Win32, and Aqua even when the process
|
||||
* inherited an unrelated DISPLAY value. An explicit -d remains intact
|
||||
* and is validated below by Tk_CreateWindowFromPath. */
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
|
||||
Tk_ScreenNumber(tkwin));
|
||||
}
|
||||
|
||||
char *cp = strrchr(bu_vls_addr(&dmp->i->dm_pathName), '.');
|
||||
if (dmp->i->dm_top) {
|
||||
tv->xtkwin = Tk_CreateWindowFromPath(interp, tkwin,
|
||||
|
||||
+13
-8
@@ -88,11 +88,13 @@ wgl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
GLfloat backgnd[4];
|
||||
GLfloat vf;
|
||||
HGLRC old_glxContext;
|
||||
struct gl_vars *mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
struct gl_vars *mvars;
|
||||
|
||||
if (dmp1 == (struct dm *)NULL)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
|
||||
if (dmp2 == (struct dm *)NULL) {
|
||||
/* create a new graphics context for dmp1 with private display lists */
|
||||
|
||||
@@ -244,6 +246,11 @@ wgl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
wglDeleteContext(old_glxContext);
|
||||
}
|
||||
|
||||
struct dm *target_dmp = dmp2 ? dmp2 : dmp1;
|
||||
struct gl_vars *target_mvars = (struct gl_vars *)target_dmp->i->m_vars;
|
||||
gl_setZBuffer(target_dmp, target_mvars->zbuffer_on);
|
||||
gl_setLight(target_dmp, target_mvars->lighting_on);
|
||||
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
@@ -1033,13 +1040,11 @@ wgl_open(void *UNUSED(ctx), void *vinterp, int argc, const char *argv[])
|
||||
++count;
|
||||
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
/* DISPLAY names an X server and is not meaningful to WGL. Unix-like
|
||||
* shells on Windows may nevertheless export it, so use the screen of
|
||||
* the Tk window that supplies the native HWND. */
|
||||
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
|
||||
Tk_ScreenNumber(tkwin));
|
||||
}
|
||||
|
||||
/* initialize dm specific variables */
|
||||
|
||||
+115
-33
@@ -138,30 +138,37 @@ static const char *p_nmgin[] = {
|
||||
|
||||
|
||||
#define ARB_FACE_COUNT 6
|
||||
#define ARB_MAX_PLANE_INTERSECTIONS 20
|
||||
|
||||
|
||||
/* Verify that every plane bounds a non-degenerate convex volume. Translating
|
||||
* the planes of an existing convex ARB cannot make their intersection
|
||||
* the planes of an existing convex polyhedron cannot make their intersection
|
||||
* unbounded, but excessive or unequal thicknesses can eliminate a face or
|
||||
* collapse the volume. */
|
||||
static int
|
||||
arb_in_planes_valid(plane_t planes[ARB_FACE_COUNT], const struct bn_tol *tol)
|
||||
in_planes_valid(const plane_t *planes, size_t plane_count,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
point_t vertices[ARB_MAX_PLANE_INTERSECTIONS];
|
||||
int plane_used[ARB_FACE_COUNT] = {0};
|
||||
size_t vertex_count = 0;
|
||||
point_t basis[3];
|
||||
plane_t basis_plane;
|
||||
size_t basis_count = 0;
|
||||
int have_volume = 0;
|
||||
|
||||
for (size_t i = 0; i < ARB_FACE_COUNT - 2; i++) {
|
||||
for (size_t j = i + 1; j < ARB_FACE_COUNT - 1; j++) {
|
||||
for (size_t k = j + 1; k < ARB_FACE_COUNT; k++) {
|
||||
if (!planes || plane_count < 4)
|
||||
return 0;
|
||||
|
||||
int *plane_used = (int *)bu_calloc(plane_count, sizeof(int),
|
||||
"inside plane use flags");
|
||||
|
||||
for (size_t i = 0; i < plane_count - 2; i++) {
|
||||
for (size_t j = i + 1; j < plane_count - 1; j++) {
|
||||
for (size_t k = j + 1; k < plane_count; k++) {
|
||||
point_t candidate;
|
||||
int outside = 0;
|
||||
|
||||
if (bg_make_pnt_3planes(candidate, planes[i], planes[j], planes[k]) < 0)
|
||||
continue;
|
||||
|
||||
for (size_t face = 0; face < ARB_FACE_COUNT; face++) {
|
||||
for (size_t face = 0; face < plane_count; face++) {
|
||||
if (DIST_PNT_PLANE(candidate, planes[face]) > tol->dist) {
|
||||
outside = 1;
|
||||
break;
|
||||
@@ -173,35 +180,39 @@ arb_in_planes_valid(plane_t planes[ARB_FACE_COUNT], const struct bn_tol *tol)
|
||||
plane_used[i] = 1;
|
||||
plane_used[j] = 1;
|
||||
plane_used[k] = 1;
|
||||
VMOVE(vertices[vertex_count], candidate);
|
||||
vertex_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t face = 0; face < ARB_FACE_COUNT; face++)
|
||||
if (!plane_used[face])
|
||||
return 0;
|
||||
|
||||
/* At least four non-coplanar vertices are required for a volume. */
|
||||
for (size_t i = 0; i + 2 < vertex_count; i++) {
|
||||
for (size_t j = i + 1; j + 1 < vertex_count; j++) {
|
||||
for (size_t k = j + 1; k < vertex_count; k++) {
|
||||
plane_t vertex_plane;
|
||||
|
||||
if (bg_make_plane_3pnts(vertex_plane, vertices[i], vertices[j], vertices[k], tol) < 0)
|
||||
if (have_volume)
|
||||
continue;
|
||||
for (size_t l = 0; l < vertex_count; l++) {
|
||||
if (l == i || l == j || l == k)
|
||||
continue;
|
||||
if (!NEAR_ZERO(DIST_PNT_PLANE(vertices[l], vertex_plane), tol->dist))
|
||||
return 1;
|
||||
if (!basis_count) {
|
||||
VMOVE(basis[0], candidate);
|
||||
basis_count = 1;
|
||||
} else if (basis_count == 1 &&
|
||||
DIST_PNT_PNT_SQ(basis[0], candidate) > tol->dist_sq) {
|
||||
VMOVE(basis[1], candidate);
|
||||
basis_count = 2;
|
||||
} else if (basis_count == 2 &&
|
||||
bg_make_plane_3pnts(basis_plane, basis[0], basis[1],
|
||||
candidate, tol) == 0) {
|
||||
VMOVE(basis[2], candidate);
|
||||
basis_count = 3;
|
||||
} else if (basis_count == 3 &&
|
||||
!NEAR_ZERO(DIST_PNT_PLANE(candidate, basis_plane),
|
||||
tol->dist)) {
|
||||
have_volume = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
int all_planes_used = 1;
|
||||
for (size_t face = 0; face < plane_count; face++) {
|
||||
if (!plane_used[face]) {
|
||||
all_planes_used = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bu_free(plane_used, "inside plane use flags");
|
||||
return all_planes_used && have_volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +238,7 @@ arb7in(struct ged *gedp,
|
||||
planes[i][W] -= thick[i];
|
||||
}
|
||||
|
||||
if (!arb_in_planes_valid(planes, tol)) {
|
||||
if (!in_planes_valid((const plane_t *)planes, ARB_FACE_COUNT, tol)) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside arb7: thicknesses eliminate a face or collapse the volume\n");
|
||||
return BRLCAD_ERROR;
|
||||
@@ -250,6 +261,43 @@ arb7in(struct ged *gedp,
|
||||
}
|
||||
|
||||
|
||||
/* Offset each outward-facing ARBN plane toward the interior. */
|
||||
static int
|
||||
arbnin(struct ged *gedp, struct rt_db_internal *ip, const fastf_t *thick,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
struct rt_arbn_internal *arbn =
|
||||
(struct rt_arbn_internal *)ip->idb_ptr;
|
||||
RT_ARBN_CK_MAGIC(arbn);
|
||||
|
||||
plane_t *planes = (plane_t *)bu_calloc(arbn->neqn, sizeof(plane_t),
|
||||
"inside ARBN planes");
|
||||
for (size_t i = 0; i < arbn->neqn; i++) {
|
||||
fastf_t normal_length = MAGNITUDE(arbn->eqn[i]);
|
||||
if (!isfinite(normal_length) || normal_length <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside ARBN: plane %zu has an invalid normal\n",
|
||||
i);
|
||||
bu_free(planes, "inside ARBN planes");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
HSCALE(planes[i], arbn->eqn[i], 1.0 / normal_length);
|
||||
planes[i][W] -= thick[i];
|
||||
}
|
||||
|
||||
if (!in_planes_valid((const plane_t *)planes, arbn->neqn, tol)) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside ARBN: thicknesses eliminate a face or collapse the volume\n");
|
||||
bu_free(planes, "inside ARBN planes");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
bu_free(arbn->eqn, "arbn planes");
|
||||
arbn->eqn = planes;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
/* finds inside arbs */
|
||||
static int
|
||||
arbin(struct ged *gedp,
|
||||
@@ -925,12 +973,22 @@ ged_inside_internal(struct ged *gedp, struct rt_db_internal *ip, int argc, const
|
||||
if (ip->idb_type == ID_ARB8) {
|
||||
/* find the comgeom arb type, & reorganize */
|
||||
int uvec[8], svec[11];
|
||||
int issues = 0;
|
||||
struct bu_vls error_msg = BU_VLS_INIT_ZERO;
|
||||
|
||||
if (rt_arb_get_cgtype(&cgtype, (struct rt_arb_internal *)ip->idb_ptr, &wdbp->wdb_tol, uvec, svec) == 0) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s: BAD ARB\n", o_name);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
(void)rt_arb_validate(NULL,
|
||||
(const struct rt_arb_internal *)ip->idb_ptr,
|
||||
&wdbp->wdb_tol, &issues);
|
||||
if (issues & RT_ARB_VALIDATE_CONCAVE) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"%s: inside requires a convex ARB; concave ARB8 solids are unsupported\n",
|
||||
o_name);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
/* must find new plane equations to account for
|
||||
* any editing in the es_mat matrix or path to this solid.
|
||||
@@ -1008,6 +1066,30 @@ ged_inside_internal(struct ged *gedp, struct rt_db_internal *ip, int argc, const
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_ARBN: {
|
||||
struct rt_arbn_internal *arbn =
|
||||
(struct rt_arbn_internal *)ip->idb_ptr;
|
||||
RT_ARBN_CK_MAGIC(arbn);
|
||||
|
||||
size_t supplied = argc > arg ? (size_t)(argc - arg) : 0;
|
||||
if (supplied < arbn->neqn) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Enter thickness for plane P%zu: ", supplied);
|
||||
return GED_MORE;
|
||||
}
|
||||
|
||||
fastf_t *arbn_thick = (fastf_t *)bu_calloc(arbn->neqn,
|
||||
sizeof(fastf_t), "inside ARBN thicknesses");
|
||||
for (i = 0; i < arbn->neqn; i++)
|
||||
arbn_thick[i] = atof(argv[arg++]) * gedp->dbip->dbi_local2base;
|
||||
|
||||
int inside_result = arbnin(gedp, ip, arbn_thick, &wdbp->wdb_tol);
|
||||
bu_free(arbn_thick, "inside ARBN thicknesses");
|
||||
if (inside_result != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_TGC:
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (argc < arg+1) {
|
||||
|
||||
@@ -1926,6 +1926,19 @@ densities_prep(struct ged *gedp, struct rt_i *rtip)
|
||||
}
|
||||
FOR_ALL_DIRECTORY_END;
|
||||
}
|
||||
|
||||
// validation loop - all regions with a material ID should be in the density table
|
||||
struct region *regp = REGION_NULL;
|
||||
for (BU_LIST_FOR(regp, region, &(rtip->HeadRegion))) {
|
||||
const long int material_id = regp->reg_gmater;
|
||||
if (analyze_densities_density(_gd_densities, material_id) >= 0.0)
|
||||
continue;
|
||||
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Error: Density %ld on region %s is not defined in the density table.\n", material_id, regp->reg_name);
|
||||
analyze_densities_clear(_gd_densities);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BRLCAD_OK;
|
||||
|
||||
+17
-4
@@ -341,7 +341,7 @@ cache_init(struct rt_cache *cache)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static int
|
||||
compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
{
|
||||
int ret;
|
||||
@@ -352,8 +352,16 @@ compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
|
||||
BU_CK_EXTERNAL(external);
|
||||
|
||||
BU_ASSERT(external->ext_nbytes < INT_MAX);
|
||||
if (external->ext_nbytes >= INT_MAX) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression input is too large (%zu bytes)\n", bu_pid(), bu_parallel_id(), external->ext_nbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
compressed_size = brl_LZ4_compressBound((int)external->ext_nbytes);
|
||||
if (compressed_size <= 0) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression input is unsupported (%zu bytes)\n", bu_pid(), bu_parallel_id(), external->ext_nbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* buffer is uncompsize + maxcompsize + compressed_data */
|
||||
buffer = (uint8_t *)bu_malloc((size_t)compressed_size + SIZEOF_NETWORK_LONG, "buffer");
|
||||
@@ -367,12 +375,14 @@ compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
|
||||
if (!compressed) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression failed (ret %d, %zu bytes @ %p to %d bytes max)\n", bu_pid(), bu_parallel_id(), ret, external->ext_nbytes, (void *) external->ext_buf, compressed_size);
|
||||
return;
|
||||
bu_free(buffer, "buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bu_free(external->ext_buf, "ext_buf");
|
||||
external->ext_nbytes = compressed_size + SIZEOF_NETWORK_LONG;
|
||||
external->ext_buf = buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -569,7 +579,10 @@ cache_try_store(struct rt_cache *cache, const char *name, const struct rt_db_int
|
||||
return 0; /* can't serialize */
|
||||
}
|
||||
|
||||
compress_external(cache, &data_external);
|
||||
if (!compress_external(cache, &data_external)) {
|
||||
bu_free_external(&data_external);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
struct bu_attribute_value_set attributes = BU_AVS_INIT_ZERO;
|
||||
|
||||
@@ -1914,8 +1914,19 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
int arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
|
||||
if (arb_type == 0)
|
||||
return BRLCAD_ERROR;
|
||||
if (rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "\nCannot calculate plane equations for ARB8\n");
|
||||
|
||||
int validation_issues = 0;
|
||||
(void)rt_arb_validate(NULL, arb, s->tol, &validation_issues);
|
||||
int planes_valid = !(validation_issues & RT_ARB_VALIDATE_NONCOPLANAR) &&
|
||||
!rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol);
|
||||
int planes_required = s->edit_flag == ECMD_ARB_MOVE_FACE ||
|
||||
s->edit_flag == ECMD_ARB_SETUP_ROTFACE ||
|
||||
s->edit_flag == ECMD_ARB_ROTATE_FACE ||
|
||||
s->edit_flag == PTARB || s->edit_flag == EARB;
|
||||
if (!planes_valid && planes_required) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"Cannot edit ARB faces or edges without valid face planes: %s",
|
||||
bu_vls_cstr(&error_msg));
|
||||
bu_vls_free(&error_msg);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
@@ -1937,11 +1948,11 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
break;
|
||||
case ECMD_ARB_MAIN_MENU:
|
||||
ecmd_arb_main_menu(s);
|
||||
break;
|
||||
return BRLCAD_OK;
|
||||
case ECMD_ARB_SPECIFIC_MENU:
|
||||
if (ecmd_arb_specific_menu(s) != BRLCAD_OK)
|
||||
return -1;
|
||||
break;
|
||||
return BRLCAD_OK;
|
||||
case ECMD_ARB_MOVE_FACE:
|
||||
return ecmd_arb_move_face(s);
|
||||
case ECMD_ARB_SETUP_ROTFACE:
|
||||
@@ -1980,6 +1991,11 @@ arb_planecalc:
|
||||
|
||||
if (ret != BRLCAD_OK)
|
||||
goto arb_failed;
|
||||
/* Rigid and uniform whole-solid transforms preserve an invalid ARB's
|
||||
* shape. They must remain usable even when face-specific editing cannot
|
||||
* construct a complete set of planes. */
|
||||
if (!planes_valid)
|
||||
return ret;
|
||||
if (edarb_canonicalize(s, arb) != BRLCAD_OK) {
|
||||
goto arb_failed;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ rt_edit_bot_labels(
|
||||
VADD3(mid_pt, p1, p2, p3);
|
||||
|
||||
VSCALE(mid_pt, mid_pt, one_third);
|
||||
POINT_LABEL_STR(mid_pt, "face");
|
||||
|
||||
*num_lines = 3;
|
||||
VMOVE(lines[0], mid_pt);
|
||||
@@ -1114,8 +1115,7 @@ ecmd_bot_pickt(struct rt_edit *s, const vect_t mousevec)
|
||||
b->bot_verts[1] = -1;
|
||||
b->bot_verts[2] = -1;
|
||||
bu_vls_free(&vls);
|
||||
}
|
||||
if (hits == 1) {
|
||||
} else if (hits == 1) {
|
||||
sscanf(bu_vls_cstr(&vls), " { { %d %d %d", &b->bot_verts[0], &b->bot_verts[1], &b->bot_verts[2]);
|
||||
bu_vls_free(&vls);
|
||||
} else {
|
||||
|
||||
@@ -270,10 +270,12 @@ rt_hlf_norm(register struct hit *hitp, struct soltab *stp, register struct xray
|
||||
/* We are expected to compute hit_point here. May be infinite. */
|
||||
f = hitp->hit_dist;
|
||||
if (f <= -INFINITY) {
|
||||
bu_log("rt_hlf_norm: hit_dist = -INFINITY, unable to compute pt.\n");
|
||||
if (RT_G_DEBUG & RT_DEBUG_ARB8)
|
||||
bu_log("rt_hlf_norm: hit_dist = -INFINITY, unable to compute pt.\n");
|
||||
VSETALL(hitp->hit_point, -INFINITY);
|
||||
} else if (f >= INFINITY) {
|
||||
bu_log("rt_hlf_norm: hit_dist = +INFINITY, unable to compute pt.\n");
|
||||
if (RT_G_DEBUG & RT_DEBUG_ARB8)
|
||||
bu_log("rt_hlf_norm: hit_dist = +INFINITY, unable to compute pt.\n");
|
||||
VSETALL(hitp->hit_point, INFINITY);
|
||||
} else {
|
||||
VJOIN1(hitp->hit_point, rp->r_pt, f, rp->r_dir);
|
||||
|
||||
@@ -1732,7 +1732,7 @@ rt_hyp_volume(fastf_t *volume, const struct rt_db_internal *ip)
|
||||
C_DECL int
|
||||
rt_hyp_labels(struct rt_point_labels *pl, int pl_max, const mat_t xform, const struct rt_db_internal *ip, const struct bn_tol *UNUSED(tol))
|
||||
{
|
||||
int lcnt = 4;
|
||||
int lcnt = 5;
|
||||
if (!pl || pl_max < lcnt || !ip)
|
||||
return 0;
|
||||
|
||||
@@ -1767,6 +1767,13 @@ rt_hyp_labels(struct rt_point_labels *pl, int pl_max, const mat_t xform, const s
|
||||
MAT4X3PNT(pos_view, xform, work);
|
||||
POINT_LABEL(pos_view, 'B');
|
||||
|
||||
/* hyp_bnr is the neck-to-base ratio. Show it at the neck's
|
||||
* semi-major-axis point, halfway along H. */
|
||||
VJOIN2(work, hyp->hyp_Vi, 0.5, hyp->hyp_Hi,
|
||||
hyp->hyp_bnr, hyp->hyp_A);
|
||||
MAT4X3PNT(pos_view, xform, work);
|
||||
POINT_LABEL(pos_view, 'c');
|
||||
|
||||
return lcnt;
|
||||
}
|
||||
|
||||
|
||||
@@ -343,6 +343,79 @@ test_arb_geometry_helpers(struct rt_edit *s, struct rt_arb_internal *arb,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nonplanar_arb8_reset(struct rt_edit *s, struct rt_arb_internal *arb,
|
||||
struct rt_arb8_edit *a, const struct bn_tol *tol)
|
||||
{
|
||||
arb8_reset(s, arb, a);
|
||||
arb->pt[6][Z] = 1.25;
|
||||
int issues = 0;
|
||||
(void)rt_arb_validate(NULL, arb, tol, &issues);
|
||||
if (!(issues & RT_ARB_VALIDATE_NONCOPLANAR))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 test fixture is planar\n");
|
||||
MAT_IDN(s->e_mat);
|
||||
MAT_IDN(s->e_invmat);
|
||||
MAT_IDN(s->model_changes);
|
||||
s->mv_context = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_nonplanar_whole_solid_edits(struct rt_edit *s,
|
||||
struct rt_arb_internal *arb, struct rt_arb8_edit *a,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_SCALE);
|
||||
s->es_scale = 2.0;
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid scale was rejected\n");
|
||||
}
|
||||
point_t scaled = {2.0, 2.0, 2.5};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], scaled, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid scale failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_TRANS);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 2.0, 3.0, 4.0);
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid translation was rejected\n");
|
||||
}
|
||||
point_t translated = {3.0, 4.0, 5.25};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], translated, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid translation failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_ROT);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 0.0, 0.0, 90.0);
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid rotation was rejected\n");
|
||||
}
|
||||
point_t rotated = {-1.0, 1.0, 1.25};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], rotated, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid rotation failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
struct rt_arb_internal before_face_move = *arb;
|
||||
a->edit_menu = 0;
|
||||
rt_edit_set_edflag(s, ECMD_ARB_MOVE_FACE);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 0.0, 0.0, 0.25);
|
||||
bu_vls_trunc(s->log_str, 0);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
memcmp(arb->pt, before_face_move.pt, sizeof(arb->pt)) ||
|
||||
!strstr(bu_vls_cstr(s->log_str), "valid face planes"))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 face edit was not rejected cleanly\n");
|
||||
|
||||
bu_log("Nonplanar ARB8 whole-solid edits SUCCESS\n");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rt_edit_test_arb8(void)
|
||||
{
|
||||
@@ -953,6 +1026,7 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
bu_log("ECMD_ARB_ROTATE_FACE knob edit SUCCESS\n");
|
||||
|
||||
test_arb_geometry_helpers(s, arb, a, &tol);
|
||||
test_nonplanar_whole_solid_edits(s, arb, a, &tol);
|
||||
|
||||
/* The public editing entry point must reject invalid type and menu indexes
|
||||
* before using them to address the type-specific editing tables. */
|
||||
|
||||
@@ -643,6 +643,32 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
be->bot_verts[0], be->bot_verts[1], be->bot_verts[2]);
|
||||
}
|
||||
|
||||
/* The selected face is labeled at its centroid and marked with one line
|
||||
* from the centroid to each vertex. */
|
||||
{
|
||||
struct rt_point_labels labels[3] = {RT_POINT_LABELS_INIT};
|
||||
point_t lines[2 * 4];
|
||||
mat_t identity;
|
||||
int num_lines = 0;
|
||||
MAT_IDN(identity);
|
||||
EDOBJ[ID_BOT].ft_labels(&num_lines, lines, labels, 3, identity, s, &tol);
|
||||
|
||||
point_t centroid = {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0};
|
||||
point_t vertices[3] = {{1.0, 0.0, 0.0},
|
||||
{0.0, 1.0, 0.0},
|
||||
{0.0, 0.0, 1.0}};
|
||||
if (num_lines != 3 || !BU_STR_EQUAL(labels[0].str, "face") ||
|
||||
!VNEAR_EQUAL(labels[0].pt, centroid, VUNITIZE_TOL) ||
|
||||
!BU_STR_EQUAL(labels[1].str, "pt"))
|
||||
bu_exit(1, "ERROR: selected BOT face label is missing or misplaced\n");
|
||||
for (int i = 0; i < num_lines; ++i) {
|
||||
if (!VNEAR_EQUAL(lines[i * 2], centroid, VUNITIZE_TOL) ||
|
||||
!VNEAR_EQUAL(lines[i * 2 + 1], vertices[i], VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: selected BOT face marker line %d is misplaced\n", i);
|
||||
}
|
||||
bu_log("ECMD_BOT_PICKT label SUCCESS: face centroid is marked\n");
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_BOT_MODE (descriptor path): set mode to RT_BOT_SOLID (2)
|
||||
* ================================================================*/
|
||||
|
||||
@@ -178,6 +178,20 @@ rt_edit_test_hyp(void)
|
||||
|
||||
vect_t mousevec;
|
||||
|
||||
{
|
||||
struct rt_point_labels labels[5] = {RT_POINT_LABELS_INIT};
|
||||
mat_t identity;
|
||||
MAT_IDN(identity);
|
||||
int label_count = OBJ[ID_HYP].ft_labels(labels, 5, identity,
|
||||
&s->es_int, &tol);
|
||||
point_t expected_c = {2.0, 0.0, 5.0};
|
||||
if (label_count != 5 || !BU_STR_EQUAL(labels[4].str, "c") ||
|
||||
!VNEAR_EQUAL(labels[4].pt, expected_c, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: HYP neck ratio label is missing or misplaced\n");
|
||||
bu_log("HYP neck ratio label SUCCESS: c=%g,%g,%g\n",
|
||||
V3ARGS(labels[4].pt));
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_HYP_H (scale Hi; note: e_para[0] is es_scale, not |Hi|)
|
||||
* MGED: es_scale = e_para[0] (scale factor); Hi' = Hi * es_scale
|
||||
|
||||
+91
-7
@@ -340,6 +340,26 @@ f_attach(ClientData clientData, Tcl_Interp *interpreter, int argc, const char *a
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_TK
|
||||
static int
|
||||
mged_restore_display_env(Tcl_Interp *interp, Tcl_Obj *saved_display)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (saved_display != NULL) {
|
||||
status = (Tcl_SetVar2Ex(interp, "env", "DISPLAY", saved_display,
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) != NULL) ? TCL_OK : TCL_ERROR;
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = Tcl_UnsetVar2(interp, "env", "DISPLAY",
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
gui_setup(struct mged_state *s, const char *dstr)
|
||||
{
|
||||
@@ -348,6 +368,7 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
|
||||
#ifdef HAVE_TK
|
||||
Tk_GenericProc *handler = doEvent;
|
||||
Tcl_Obj *saved_display = NULL;
|
||||
#endif
|
||||
/* initialize only once */
|
||||
if (tkwin != NULL)
|
||||
@@ -355,24 +376,83 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
|
||||
Tcl_ResetResult(s->interp);
|
||||
|
||||
/* set DISPLAY to dstr */
|
||||
if (dstr != (char *)NULL) {
|
||||
Tcl_SetVar(s->interp, "env(DISPLAY)", dstr, TCL_GLOBAL_ONLY);
|
||||
#ifdef HAVE_TK
|
||||
/* Tk has no display-name argument in its C initialization API. For an
|
||||
* explicit MGED -d/loadtk argument, env(DISPLAY) is therefore the only
|
||||
* portable way to select an X11 display before Tk_Init. Do not do this
|
||||
* for ambient process state: X11 Tk already reads DISPLAY itself, and
|
||||
* native Win32/Aqua Tk deliberately ignores that X11-only variable. */
|
||||
if (dstr != NULL) {
|
||||
saved_display = Tcl_GetVar2Ex(s->interp, "env", "DISPLAY",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (saved_display != NULL)
|
||||
Tcl_IncrRefCount(saved_display);
|
||||
if (Tcl_SetVar2(s->interp, "env", "DISPLAY", dstr,
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
if (saved_display != NULL)
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TK
|
||||
/* This runs the tk.tcl script */
|
||||
if (Tk_Init(s->interp) == TCL_ERROR) {
|
||||
const char *result = Tcl_GetStringResult(s->interp);
|
||||
/* hack to avoid a stupid Tk error */
|
||||
if (bu_strncmp(result, "this isn't a Tk applicationcouldn't", 35) == 0) {
|
||||
result = (result + 27);
|
||||
Tcl_ResetResult(s->interp);
|
||||
Tcl_AppendResult(s->interp, result, (char *)NULL);
|
||||
Tcl_SetObjResult(s->interp, Tcl_NewStringObj(result + 27, -1));
|
||||
}
|
||||
if (dstr != NULL) {
|
||||
Tcl_SavedResult init_result;
|
||||
|
||||
/* Environment restoration is cleanup on this path; retain Tk's
|
||||
* diagnostic even if an unusual Tcl environment trace rejects it. */
|
||||
Tcl_SaveResult(s->interp, &init_result);
|
||||
(void)mged_restore_display_env(s->interp, saved_display);
|
||||
Tcl_RestoreResult(s->interp, &init_result);
|
||||
}
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (dstr != NULL) {
|
||||
int is_x11;
|
||||
|
||||
if (Tcl_Eval(s->interp, "tk windowingsystem") != TCL_OK) {
|
||||
Tcl_SavedResult windowing_result;
|
||||
|
||||
Tcl_SaveResult(s->interp, &windowing_result);
|
||||
(void)mged_restore_display_env(s->interp, saved_display);
|
||||
Tcl_RestoreResult(s->interp, &windowing_result);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
is_x11 = BU_STR_EQUAL(Tcl_GetStringResult(s->interp), "x11");
|
||||
Tcl_ResetResult(s->interp);
|
||||
|
||||
if (is_x11) {
|
||||
/* X11 may use the explicit display for subsequently created
|
||||
* toplevels and display managers, so keep it in the environment. */
|
||||
if (saved_display != NULL)
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
} else {
|
||||
Tk_Window display_probe;
|
||||
|
||||
/* Win32 and Aqua cannot be redirected by DISPLAY. Restore the
|
||||
* caller's environment, then let Tk validate whether the explicit
|
||||
* name denotes the already initialized native screen. This accepts
|
||||
* native aliases such as :0/:0.0 but reports unsupported alternate
|
||||
* displays instead of silently opening a different screen. */
|
||||
if (mged_restore_display_env(s->interp, saved_display) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
|
||||
display_probe = Tk_CreateWindowFromPath(s->interp,
|
||||
Tk_MainWindow(s->interp), ".__mged_display_probe", dstr);
|
||||
if (display_probe == NULL)
|
||||
return TCL_ERROR;
|
||||
Tk_DestroyWindow(display_probe);
|
||||
Tcl_ResetResult(s->interp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize [incr Tk] */
|
||||
if (Tcl_Eval(s->interp, "package require Itk") != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
@@ -385,6 +465,10 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TK
|
||||
(void)dstr;
|
||||
#endif
|
||||
|
||||
/* Initialize the Iwidgets package */
|
||||
if (Tcl_Eval(s->interp, "package require Iwidgets") != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
|
||||
+22
-55
@@ -424,11 +424,12 @@ ecmd_bot_pickt_multihit_clbk(int UNUSED(ac), const char **UNUSED(av), void *d, v
|
||||
struct rt_bot_edit *b = (struct rt_bot_edit *)se->ipe_ptr;
|
||||
struct bu_vls *vls = (struct bu_vls *)se->u_ptr;
|
||||
|
||||
// Evil Tcl variable linkage. Will need to figure out how to do this
|
||||
// "on the fly" with temporary s_edit structure internal variables...
|
||||
Tcl_LinkVar(s->interp, "bot_v1", (char *)&b->bot_verts[0], TCL_LINK_INT);
|
||||
Tcl_LinkVar(s->interp, "bot_v2", (char *)&b->bot_verts[1], TCL_LINK_INT);
|
||||
Tcl_LinkVar(s->interp, "bot_v3", (char *)&b->bot_verts[2], TCL_LINK_INT);
|
||||
/* The chooser is nonmodal, so it cannot safely retain links to this edit
|
||||
* state. Clear the old selection while the user chooses a new face; the
|
||||
* Tcl callback applies the chosen indices through the normal edit path. */
|
||||
b->bot_verts[0] = -1;
|
||||
b->bot_verts[1] = -1;
|
||||
b->bot_verts[2] = -1;
|
||||
|
||||
int ret_tcl = Tcl_VarEval(s->interp, "bot_face_select ", bu_vls_cstr(vls), (char *)NULL);
|
||||
int ret = BRLCAD_OK;
|
||||
@@ -439,9 +440,6 @@ ecmd_bot_pickt_multihit_clbk(int UNUSED(ac), const char **UNUSED(av), void *d, v
|
||||
b->bot_verts[2] = -1;
|
||||
ret = BRLCAD_ERROR;
|
||||
}
|
||||
Tcl_UnlinkVar(s->interp, "bot_v1");
|
||||
Tcl_UnlinkVar(s->interp, "bot_v2");
|
||||
Tcl_UnlinkVar(s->interp, "bot_v3");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -735,6 +733,7 @@ sedit_mouse(struct mged_state *s, const vect_t mousevec)
|
||||
if (bu_vls_strlen(MEDIT(s)->log_str)) {
|
||||
Tcl_AppendResult(s->interp, bu_vls_cstr(MEDIT(s)->log_str), (char *)NULL);
|
||||
bu_vls_trunc(MEDIT(s)->log_str, 0);
|
||||
mged_print_result(0, NULL, s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1711,57 +1710,25 @@ f_sedit_reset(ClientData clientData, Tcl_Interp *interp, int argc, const char *U
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* free old copy */
|
||||
rt_db_free_internal(&MEDIT(s)->es_int);
|
||||
|
||||
/* reset internal variables */
|
||||
if (EDOBJ[MEDIT(s)->es_int.idb_type].ft_prim_edit_reset)
|
||||
(*EDOBJ[MEDIT(s)->es_int.idb_type].ft_prim_edit_reset)(MEDIT(s));
|
||||
|
||||
/* read in a fresh copy */
|
||||
if (!illump || !illump->s_u_data)
|
||||
if (!illump->s_u_data)
|
||||
return TCL_ERROR;
|
||||
|
||||
struct ged_bv_data *bdata = (struct ged_bv_data *)illump->s_u_data;
|
||||
if (rt_db_get_internal(&MEDIT(s)->es_int, LAST_SOLID(bdata),
|
||||
s->dbip, NULL) < 0) {
|
||||
if (bdata->s_fullpath.fp_len > 0) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(",
|
||||
LAST_SOLID(bdata)->d_namep,
|
||||
"): solid import failure\n", (char *)NULL);
|
||||
} else {
|
||||
Tcl_AppendResult(interp, "sedit_reset(NULL): solid import failure\n", (char *)NULL);
|
||||
|
||||
}
|
||||
return TCL_ERROR; /* FAIL */
|
||||
if (!bdata->s_fullpath.fp_len) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(NULL): solid import failure\n", (char *)NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
RT_CK_DB_INTERNAL(&MEDIT(s)->es_int);
|
||||
|
||||
struct directory *dp = LAST_SOLID(bdata);
|
||||
if (reinit_edit_state(s, bdata) != BRLCAD_OK) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(",
|
||||
dp->d_namep,
|
||||
"): solid import failure\n", (char *)NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
init_sedit_vars(s);
|
||||
replot_editing_solid(0, NULL, s, NULL);
|
||||
|
||||
/* Establish initial keypoint */
|
||||
MEDIT(s)->e_keytag = "";
|
||||
rt_get_solid_keypoint(MEDIT(s), &MEDIT(s)->e_keypoint, &MEDIT(s)->e_keytag, MEDIT(s)->e_mat);
|
||||
|
||||
/* Reset relevant variables */
|
||||
MAT_IDN(MEDIT(s)->acc_rot_sol);
|
||||
VSETALL(MEDIT(s)->k.rot_m_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_m_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v_abs_last, 0.0);
|
||||
MEDIT(s)->k.sca_abs = 0.0;
|
||||
MEDIT(s)->acc_sc_sol = 1.0;
|
||||
VSETALL(MEDIT(s)->k.rot_m, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v, 0.0);
|
||||
|
||||
set_e_axes_pos(s, 1);
|
||||
s->update_views = 1;
|
||||
dm_set_dirty(DMP, 1);
|
||||
|
||||
|
||||
+30
-16
@@ -2446,6 +2446,29 @@ apply_cli_overrides(struct mged_state *s, struct mged_cli_overrides *cl)
|
||||
if (cli_dbl_is_set(cl->eye_sep_dist)) CLI_SETVAR_DBL("eye_sep_dist", cl->eye_sep_dist);
|
||||
|
||||
/* --- Tcl mged_default array entries ---------------------------------- */
|
||||
if (cl->dpy_string) {
|
||||
const char *display = cl->dpy_string;
|
||||
#ifdef HAVE_TK
|
||||
struct bu_vls tk_screen = BU_VLS_INIT_ZERO;
|
||||
Tk_Window main_window = Tk_MainWindow(s->interp);
|
||||
|
||||
/* Apply -d after .mgedrc just like the other command-line overrides.
|
||||
* Once Tk is initialized, store its canonical screen name rather than
|
||||
* the spelling used to select it (for example, :0 and :0.0 may denote
|
||||
* the same native screen). Classic/headless mode retains the original
|
||||
* value for a later display-manager attach. */
|
||||
if (main_window != NULL) {
|
||||
bu_vls_printf(&tk_screen, "%s.%d", Tk_DisplayName(main_window),
|
||||
Tk_ScreenNumber(main_window));
|
||||
display = bu_vls_cstr(&tk_screen);
|
||||
}
|
||||
#endif
|
||||
Tcl_SetVar2(s->interp, "mged_default", "display", display,
|
||||
TCL_GLOBAL_ONLY);
|
||||
#ifdef HAVE_TK
|
||||
bu_vls_free(&tk_screen);
|
||||
#endif
|
||||
}
|
||||
if (cl->dm_type)
|
||||
Tcl_SetVar2(s->interp, "mged_default", "dm_type", cl->dm_type, TCL_GLOBAL_ONLY);
|
||||
if (cl->geom)
|
||||
@@ -2694,7 +2717,7 @@ main(int argc, char *argv[])
|
||||
struct bu_opt_desc opt_defs[54];
|
||||
/* ---- Existing short options, now with long aliases ---- */
|
||||
BU_OPT(opt_defs[0], "a", "attach", "type", bu_opt_str, &cl.attach, "display manager attach target");
|
||||
BU_OPT(opt_defs[1], "d", "display", "string", bu_opt_str, &cl.dpy_string, "X display string");
|
||||
BU_OPT(opt_defs[1], "d", "display", "screen", bu_opt_str, &cl.dpy_string, "Tk display and screen name");
|
||||
BU_OPT(opt_defs[2], "r", "read-only", "", NULL, &cl.read_only, "open database read-only");
|
||||
BU_OPT(opt_defs[3], "p", "pipe", "", NULL, &cl.pipe_mode, "pipe mode (emit CMD_DONE sentinels)");
|
||||
BU_OPT(opt_defs[4], "c", "classic", "", NULL, &cl.classic_mode, "classic text-only mode");
|
||||
@@ -3044,9 +3067,6 @@ main(int argc, char *argv[])
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(&s->input_str));
|
||||
bu_vls_trunc(&s->input_str, 0);
|
||||
|
||||
if (!s->dpy_string)
|
||||
s->dpy_string = getenv("DISPLAY");
|
||||
|
||||
/* show ourselves */
|
||||
if (s->interactive) {
|
||||
if (s->classic_mged) {
|
||||
@@ -3068,23 +3088,17 @@ main(int argc, char *argv[])
|
||||
/* start up the gui */
|
||||
|
||||
int status;
|
||||
struct bu_vls vls = BU_VLS_INIT_ZERO;
|
||||
struct bu_vls error = BU_VLS_INIT_ZERO;
|
||||
|
||||
(void)Tcl_Eval(s->interp, "set mged_console_mode gui");
|
||||
|
||||
bu_vls_strcpy(&vls, "loadtk");
|
||||
if (s->dpy_string)
|
||||
bu_vls_printf(&vls, " %s", s->dpy_string);
|
||||
|
||||
status = Tcl_Eval(s->interp, bu_vls_addr(&vls));
|
||||
/* An unset -d is deliberately passed as NULL. Tk already knows how
|
||||
* to select its platform display: X11 consults DISPLAY, while the
|
||||
* Win32 and Aqua backends select their native display. Treating an
|
||||
* inherited DISPLAY value as an explicit request breaks native Tk
|
||||
* when Unix-like shells export an X11 placeholder. */
|
||||
status = gui_setup(s, s->dpy_string);
|
||||
bu_vls_strcpy(&error, Tcl_GetStringResult(s->interp));
|
||||
bu_vls_free(&vls);
|
||||
|
||||
if (status != TCL_OK && !s->dpy_string) {
|
||||
/* failed to load tk, try localhost X11 if DISPLAY was not set */
|
||||
status = Tcl_Eval(s->interp, "loadtk :0");
|
||||
}
|
||||
|
||||
if (status != TCL_OK) {
|
||||
if (!run_in_foreground && use_pipe) {
|
||||
|
||||
@@ -146,7 +146,6 @@ set(
|
||||
helpcomm.tcl
|
||||
helplib.tcl
|
||||
hoc.tcl
|
||||
html_library.tcl
|
||||
libtclcad.tcl
|
||||
man_browser.tcl
|
||||
menu_override.tcl
|
||||
|
||||
@@ -6,7 +6,6 @@ chkexterns.tcl utility to check for the existence of commands
|
||||
fs_dialog.tk file selection dialog widget
|
||||
helpcomm.tcl generic help routines
|
||||
helplib.tcl library help routines
|
||||
html_library.tcl HTML display library by Stephen Uhler
|
||||
libdm.tcl libdm initialization routines
|
||||
mged directory of mged specific tcl scripts
|
||||
pl-dm directory of pl-dm specific tcl scripts
|
||||
|
||||
@@ -1090,9 +1090,9 @@ namespace delete ::ArcherCoreBootstrap
|
||||
wm withdraw [namespace tail $this]
|
||||
}
|
||||
|
||||
if {![info exists env(DISPLAY)]} {
|
||||
set env(DISPLAY) ":0"
|
||||
}
|
||||
# Tk has already selected its X11, Win32, or Aqua display. DISPLAY is an
|
||||
# X11 input to that initialization, not portable application state; in
|
||||
# particular, synthesizing :0 here can misdirect native Tk child windows.
|
||||
|
||||
set mImgDir [file join [bu_dir data] tclscripts archer images]
|
||||
|
||||
|
||||
@@ -1,663 +0,0 @@
|
||||
# Simple HTML display library by Stephen Uhler (stephen.uhler@sun.com)
|
||||
# Copyright (c) 1995 by Sun Microsystems
|
||||
# Version 0.1 Thu Jul 20 09:06:28 PDT 1995
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
# To use this package, create a text widget (say, .text)
|
||||
# and set a variable full of html, (say $html), and issue:
|
||||
# HMinit_win .text
|
||||
# HMparse_html $html "HMrender .text"
|
||||
# You also need to supply the routine:
|
||||
# proc HMlink_callback {win href} { ...}
|
||||
# win: The name of the text widget
|
||||
# href The name of the link
|
||||
# which will be called anytime the user "clicks" on a link.
|
||||
# The supplied version just prints the link to stdout.
|
||||
# In addition, if you wish to use embedded images, you will need to write
|
||||
# proc HMset_image {handle src}
|
||||
# handle an arbitrary handle (not really)
|
||||
# src The name of the image
|
||||
# Which calls
|
||||
# HMgot_image $handle $image
|
||||
# with the TK image.
|
||||
#
|
||||
# To return a "used" text widget to its initialized state, call:
|
||||
# HMreset_win .text
|
||||
# See "sample.tcl" for sample usage
|
||||
##################################################################
|
||||
############################################
|
||||
# mapping of html tags to text tag properties
|
||||
# properties beginning with "T" map directly to text tags
|
||||
|
||||
# These are Defined in HTML 2.0
|
||||
|
||||
array set HMtag_map {
|
||||
a {Tlink link}
|
||||
b {weight bold}
|
||||
blockquote {style i indent 1 Trindent rindent}
|
||||
bq {style i indent 1 Trindent rindent}
|
||||
cite {style i}
|
||||
code {family courier}
|
||||
dfn {style i}
|
||||
dir {indent 1}
|
||||
dl {indent 1}
|
||||
em {style i}
|
||||
h1 {size 24 weight bold}
|
||||
h2 {size 22}
|
||||
h3 {size 20}
|
||||
h4 {size 18}
|
||||
h5 {size 16}
|
||||
h6 {style i}
|
||||
i {style i}
|
||||
kbd {family courier weight bold}
|
||||
menu {indent 1}
|
||||
ol {indent 1}
|
||||
pre {fill 0 family courier Tnowrap nowrap}
|
||||
samp {family courier}
|
||||
strong {weight bold}
|
||||
tt {family courier}
|
||||
u {Tunderline underline}
|
||||
ul {indent 1}
|
||||
var {style i}
|
||||
}
|
||||
|
||||
# These are in common(?) use, but not defined in html2.0
|
||||
|
||||
array set HMtag_map {
|
||||
center {Tcenter center}
|
||||
strike {Tstrike strike}
|
||||
u {Tunderline underline}
|
||||
}
|
||||
|
||||
# initial values
|
||||
|
||||
set HMtag_map(hmstart) {
|
||||
family times weight medium style r size 14
|
||||
Tcenter "" Tlink "" Tnowrap "" Tunderline "" list list
|
||||
fill 1 indent "" counter 0 adjust 0
|
||||
}
|
||||
|
||||
# html tags that insert white space
|
||||
|
||||
array set HMinsert_map {
|
||||
blockquote "\n\n" /blockquote "\n"
|
||||
br "\n"
|
||||
dd "\n" /dd "\n"
|
||||
dl "\n" /dl "\n"
|
||||
dt "\n"
|
||||
form "\n" /form "\n"
|
||||
h1 "\n\n" /h1 "\n"
|
||||
h2 "\n\n" /h2 "\n"
|
||||
h3 "\n\n" /h3 "\n"
|
||||
h4 "\n" /h4 "\n"
|
||||
h5 "\n" /h5 "\n"
|
||||
h6 "\n" /h6 "\n"
|
||||
li "\n"
|
||||
/dir "\n"
|
||||
/ul "\n"
|
||||
/ol "\n"
|
||||
/menu "\n"
|
||||
p "\n\n"
|
||||
pre "\n" /pre "\n"
|
||||
}
|
||||
|
||||
# tags that are list elements, that support "compact" rendering
|
||||
|
||||
array set HMlist_elements {
|
||||
ol 1 ul 1 menu 1 dl 1 dir 1
|
||||
}
|
||||
############################################
|
||||
# initialize the window and stack state
|
||||
|
||||
proc HMinit_win {win} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
HMinit_state $win
|
||||
$win tag configure underline -underline 1
|
||||
$win tag configure center -justify center
|
||||
$win tag configure nowrap -wrap none
|
||||
$win tag configure rindent -rmargin $var(S_tab)c
|
||||
$win tag configure strike -overstrike 1
|
||||
$win tag configure mark -foreground red ;# list markers
|
||||
$win tag configure list -spacing1 3p -spacing3 3p ;# regular lists
|
||||
$win tag configure compact -spacing1 0p ;# compact lists
|
||||
$win tag configure link -foreground blue ;# hypertext links
|
||||
HMset_indent $win $var(S_tab)
|
||||
$win configure -wrap word
|
||||
|
||||
# for horizontal rules
|
||||
$win tag configure thin -font [HMx_font Times 14 Medium R]
|
||||
$win tag configure hr -relief sunken -borderwidth 2 -wrap none \
|
||||
-tabs [winfo width $win]
|
||||
bind $win <Configure> {%W tag configure hr -tabs %w}
|
||||
|
||||
# generic link enter callback
|
||||
|
||||
$win tag bind link <1> "HMlink_hit $win %x %y"
|
||||
}
|
||||
|
||||
# set the indent spacing (in cm) for lists
|
||||
# TK uses a "weird" tabbing model that causes \t to insert a single
|
||||
# space if the current line position is past the tab setting
|
||||
|
||||
proc HMset_indent {win cm} {
|
||||
set tabs [expr $cm / 2.0]
|
||||
$win configure -tabs ${tabs}c
|
||||
foreach i {1 2 3 4 5 6 7 8 9} {
|
||||
set tab [expr $i * $cm]
|
||||
$win tag configure indent$i -lmargin1 ${tab}c -lmargin2 ${tab}c \
|
||||
-tabs "[expr $tab + $tabs]c [expr $tab + 2*$tabs]c"
|
||||
}
|
||||
}
|
||||
|
||||
# reset the state of window - get ready for the next page
|
||||
# remove all but the font tags
|
||||
|
||||
proc HMreset_win {win} {
|
||||
regsub -all { +[^L ][^ ]*} " [$win tag names] " {} tags
|
||||
catch "$win tag delete $tags"
|
||||
eval $win mark unset [$win mark names]
|
||||
$win delete 0.0 end
|
||||
$win tag configure hr -tabs [winfo width $win]
|
||||
HMinit_state $win
|
||||
}
|
||||
|
||||
# initialize the window's state array
|
||||
# Parameters beginning with S_ are NOT reset
|
||||
# adjust_size: global font size adjuster
|
||||
# unknown: character to use for unknown entities
|
||||
# tab: tab stop (in cm)
|
||||
# stop: enabled to stop processing
|
||||
# update: how many tags between update calls
|
||||
# tags: number of tags processed so far
|
||||
# symbols: Symbols to use on un-ordered lists
|
||||
|
||||
proc HMinit_state {win} {
|
||||
upvar #0 HM$win var
|
||||
array set tmp [array get var S_*]
|
||||
catch {unset var}
|
||||
array set var {
|
||||
stop 0
|
||||
tags 0
|
||||
fill 0
|
||||
list list
|
||||
S_adjust_size 0
|
||||
S_tab 1.0
|
||||
S_unknown \xb7
|
||||
S_update 10
|
||||
S_symbols O*=+-o\xd7\xb0>:\xb7
|
||||
}
|
||||
array set var [array get tmp]
|
||||
}
|
||||
|
||||
# alter the parameters of the text state
|
||||
# this allows an application to over-ride the default settings
|
||||
# it is called as: HMset_state -param value -param value ...
|
||||
|
||||
array set HMparam_map {
|
||||
-update S_update
|
||||
-tabs S_tab
|
||||
-unknown S_unknown
|
||||
-stop S_stop
|
||||
-size S_adjust_size
|
||||
-symbols S_symbols
|
||||
}
|
||||
|
||||
proc HMset_state {win args} {
|
||||
upvar #0 HM$win var
|
||||
global HMparam_map
|
||||
set bad 0
|
||||
if {[catch {array set params $args}]} {return 0}
|
||||
foreach i [array names params] {
|
||||
incr bad [catch {set var($HMparam_map($i)) $params($i)}]
|
||||
}
|
||||
return [expr $bad == 0]
|
||||
}
|
||||
|
||||
############################################
|
||||
# manage the display of html
|
||||
|
||||
# this gets called for every html tag
|
||||
# win: The name of the text widget to render into
|
||||
# tag: The html tag (in arbitrary case)
|
||||
# not: a "/" or the empty string
|
||||
# param: The un-interpreted parameter list
|
||||
# text: The plain text until the next html tag
|
||||
|
||||
proc HMrender {win tag not param text} {
|
||||
upvar #0 HM$win var
|
||||
if {$var(stop)} return
|
||||
global HMtag_map HMinsert_map HMlist_elements
|
||||
set tag [string tolower $tag]
|
||||
set text [HMmap_esc $text]
|
||||
|
||||
# manage compact rendering of lists
|
||||
if {[info exists HMlist_elements($tag)]} {
|
||||
set list "list [expr {[HMextract_param $param compact] ? "compact" : "list"}]"
|
||||
} else {
|
||||
set list ""
|
||||
}
|
||||
|
||||
# adjust tag state
|
||||
catch {HMstack $win $not "$HMtag_map($tag) $list"}
|
||||
|
||||
# insert white space (with current font)
|
||||
# adding white space can get a bit tricky. This isn't quite right
|
||||
set bad [catch {$win insert end $HMinsert_map($not$tag) "space $var(font)"}]
|
||||
if {!$bad && [llength $var(fill)]>0 && [lindex $var(fill) end]} {
|
||||
set text [string trimleft $text]
|
||||
}
|
||||
|
||||
# to fill or not to fill
|
||||
if {[llength $var(fill)]>0 && [lindex $var(fill) end]} {
|
||||
set text [HMzap_white $text]
|
||||
}
|
||||
|
||||
# do any special tag processing
|
||||
catch {HMtag_$not$tag $win $param text} msg
|
||||
|
||||
# debugging only (code will not be here if no debugging was set)
|
||||
|
||||
# add the text with proper tags
|
||||
set tags [HMcurrent_tags $win]
|
||||
$win insert end $text $tags
|
||||
|
||||
# We need to do an update every so often to insure interactive response.
|
||||
# This can cause us to re-enter the event loop, and cause recursive
|
||||
# invocations of HMrender, so we need to be careful.
|
||||
if {!([incr var(tags)] % $var(S_update))} {
|
||||
update
|
||||
}
|
||||
}
|
||||
|
||||
# html tags requiring special processing
|
||||
# Procs of the form HMtag_<tag> or HMtag_</tag> get called just before
|
||||
# the text for this tag is displayed.
|
||||
# win: The name of the text widget to render into
|
||||
# param: The un-interpreted parameter list
|
||||
# text: A pass-by-reference name of the plain text until the next html tag
|
||||
# Tag commands may change this to affect what text will be inserted
|
||||
# next.
|
||||
|
||||
proc HMtag_title {win param text} {
|
||||
upvar $text data
|
||||
wm title [winfo toplevel $win] $data
|
||||
set data ""
|
||||
}
|
||||
|
||||
proc HMtag_hr {win param text} {
|
||||
$win insert end "\n" space "\n" thin "\t" "thin hr" "\n" thin
|
||||
}
|
||||
|
||||
# list element tags
|
||||
|
||||
proc HMtag_ol {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set var(count$var(level)) 0
|
||||
}
|
||||
|
||||
proc HMtag_ul {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(count$var(level))}
|
||||
}
|
||||
|
||||
proc HMtag_menu {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set var(menu) ->
|
||||
set var(compact) 1
|
||||
}
|
||||
|
||||
proc HMtag_/menu {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(menu)}
|
||||
catch {unset var(compact)}
|
||||
}
|
||||
|
||||
proc HMtag_dt {win param text} {
|
||||
upvar #0 HM$win var
|
||||
upvar $text data
|
||||
set level $var(level)
|
||||
incr level -1
|
||||
$win insert end "$data" "hi [lindex $var(list) end] indent$level $var(font)"
|
||||
set data {}
|
||||
}
|
||||
|
||||
proc HMtag_li {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set level $var(level)
|
||||
incr level -1
|
||||
set x [string index $var(S_symbols)+-+-+-+-" $level]
|
||||
catch {set x [incr var(count$level)]}
|
||||
catch {set x $var(menu)}
|
||||
$win insert end \t$x\t "mark [lindex $var(list) end] indent$level $var(font)"
|
||||
}
|
||||
|
||||
# hypertext links.
|
||||
|
||||
proc HMtag_a {win param text} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
if {[HMextract_param $param href]} {
|
||||
set var(Tref) L:$href
|
||||
HMlink_setup $win $href
|
||||
}
|
||||
}
|
||||
|
||||
proc HMtag_/a {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(Tref)}
|
||||
}
|
||||
|
||||
# This interface is subject to change
|
||||
# Most of the work is getting around a limitation of TK that prevents
|
||||
# setting the size of a label to a widthxheight in pixels
|
||||
#
|
||||
# Images have the following parameters:
|
||||
# align: top,middle,bottom
|
||||
# alt: alternate text
|
||||
# ismap: A clickable image map
|
||||
# src: The URL link
|
||||
# Netscape supports
|
||||
# width: A width hint (in pixels)
|
||||
# height: A height hint (in pixels)
|
||||
# border: The size of the window border
|
||||
|
||||
proc HMtag_img {win param text} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
# get alignment
|
||||
array set align_map {top top middle center bottom bottom}
|
||||
set align bottom ;# The spec isn't clear what the default should be
|
||||
HMextract_param $param align
|
||||
catch {set align $align_map([string tolower $align])}
|
||||
|
||||
# get alternate text
|
||||
set alt "<image>"
|
||||
HMextract_param $param alt
|
||||
set alt [HMmap_esc $alt]
|
||||
|
||||
# get the border width
|
||||
set border 1
|
||||
HMextract_param $param border
|
||||
|
||||
# see if we have an image size hint
|
||||
# If so, make a frame the "hint" size to put the label in
|
||||
# otherwise just make the label
|
||||
set item $win.$var(tags)
|
||||
catch {destroy $item}
|
||||
if {[HMextract_param $param width] && [HMextract_param $param height]} {
|
||||
frame $item -width $width -height $height
|
||||
pack propagate $item 0
|
||||
set label $item.label
|
||||
label $label
|
||||
pack $label -expand 1 -fill both
|
||||
} else {
|
||||
set label $item
|
||||
label $label
|
||||
}
|
||||
|
||||
$label configure -relief ridge -fg orange -text $alt
|
||||
catch {$label configure -bd $border}
|
||||
$win window create end -align $align -window $item -pady 2
|
||||
|
||||
# add in all the current tags (this is overkill)
|
||||
set tags [HMcurrent_tags $win]
|
||||
foreach tag $tags {
|
||||
$win tag add $tag $item
|
||||
}
|
||||
|
||||
# set imagemap callbacks
|
||||
if {[HMextract_param $param ismap]} {
|
||||
set link ""
|
||||
regsub -all {[^L]*L:([^ ]*).*} $tags {\1} link
|
||||
global HMevents
|
||||
foreach i [array names HMevents] {
|
||||
bind $label <$i> "%W configure $HMevents($i)"
|
||||
}
|
||||
bind ismap <ButtonRelease-1> "HMlink_callback $win $link?%x,%y"
|
||||
bindtags $label "ismap [bindtags $label]"
|
||||
}
|
||||
|
||||
# now callback to the application
|
||||
set src ""
|
||||
HMextract_param $param src
|
||||
HMset_image $label $src
|
||||
}
|
||||
|
||||
# The app needs to supply one of these
|
||||
#proc HMset_image {handle src} {
|
||||
# puts "Found an image <$src> to put in $handle"
|
||||
# HMgot_image $handle "can't get\n$src"
|
||||
#}
|
||||
|
||||
# When the image is available, the application should call back here.
|
||||
# If we have the image, put it in the label, otherwise display the error
|
||||
# message. If we don't get a callback, the "alt" text remains.
|
||||
# if we have a clickable image, arrange for a callback
|
||||
|
||||
proc HMgot_image {win image_error} {
|
||||
# if we're in a frame turn on geometry propagation
|
||||
if {[winfo name $win] == "label"} {
|
||||
pack propagate [winfo parent $win] 1
|
||||
}
|
||||
if {[catch {$win configure -image $image_error}]} {
|
||||
$win configure -image {}
|
||||
$win configure -text $image_error
|
||||
}
|
||||
}
|
||||
|
||||
# Sample hypertext link callback routine - should be replaced by app
|
||||
# This proc is called once for each <A> tag.
|
||||
# Applications can overwrite this procedure, as required, or
|
||||
# replace the HMevents array
|
||||
# win: The name of the text widget to render into
|
||||
# href: The HREF link for this <a> tag.
|
||||
|
||||
array set HMevents {
|
||||
Enter {-borderwidth 2 -relief raised }
|
||||
Leave {-borderwidth 0 -relief flat }
|
||||
1 {-borderwidth 2 -relief sunken}
|
||||
ButtonRelease-1 {-relief raised}
|
||||
}
|
||||
|
||||
proc HMlink_setup {win href} {
|
||||
global HMevents
|
||||
foreach i [array names HMevents] {
|
||||
eval $win tag bind L:$href <$i> \
|
||||
\{$win tag configure L:$href $HMevents($i)\}
|
||||
}
|
||||
}
|
||||
|
||||
# generic link-hit callback
|
||||
# This gets called upon button hits on hypertext links
|
||||
# Applications are expected to supply their own HMlink_callback routine
|
||||
# win: The name of the text widget to render into
|
||||
# x,y: The cursor position at the "click"
|
||||
|
||||
proc HMlink_hit {win x y} {
|
||||
set tags [$win tag names @$x,$y]
|
||||
regsub -all {[^L]*L:([^ ]*).*} $tags {\1} link
|
||||
HMlink_callback $win $link
|
||||
}
|
||||
|
||||
# replace this!
|
||||
# win: The name of the text widget to render into
|
||||
# href: The HREF link for this <a> tag.
|
||||
|
||||
#proc HMlink_callback {win href} {
|
||||
# puts "Got hit on $win, link $href"
|
||||
#}
|
||||
|
||||
# extract a value from parameter list (this needs a re-do)
|
||||
# returns "1" if the keyword is found, "0" otherwise
|
||||
# param: A parameter list. It should already have been processed to
|
||||
# remove any entity references
|
||||
# key: The parameter name
|
||||
# val: The variable to put the value into (use key as default)
|
||||
|
||||
proc HMextract_param {param key {val ""}} {
|
||||
|
||||
if {$val == ""} {
|
||||
upvar $key result
|
||||
} else {
|
||||
upvar $val result
|
||||
}
|
||||
|
||||
# look for name=value combinations. Either (') or (") are valid delimiters
|
||||
if {
|
||||
[regsub -nocase [format {.*%s *= *"([^"]*).*} $key] $param {\1} value] ||
|
||||
[regsub -nocase [format {.*%s *= *'([^']*).*} $key] $param {\1} value] ||
|
||||
[regsub -nocase [format {.*%s *= *([^ ]+).*} $key] $param {\1} value] } {
|
||||
set result $value
|
||||
return 1
|
||||
}
|
||||
|
||||
# now look for valueless names
|
||||
# I should strip out name=value pairs, so we don't end up with "name"
|
||||
# inside the "value" part of some other key word - some day
|
||||
|
||||
set bad \[^a-zA-Z\]+
|
||||
if {[regexp -nocase "$bad$key$bad" -$param-]} {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
# These next two routines manage the display state of the page.
|
||||
|
||||
# push or pop tags to/from stack
|
||||
# the current tag is the last item on the list
|
||||
|
||||
proc HMstack {win push list} {
|
||||
upvar #0 HM$win var
|
||||
array set tags $list
|
||||
if {$push == ""} {
|
||||
foreach tag [array names tags] {
|
||||
lappend var($tag) $tags($tag)
|
||||
}
|
||||
} else {
|
||||
foreach tag [array names tags] {
|
||||
set cnt [regsub { *[^ ]+$} $var($tag) {} var($tag)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# extract set of current text tags
|
||||
# tags starting with T map directly to text tags
|
||||
|
||||
proc HMcurrent_tags {win} {
|
||||
upvar #0 HM$win var
|
||||
set font font
|
||||
foreach i {family size weight style} {
|
||||
set $i [lindex $var($i) end]
|
||||
append font :[set $i]
|
||||
}
|
||||
set xfont [HMx_font $family $size $weight $style $var(S_adjust_size)]
|
||||
catch {$win tag configure $font -font $xfont} msg
|
||||
set indent [llength $var(indent)]
|
||||
incr indent -1
|
||||
lappend tags $font indent$indent
|
||||
foreach tag [array names var T*] {
|
||||
append tags " [lindex $var($tag) end]"
|
||||
}
|
||||
set var(font) $font
|
||||
set var(level) $indent
|
||||
return $tags
|
||||
}
|
||||
|
||||
# generate an X font name
|
||||
proc HMx_font {family size weight style {adjust_size 0}} {
|
||||
catch {incr size $adjust_size}
|
||||
return "-*-$family-$weight-$style-normal--${size}-*-*-*-*-*-*-*"
|
||||
}
|
||||
############################################
|
||||
# Turn HTML into TCL commands
|
||||
# html A string containing an html document
|
||||
# cmd A command to run for each html tag found
|
||||
|
||||
proc HMparse_html {html {cmd HMtest_parse}} {
|
||||
regsub -all \{ $html {\&ob;} html
|
||||
regsub -all \} $html {\&cb;} html
|
||||
set w " \t\r\n" ;# white space
|
||||
proc HMcl x {return "\[$x\]"}
|
||||
set exp <(/?)([HMcl ^$w>]+)[HMcl $w]*([HMcl ^>]*)>
|
||||
set sub "\}\n$cmd {\\2} {\\1} {\\3} \{"
|
||||
regsub -all $exp $html $sub html
|
||||
eval "$cmd hmstart {} {} \{ $html \}"
|
||||
eval "$cmd hmstart / {} {}"
|
||||
}
|
||||
|
||||
proc HMtest_parse {command tag slash text_after_tag} {
|
||||
puts "==> $command $tag $slash $text_after_tag"
|
||||
}
|
||||
|
||||
# Convert multiple white space into a single space
|
||||
|
||||
proc HMzap_white {data} {
|
||||
regsub -all "\[ \t\r\n\]+" $data " " data
|
||||
return $data
|
||||
}
|
||||
|
||||
# find HTML escape characters of the form &xxx;
|
||||
|
||||
proc HMmap_esc {text} {
|
||||
if {![regexp & $text]} {return $text}
|
||||
regsub -all {([][$\\])} $text {\\\1} new
|
||||
regsub -all {&#([0-9][0-9][0-9]?);?} \
|
||||
$new {[format %c \1]} new
|
||||
regsub -all {&([^ ;]+);?} $new {[HMdo_map \1]} new
|
||||
return [subst $new]
|
||||
}
|
||||
|
||||
# convert an HTML escape sequence into character
|
||||
|
||||
proc HMdo_map {text {unknown ?}} {
|
||||
global HMesc_map
|
||||
set result $unknown
|
||||
catch {set result $HMesc_map($text)}
|
||||
return $result
|
||||
}
|
||||
|
||||
# table of escape characters (ISO latin-1 esc's are in a different table)
|
||||
|
||||
array set HMesc_map {
|
||||
lt < gt > amp & quot \" copy \xa9
|
||||
reg \xae ob \x7b cb \x7d nbsp \xa0
|
||||
}
|
||||
#############################################################
|
||||
# ISO Latin-1 escape codes
|
||||
|
||||
array set HMesc_map {
|
||||
nbsp \xa0 iexcl \xa1 cent \xa2 pound \xa3 curren \xa4
|
||||
yen \xa5 brvbar \xa6 sect \xa7 uml \xa8 copy \xa9
|
||||
ordf \xaa laquo \xab not \xac shy \xad reg \xae
|
||||
hibar \xaf deg \xb0 plusmn \xb1 sup2 \xb2 sup3 \xb3
|
||||
acute \xb4 micro \xb5 para \xb6 middot \xb7 cedil \xb8
|
||||
sup1 \xb9 ordm \xba raquo \xbb frac14 \xbc frac12 \xbd
|
||||
frac34 \xbe iquest \xbf Agrave \xc0 Aacute \xc1 Acirc \xc2
|
||||
Atilde \xc3 Auml \xc4 Aring \xc5 AElig \xc6 Ccedil \xc7
|
||||
Egrave \xc8 Eacute \xc9 Ecirc \xca Euml \xcb Igrave \xcc
|
||||
Iacute \xcd Icirc \xce Iuml \xcf ETH \xd0 Ntilde \xd1
|
||||
Ograve \xd2 Oacute \xd3 Ocirc \xd4 Otilde \xd5 Ouml \xd6
|
||||
times \xd7 Oslash \xd8 Ugrave \xd9 Uacute \xda Ucirc \xdb
|
||||
Uuml \xdc Yacute \xdd THORN \xde szlig \xdf agrave \xe0
|
||||
aacute \xe1 acirc \xe2 atilde \xe3 auml \xe4 aring \xe5
|
||||
aelig \xe6 ccedil \xe7 egrave \xe8 eacute \xe9 ecirc \xea
|
||||
euml \xeb igrave \xec iacute \xed icirc \xee iuml \xef
|
||||
eth \xf0 ntilde \xf1 ograve \xf2 oacute \xf3 ocirc \xf4
|
||||
otilde \xf5 ouml \xf6 divide \xf7 oslash \xf8 ugrave \xf9
|
||||
uacute \xfa ucirc \xfb uuml \xfc yacute \xfd thorn \xfe
|
||||
yuml \xff
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: Tcl
|
||||
# tab-width: 8
|
||||
# c-basic-offset: 4
|
||||
# tcl-indent-level: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8
|
||||
@@ -160,6 +160,13 @@ namespace eval hv3 {
|
||||
return $O(myWidget)
|
||||
}
|
||||
|
||||
# Namespace resolution can find an application-level search command
|
||||
# before invoking the unknown handler, so forward this method explicitly.
|
||||
proc search {me args} {
|
||||
upvar #0 $me O
|
||||
eval $O(myWidget) search $args
|
||||
}
|
||||
|
||||
proc unknown {method me args} {
|
||||
# puts "UNKNOWN: $me $method $args"
|
||||
upvar #0 $me O
|
||||
|
||||
@@ -63,6 +63,7 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
protected {
|
||||
method getPages {section}
|
||||
method loadSelectedPage {listbox}
|
||||
method refreshPageList {}
|
||||
method accordianCallback {_item _state}
|
||||
}
|
||||
@@ -126,6 +127,17 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# Load the page selected in the table of contents.
|
||||
#
|
||||
::itcl::body ManBrowser::loadSelectedPage {listbox} {
|
||||
set selection [$listbox curselection]
|
||||
if {[llength $selection] != 1} {
|
||||
return
|
||||
}
|
||||
loadPage [$listbox get $selection]
|
||||
}
|
||||
|
||||
##
|
||||
# Selects page in ToC & loads into HTML browser; used for command line calls
|
||||
#
|
||||
@@ -356,10 +368,8 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
|
||||
if {$itk_option(-useToC)} {
|
||||
bind $itk_component(manpagelistbox) <<ListboxSelect>> {
|
||||
set mb [itcl_info objects -class ManBrowser]
|
||||
$mb loadPage [%W get [%W curselection]]
|
||||
}
|
||||
bind $itk_component(manpagelistbox) <<ListboxSelect>> \
|
||||
[::itcl::code $this loadSelectedPage %W]
|
||||
}
|
||||
|
||||
# bind MouseWheel listener to the widget.document (this is the html
|
||||
|
||||
@@ -20,11 +20,21 @@
|
||||
###
|
||||
#
|
||||
# Description -
|
||||
# rouintes for displaying a Tcl/Tk widget for selecting a BOT face
|
||||
# routines for displaying a Tcl/Tk widget for selecting a BOT face
|
||||
#
|
||||
|
||||
proc bot_face_sel_apply { face } {
|
||||
if { [llength $face] != 3 } {
|
||||
return -code error "BOT face does not have 3 vertices"
|
||||
}
|
||||
|
||||
_mged_p {*}$face
|
||||
_mged_get_solid_keypoint
|
||||
_mged_refresh
|
||||
}
|
||||
|
||||
proc bot_face_select { face_list } {
|
||||
global bot_v1 bot_v2 bot_v3 mged_gui
|
||||
global mged_gui
|
||||
global ::tk::Priv
|
||||
|
||||
|
||||
@@ -46,71 +56,38 @@ proc bot_face_select { face_list } {
|
||||
|
||||
set face_list_len [llength $face_list]
|
||||
if { $face_list_len == 0 } {
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
bot_face_sel_abort $w
|
||||
return
|
||||
}
|
||||
|
||||
if { $face_list_len == 1 } {
|
||||
set face [lindex $face_list 0]
|
||||
if { [llength $face] != 3 } {
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
bot_face_sel_abort $w
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Internal Error" "Face does not have 3 vertices" error 0 OK
|
||||
return
|
||||
}
|
||||
set bot_v1 [lindex $face 0]
|
||||
set bot_v2 [lindex $face 1]
|
||||
set bot_v3 [lindex $face 2]
|
||||
get_solid_keypoint
|
||||
bot_face_sel_apply $face
|
||||
return
|
||||
}
|
||||
|
||||
create_listbox $w $screen "BOT Triangle" $face_list "bot_face_sel_abort $w"
|
||||
wm protocol $w WM_DELETE_WINDOW [list bot_face_sel_abort $w]
|
||||
bind_listbox $w "<B1-Motion>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh"
|
||||
if 0 {
|
||||
bind_listbox $w "<ButtonPress-1>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh"
|
||||
bind_listbox $w "<Double-1>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh;\
|
||||
destroy $w"
|
||||
} else {
|
||||
bind_listbox $w "<ButtonPress-1>" \
|
||||
"lbdcHack %W %x %y %t $id bf junkpath"
|
||||
}
|
||||
"bot_face_sel_apply \[get_listbox_entry %W %x %y\]"
|
||||
bind_listbox $w "<ButtonPress-1>" \
|
||||
"lbdcHack %W %x %y %t $id bf junkpath"
|
||||
hoc_register_data $w.listbox "BOT Triangle Select" {
|
||||
{summary "Use your left mouse button to highlight entries in this list.
|
||||
Each entry show the three vertex numbers that make up a single triangle.
|
||||
Each entry shows the three vertex numbers that make up a single triangle.
|
||||
Double click to select a triangle for editing."}
|
||||
}
|
||||
}
|
||||
|
||||
proc bot_face_sel_abort { w } {
|
||||
global bot_v1 bot_v2 bot_v3
|
||||
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
get_solid_keypoint
|
||||
catch "destroy $w"
|
||||
_mged_get_solid_keypoint
|
||||
_mged_refresh
|
||||
catch {destroy $w}
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
#
|
||||
|
||||
if ![info exists mged_default(display)] {
|
||||
if [info exists env(DISPLAY)] {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if ![info exists mged_gui(mged,screen)] {
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
#
|
||||
|
||||
if ![info exists mged_default(display)] {
|
||||
if [info exists env(DISPLAY)] {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if ![info exists mged_gui(mged,screen)] {
|
||||
|
||||
@@ -74,7 +74,6 @@ proc lbdcHack {w x y t id type path} {
|
||||
global mged_gui
|
||||
global mged_default
|
||||
global comb_control
|
||||
global bot_v1 bot_v2 bot_v3
|
||||
|
||||
# set item from listbox selection @$x,$y
|
||||
switch $type {
|
||||
@@ -119,11 +118,7 @@ proc lbdcHack {w x y t id type path} {
|
||||
matrix_illum $path $item
|
||||
}
|
||||
bf {
|
||||
set bot_v1 [lindex $item 0];
|
||||
set bot_v2 [lindex $item 1];
|
||||
set bot_v3 [lindex $item 2];
|
||||
get_solid_keypoint;
|
||||
refresh;
|
||||
bot_face_sel_apply $item
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -158,11 +153,7 @@ proc lbdcHack {w x y t id type path} {
|
||||
set mged_gui($id,mgs_pos) $item
|
||||
}
|
||||
bf {
|
||||
set bot_v1 [lindex $item 0];
|
||||
set bot_v2 [lindex $item 1];
|
||||
set bot_v3 [lindex $item 2];
|
||||
get_solid_keypoint;
|
||||
refresh;
|
||||
bot_face_sel_apply $item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+151
-127
@@ -27,10 +27,6 @@ if ![info exists mged_players] {
|
||||
set mged_players {}
|
||||
}
|
||||
|
||||
if ![info exists env(DISPLAY)] {
|
||||
set env(DISPLAY) ":0"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Ensure that tk.tcl has been loaded already via mged command 'loadtk'.
|
||||
#==============================================================================
|
||||
@@ -43,7 +39,6 @@ if { [info exists tk_strictMotif] == 0 } {
|
||||
#------------------------------------------------------------------------------
|
||||
# vmath.tcl : The vector math library
|
||||
# menu.tcl : The Tk menu replacement
|
||||
# html_library.tcl : Stephen Uhler's routines for processing HTML
|
||||
#==============================================================================
|
||||
|
||||
# MGED html manual directory search order precedence should be:
|
||||
@@ -519,148 +514,177 @@ proc echo args {
|
||||
#==============================================================================
|
||||
# HTML support
|
||||
#==============================================================================
|
||||
proc man_goto { w screen } {
|
||||
global ia_url
|
||||
global ::tk::Priv
|
||||
namespace eval ::mged::manual {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
}
|
||||
|
||||
cad_input_dialog $::tk::Priv(cad_dialog) $screen "Go To" "Enter filename to read:" \
|
||||
filename $ia_url(current) \
|
||||
0 {{ summary "Enter a filename or URL."}} OK
|
||||
proc ::mged::manual::file_uri {path} {
|
||||
set uri_path [string map {\\ /} [file normalize $path]]
|
||||
if {[string index $uri_path 0] ne "/"} {
|
||||
set uri_path /$uri_path
|
||||
}
|
||||
set uri_path [::tkhtml::encode $uri_path]
|
||||
return file://[string map {%2F /} $uri_path]
|
||||
}
|
||||
|
||||
if { [file exists $filename]!=0 } {
|
||||
if { [string match /* $filename] } {
|
||||
set new_url $filename
|
||||
} else {
|
||||
set new_url [pwd]/$filename
|
||||
proc ::mged::manual::local_path {location} {
|
||||
set uri [::tkhtml::uri $location]
|
||||
set scheme [$uri scheme]
|
||||
set authority [$uri authority]
|
||||
set path [::tkhtml::decode [$uri path]]
|
||||
$uri destroy
|
||||
|
||||
if {![string equal -nocase $scheme file]} {
|
||||
error "unsupported URI scheme '$scheme'"
|
||||
}
|
||||
if {$authority ne "" && ![string equal -nocase $authority localhost]} {
|
||||
set path //$authority$path
|
||||
}
|
||||
if {$::tcl_platform(platform) eq "windows" &&
|
||||
[regexp {^/[A-Za-z]:/} $path]} {
|
||||
set path [string range $path 1 end]
|
||||
}
|
||||
return [file normalize $path]
|
||||
}
|
||||
|
||||
proc ::mged::manual::request_error {handle error_message} {
|
||||
global message
|
||||
|
||||
set message $error_message
|
||||
$handle configure -mimetype text/plain
|
||||
$handle finish $error_message
|
||||
}
|
||||
|
||||
proc ::mged::manual::request {handle} {
|
||||
global message
|
||||
|
||||
set location [$handle cget -uri]
|
||||
if {[catch {set path [local_path $location]} path_error]} {
|
||||
request_error $handle "Cannot read $location: $path_error"
|
||||
return
|
||||
}
|
||||
|
||||
set message "Reading file $path"
|
||||
if {[catch {
|
||||
set channel [open $path rb]
|
||||
try {
|
||||
set data [read $channel]
|
||||
} finally {
|
||||
close $channel
|
||||
}
|
||||
} read_error]} {
|
||||
request_error $handle "Cannot read $path: $read_error"
|
||||
return
|
||||
}
|
||||
$handle finish $data
|
||||
}
|
||||
|
||||
HMlink_callback $w.text $new_url
|
||||
} else {
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Error reading file" \
|
||||
"Cannot read file $filename." error 0 OK
|
||||
proc ::mged::manual::remember_location {viewer} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {[info exists suppress_history($viewer)] &&
|
||||
$suppress_history($viewer)} {
|
||||
return
|
||||
}
|
||||
if {[catch {$viewer location} location] ||
|
||||
$location eq "home://blank/"} {
|
||||
return
|
||||
}
|
||||
if {![info exists back_history($viewer)] ||
|
||||
[lindex $back_history($viewer) end] ne $location} {
|
||||
lappend back_history($viewer) $location
|
||||
}
|
||||
}
|
||||
|
||||
proc ia_man { parent screen } {
|
||||
global mged_html_dir ia_url message
|
||||
proc ::mged::manual::go_back {viewer} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {![info exists back_history($viewer)] ||
|
||||
![llength $back_history($viewer)]} {
|
||||
return
|
||||
}
|
||||
|
||||
set location [lindex $back_history($viewer) end]
|
||||
set back_history($viewer) [lrange $back_history($viewer) 0 end-1]
|
||||
set suppress_history($viewer) 1
|
||||
set status [catch {$viewer goto $location -nosave} result options]
|
||||
set suppress_history($viewer) 0
|
||||
if {$status} {
|
||||
return -options $options $result
|
||||
}
|
||||
}
|
||||
|
||||
proc ::mged::manual::go_to {viewer screen} {
|
||||
global ::tk::Priv
|
||||
|
||||
set initial_path [pwd]
|
||||
if {![catch {local_path [$viewer location]} current_path]} {
|
||||
set initial_path $current_path
|
||||
}
|
||||
cad_input_dialog $::tk::Priv(cad_dialog) $screen "Go To" \
|
||||
"Enter filename to read:" filename $initial_path \
|
||||
0 {{ summary "Enter the name of a local HTML file."}} OK
|
||||
|
||||
if {[file pathtype $filename] eq "relative"} {
|
||||
set filename [file join [pwd] $filename]
|
||||
}
|
||||
set filename [file normalize $filename]
|
||||
if {[file readable $filename] && ![file isdirectory $filename]} {
|
||||
$viewer goto [file_uri $filename]
|
||||
return
|
||||
}
|
||||
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Error reading file" \
|
||||
"Cannot read file $filename." error 0 OK
|
||||
}
|
||||
|
||||
proc ::mged::manual::cleanup {viewer destroyed_widget} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {$destroyed_widget ne $viewer} {
|
||||
return
|
||||
}
|
||||
unset -nocomplain back_history($viewer)
|
||||
unset -nocomplain suppress_history($viewer)
|
||||
}
|
||||
|
||||
proc ia_man {parent screen} {
|
||||
global mged_html_dir message
|
||||
|
||||
package require hv3
|
||||
|
||||
set w $parent.man
|
||||
catch { destroy $w }
|
||||
catch {destroy $w}
|
||||
toplevel $w -screen $screen
|
||||
wm title $w "MGED HTML browser"
|
||||
|
||||
frame $w.f -relief sunken -bd 1
|
||||
pack $w.f -side top -fill x
|
||||
|
||||
button $w.f.close -text Close -command "destroy $w"
|
||||
button $w.f.goto -text "Go To" -command "man_goto $w $screen"
|
||||
button $w.f.back -text "Back" -command "ia_man_back $w.text"
|
||||
set viewer [::hv3::hv3 $w.html \
|
||||
-requestcmd ::mged::manual::request]
|
||||
button $w.f.close -text Close -command [list destroy $w]
|
||||
button $w.f.goto -text "Go To" \
|
||||
-command [list ::mged::manual::go_to $viewer $screen]
|
||||
button $w.f.back -text "Back" \
|
||||
-command [list ::mged::manual::go_back $viewer]
|
||||
|
||||
pack $w.f.close $w.f.goto $w.f.back -side left -fill x -expand yes
|
||||
|
||||
label $w.message -textvar message -anchor w
|
||||
label $w.message -textvariable message -anchor w
|
||||
pack $w.message -side top -anchor w -fill x
|
||||
pack $viewer -side top -fill both -expand yes
|
||||
|
||||
scrollbar $w.scrolly -command "$w.text yview"
|
||||
scrollbar $w.scrollx -command "$w.text xview" -orient horizontal
|
||||
text $w.text -relief ridge -yscroll "$w.scrolly set" \
|
||||
-xscroll "$w.scrollx set"
|
||||
pack $w.scrolly -side right -fill y
|
||||
pack $w.text -side top -fill both -expand yes
|
||||
pack $w.scrollx -side bottom -fill x
|
||||
set ::mged::manual::back_history($viewer) {}
|
||||
set ::mged::manual::suppress_history($viewer) 0
|
||||
bind $viewer <<Goto>> +[list ::mged::manual::remember_location $viewer]
|
||||
bind $viewer <Destroy> +[list ::mged::manual::cleanup $viewer %W]
|
||||
|
||||
set w $w.text
|
||||
|
||||
HMinit_win $w
|
||||
set ia_url(current) $mged_html_dir/
|
||||
set ia_url(last) ""
|
||||
set ia_url(backtrack) ""
|
||||
HMlink_callback $w contents.html
|
||||
}
|
||||
|
||||
proc HMlink_callback { w href } {
|
||||
global ia_url message
|
||||
|
||||
if {[string match /* $href]} {
|
||||
set new_url $href
|
||||
} else {
|
||||
if { [file isdirectory $ia_url(current)] } {
|
||||
set new_url $ia_url(current)$href
|
||||
} else {
|
||||
set new_url [file dirname $ia_url(current)]/$href
|
||||
}
|
||||
}
|
||||
|
||||
# Remove tags
|
||||
regsub {"#[0-9a-zA-Z]*"} $new_url {} ia_url(current)
|
||||
lappend ia_url(last) $ia_url(current)
|
||||
set ia_url(backtrack) [lrange $ia_url(last) 0 \
|
||||
[expr [llength $ia_url(last)]-2]]
|
||||
|
||||
HMreset_win $w
|
||||
HMparse_html [ia_get_html $ia_url(current)] "HMrender $w"
|
||||
update
|
||||
}
|
||||
|
||||
proc ia_man_back { w } {
|
||||
global ia_url message
|
||||
|
||||
if {[llength $ia_url(backtrack)]<1} {
|
||||
return
|
||||
}
|
||||
|
||||
set new_url [lindex $ia_url(backtrack) end]
|
||||
set ia_url(backtrack) [lrange $ia_url(backtrack) 0 \
|
||||
[expr [llength $ia_url(backtrack)]-2]]
|
||||
|
||||
HMreset_win $w
|
||||
HMparse_html [ia_get_html $new_url] "HMrender $w"
|
||||
update
|
||||
}
|
||||
|
||||
proc HMset_image { handle src } {
|
||||
global ia_url message
|
||||
|
||||
if {[string match http://* $src]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {[string match /* $src]} {
|
||||
set image $src
|
||||
} else {
|
||||
set image [file dirname $ia_url(current)]/$src
|
||||
}
|
||||
|
||||
set message "Fetching image $image."
|
||||
update
|
||||
if {[string first " $image " " [image names] "] >= 0} {
|
||||
HMgot_image $handle $image
|
||||
} else {
|
||||
catch {image create photo $image -file $image} image
|
||||
HMgot_image $handle $image
|
||||
}
|
||||
}
|
||||
|
||||
proc ia_get_html {file} {
|
||||
global message ia_url
|
||||
|
||||
set message "Reading file $file"
|
||||
update
|
||||
|
||||
if {[string match *.gif $file]} {
|
||||
return "<img src=\"[file tail $file]\">"
|
||||
}
|
||||
|
||||
if {[catch {set fd [open $file]} msg]} {
|
||||
return "
|
||||
<title>Bad file $file</title>
|
||||
<h1>Error reading $file</h1><p>
|
||||
$msg<hr>
|
||||
"
|
||||
}
|
||||
set result [read $fd]
|
||||
close $fd
|
||||
return $result
|
||||
set contents [file join $mged_html_dir contents.html]
|
||||
$viewer goto [::mged::manual::file_uri $contents]
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
||||
@@ -154,8 +154,7 @@ proc dump_mged_state {fd} {
|
||||
puts $fd "# Determines the border width in the geometry window"
|
||||
puts $fd "set mged_default(bd) $mged_default(bd)"
|
||||
puts $fd ""
|
||||
puts $fd "# X display string used to determine the screen"
|
||||
puts $fd "# on which to display the GUI's windows"
|
||||
puts $fd "# Tk screen name used for the GUI's windows"
|
||||
puts $fd "set mged_default(display) $mged_default(display)"
|
||||
puts $fd ""
|
||||
puts $fd "# Configures the GUI. Note - this is only"
|
||||
|
||||
@@ -108,13 +108,12 @@ if {![info exists mged_default(config)]} {
|
||||
set mged_default(config) b
|
||||
}
|
||||
|
||||
if {[info exists env(DISPLAY)]} {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
if {![info exists mged_default(display)]} {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set env(DISPLAY) $mged_default(display)
|
||||
# DISPLAY is an X11 connection setting, not a portable Tk screen name. Tk is
|
||||
# initialized before this script runs, so its canonical screen is authoritative
|
||||
# on X11, Win32, and Aqua alike. Preserve a value supplied explicitly through
|
||||
# .mgedrc or the gui command for multi-display X11 use.
|
||||
if {![info exists mged_default(display)]} {
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if {![info exists mged_default(gdisplay)]} {
|
||||
|
||||
Reference in New Issue
Block a user