Compare commits

...
17 Commits
Author SHA1 Message Date
Clifford Yapp acd957aec3 Use Tk-native display selection across graphical tools
DISPLAY is an X11 connection setting, but MGED treated any inherited
value as an explicit Tk screen. Unix-like shells on Windows can export
placeholders, causing native Tk child windows and display managers to
fail even though Tk initialized successfully.

Let Tk select its platform backend and canonical screen when no -d
option is given. Preserve explicit X11 selection by applying DISPLAY
only for Tk initialization, restore the caller environment for Win32
and Aqua, and reject unsupported native screen requests clearly.

Use the initialized Tk screen for WGL and Tk software rendering, and
stop assigning X11 defaults to offscreen or Qt contexts. Remove the
same synthetic DISPLAY assumptions from MGED and Archer scripts so
Archer, RtWizard, BRLMan, and Tk ISST follow consistent startup rules.
2026-10-02 14:54:31 -04:00
Clifford Yapp f7a8d5b406 Fix Edit->Reset menu entry - uses reinit_edit_state() 2026-10-02 13:42:36 -04:00
Clifford Yapp 85de3929e5 Make sure zbuffer and lighting are set up when using share_dlist 2026-10-02 13:09:25 -04:00
Clifford Yapp 0a8c6d8bc2 Update Manual viewer in MGED to use tkhtml3 2026-10-01 15:43:07 -04:00
Clifford Yapp a00efd15c6 Fixes for man page viewer 2026-10-01 15:43:07 -04:00
f4alt 06c8ab6204 more uniform exiting
consolidate the call sites where we end up in bu_exit due to a failure.
Have a simple wrapper so we flush any results buffers that may be useful
for error context, and then call the bu_exit.
2026-10-01 14:34:31 -04:00
f4alt cd55562c46 bubble gqa return code 2026-10-01 14:34:31 -04:00
f4alt 6d142b62e7 validate material IDs are present in density table
previously, positive but not defined in the table values would silently
corrupt the calculation with a -1.0 for the density value and no
warning.
2026-10-01 14:34:31 -04:00
f4alt da2f503367 handle cache compression failures safely
ensure we can compress with bounds checks. If we got something failing
or unsupported, log and return instead of BU_ASSERT (bombing). This
allows the caller to appropriately free the external.
2026-10-01 14:34:31 -04:00
f4alt a9ac66788a guard logging behind debug flag 2026-10-01 14:34:31 -04:00
Clifford Yapp 4cc9f9cf01 Be more nuanced about what ARB edit ops we can support. 2026-10-01 12:10:33 -04:00
Clifford Yapp 7b1898d9fd Add ARBN inside logic. 2026-10-01 12:06:29 -04:00
Clifford Yapp e4d297893e label hyp neck-to-base ratio 2026-10-01 12:00:03 -04:00
Clifford Yapp 0173dd8c40 Correct bot face selection logic 2026-10-01 11:55:30 -04:00
Clifford Yapp cf344d773e Print result in mged (just assigning to interp isn't enough) 2026-10-01 11:14:39 -04:00
Clifford Yapp 8c51c1d527 Mention facetize improvements in NEWS 2026-10-01 08:55:26 -04:00
Clifford Yapp 6e48ea9ddd Center README toplevel text 2026-09-30 06:44:36 -04:00
42 changed files with 888 additions and 1052 deletions
+2
View File
@@ -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
+3 -3
View File
@@ -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
-1
View File
@@ -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
+1
View File
@@ -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
+24
View File
@@ -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
+5
View File
@@ -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")
+31
View File
@@ -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 ***"
+64
View File
@@ -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"
+41 -1
View File
@@ -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
}
+30 -18
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+3 -9
View File
@@ -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;
+3 -9
View File
@@ -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;
+10
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+13
View File
@@ -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
View File
@@ -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;
+20 -4
View File
@@ -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;
}
+2 -2
View File
@@ -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 {
+4 -2
View File
@@ -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);
+8 -1
View File
@@ -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;
}
+74
View File
@@ -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. */
+26
View File
@@ -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)
* ================================================================*/
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
-1
View File
@@ -146,7 +146,6 @@ set(
helpcomm.tcl
helplib.tcl
hoc.tcl
html_library.tcl
libtclcad.tcl
man_browser.tcl
menu_override.tcl
-1
View File
@@ -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
+3 -3
View File
@@ -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]
-663
View File
@@ -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
+7
View File
@@ -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
+14 -4
View File
@@ -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
+23 -46
View File
@@ -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:
+1 -5
View File
@@ -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)] {
+1 -5
View File
@@ -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)] {
+2 -11
View File
@@ -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
View File
@@ -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]
}
#==============================================================================
+1 -2
View File
@@ -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"
+6 -7
View File
@@ -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)]} {