summaryrefslogtreecommitdiff
path: root/app/wlib
diff options
context:
space:
mode:
Diffstat (limited to 'app/wlib')
-rw-r--r--app/wlib/gtklib/CMakeLists.txt48
-rw-r--r--app/wlib/gtklib/browserhelp.c59
-rw-r--r--app/wlib/gtklib/button.c44
-rw-r--r--app/wlib/gtklib/color.c11
-rw-r--r--app/wlib/gtklib/control.c59
-rw-r--r--app/wlib/gtklib/droplist.c75
-rw-r--r--app/wlib/gtklib/filesel.c238
-rw-r--r--app/wlib/gtklib/font.c17
-rw-r--r--app/wlib/gtklib/gtkdraw-cairo.c995
-rw-r--r--app/wlib/gtklib/gtkint.h24
-rw-r--r--app/wlib/gtklib/help.c16
-rw-r--r--app/wlib/gtklib/ixhelp.c10
-rw-r--r--app/wlib/gtklib/list.c5
-rw-r--r--app/wlib/gtklib/liststore.c2
-rw-r--r--app/wlib/gtklib/menu.c8
-rw-r--r--app/wlib/gtklib/notice.c18
-rw-r--r--app/wlib/gtklib/opendocument.c117
-rw-r--r--app/wlib/gtklib/osxhelp.c67
-rw-r--r--app/wlib/gtklib/print.c233
-rw-r--r--app/wlib/gtklib/single.c82
-rw-r--r--app/wlib/gtklib/splash.c12
-rw-r--r--app/wlib/gtklib/statusbar.c6
-rw-r--r--app/wlib/gtklib/text.c24
-rw-r--r--app/wlib/gtklib/timer.c3
-rw-r--r--app/wlib/gtklib/util.c88
-rw-r--r--app/wlib/gtklib/window.c204
-rw-r--r--app/wlib/gtklib/wpref.c10
-rw-r--r--app/wlib/include/mswlib.h2
-rw-r--r--app/wlib/include/wlib.h103
-rw-r--r--app/wlib/mswlib/CMakeLists.txt19
-rw-r--r--app/wlib/mswlib/backgnd.c220
-rw-r--r--app/wlib/mswlib/mswbitmap.c46
-rw-r--r--app/wlib/mswlib/mswbutt.c21
-rw-r--r--app/wlib/mswlib/mswchksm.c125
-rw-r--r--app/wlib/mswlib/mswdraw.c833
-rw-r--r--app/wlib/mswlib/mswedit.c210
-rw-r--r--app/wlib/mswlib/mswint.h23
-rw-r--r--app/wlib/mswlib/mswlist.c2
-rw-r--r--app/wlib/mswlib/mswmenu.c8
-rw-r--r--app/wlib/mswlib/mswmisc.c266
-rw-r--r--app/wlib/mswlib/mswmsg.c9
-rw-r--r--app/wlib/mswlib/mswpref.c1
-rw-r--r--app/wlib/mswlib/mswprint.c46
-rw-r--r--app/wlib/mswlib/mswsplash.c8
-rw-r--r--app/wlib/mswlib/mswtext.c63
-rw-r--r--app/wlib/mswlib/simple-gettext.c3
-rw-r--r--app/wlib/mswlib/unittest/CMakeLists.txt11
-rw-r--r--app/wlib/mswlib/unittest/utf8test.c65
-rw-r--r--app/wlib/mswlib/utf8conv.c210
49 files changed, 3495 insertions, 1274 deletions
diff --git a/app/wlib/gtklib/CMakeLists.txt b/app/wlib/gtklib/CMakeLists.txt
index bf20e91..97ab56f 100644
--- a/app/wlib/gtklib/CMakeLists.txt
+++ b/app/wlib/gtklib/CMakeLists.txt
@@ -18,6 +18,7 @@ set(sources
menu.c
message.c
notice.c
+ opendocument.c
pixbuf.c
png.c
print.c
@@ -35,29 +36,43 @@ set(sources
gtkdraw-cairo.c
)
-
# help system is OS and build specific, add appropriate source files
if(APPLE)
- set(sources
- ${sources}
- osxhelp.c)
-else()
+ if (XTRKCAD_USE_APPLEHELP)
+ set(sources
+ ${sources}
+ osxhelp.c)
+ else(XTRKCAD_USE_APPLEHELP)
+ if(XTRKCAD_USE_BROWSER)
+ set(sources
+ ${sources}
+ browserhelp.c)
+ else(XTRKCAD_USE_BROWSER)
+ PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0" REQUIRED)
+ set(sources
+ ${sources}
+ ixhelp.c)
+ endif(XTRKCAD_USE_BROWSER)
+ endif(XTRKCAD_USE_APPLEHELP)
+else(APPLE)
if(XTRKCAD_USE_BROWSER)
set(sources
${sources}
browserhelp.c)
- else()
+ else(XTRKCAD_USE_BROWSER)
+ PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0" REQUIRED)
set(sources
${sources}
ixhelp.c)
- endif()
-endif()
+ endif(XTRKCAD_USE_BROWSER)
+endif(APPLE)
include_directories(${XTrkCAD_BINARY_DIR})
add_library(xtrkcad-wlib ${headers} ${sources})
# GTK
+find_package (GTK2)
include_directories(${GTK_INCLUDE_DIRS})
target_link_libraries(xtrkcad-wlib ${GTK_LIBRARIES})
@@ -67,7 +82,16 @@ include_directories(${GTK_UNIX_PRINT_INCLUDE_DIRS})
target_link_libraries(xtrkcad-wlib ${GTK_UNIX_PRINT_LIBRARIES})
# add dependency to webkit if configured
-if(NOT XTRKCAD_USE_BROWSER)
- include_directories(${GTK_WEBKIT_INCLUDE_DIRS})
- target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES})
-endif()
+if (APPLE)
+ if(NOT XTRKCAD_USE_APPLEHELP)
+ if(NOT XTRKCAD_USE_BROWSER)
+ include_directories(${GTK_WEBKIT_INCLUDE_DIRS})
+ target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES})
+ endif()
+ endif()
+else (APPLE)
+ if(NOT XTRKCAD_USE_BROWSER)
+ include_directories(${GTK_WEBKIT_INCLUDE_DIRS})
+ target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES})
+ endif()
+endif(APPLE)
diff --git a/app/wlib/gtklib/browserhelp.c b/app/wlib/gtklib/browserhelp.c
index 9351e86..aa8f5c7 100644
--- a/app/wlib/gtklib/browserhelp.c
+++ b/app/wlib/gtklib/browserhelp.c
@@ -22,12 +22,17 @@
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
+
+#include "misc.h"
#include "gtkint.h"
#include "i18n.h"
#include "dynstring.h"
+#define debug 0
+
#define DEFAULTBROWSERCOMMAND "xdg-open"
#define HELPERRORTEXT "Help Error - help information can not be found.\n" \
@@ -38,7 +43,7 @@
"variable.\n Also make sure that the user has sufficient access rights to read these" \
"files."
/**
- * Create a fully qualified url froma topic
+ * Create a fully qualified url from a topic
*
* \param helpUrl OUT pointer to url, free by caller
* \param topic IN the help topic
@@ -63,36 +68,6 @@ TopicToUrl(char **helpUrl, const char *topic)
DynStringFree(&url);
}
/**
- * Extend the PATH variable inthe environment to include XTrackCAD's
- * script directory.
- *
- * \return pointer to old path
- */
-
-static char *
-ExtendPath(void)
-{
- char *path = getenv("PATH");
- DynString newPath;
- DynStringMalloc(&newPath, 16);
-
- // append XTrackCAD's directory to the path as a fallback
- DynStringCatCStrs(&newPath,
- path,
- ":",
- wGetAppLibDir(),
- NULL);
-
- setenv("PATH",
- DynStringToCStr(&newPath),
- TRUE);
-
- DynStringFree(&newPath);
-
- return (path);
-}
-
-/**
* Invoke the system's default browser to display help for <topic>. First the
* system's standard xdg-open command is attempted. If that is not available, the
* version included with the XTrackCAD installation is executed.
@@ -104,34 +79,20 @@ void wHelp(const char * topic)
{
int rc;
char *url;
- DynString commandLine;
char *currentPath;
assert(topic != NULL);
assert(strlen(topic));
- currentPath = ExtendPath();
- TopicToUrl(&url, topic);
+ if (!CheckHelpTopicExists(topic)) return;
- DynStringMalloc(&commandLine, 16);
- DynStringCatCStrs(&commandLine,
- DEFAULTBROWSERCOMMAND,
- " ",
- url,
- NULL);
+ TopicToUrl(&url, topic);
- // the command should be found via the PATH
- rc = system(DynStringToCStr(&commandLine));
+ rc = wOpenFileExternal(url);
- if (rc) {
+ if (!rc) {
wNotice(HELPERRORTEXT, _("Cancel"), NULL);
}
- // restore the PATH
- setenv("PATH",
- currentPath,
- TRUE);
-
free(url);
- DynStringFree(&commandLine);
}
diff --git a/app/wlib/gtklib/button.c b/app/wlib/gtklib/button.c
index b5fabe8..51106c8 100644
--- a/app/wlib/gtklib/button.c
+++ b/app/wlib/gtklib/button.c
@@ -94,15 +94,23 @@ void wlibSetLabel(
} else {
pixbuf = wlibPixbufFromXBM( bm );
}
+ double scaleicon;
+ wPrefGetFloat(PREFSECTION, LARGEICON, &scaleicon, 1.0);
+ if (scaleicon<1.0) scaleicon=1.0;
+ if (scaleicon>2.0) scaleicon=2.0;
+ GdkPixbuf *pixbuf2 =
+ gdk_pixbuf_scale_simple(pixbuf, gdk_pixbuf_get_width(pixbuf)*scaleicon, gdk_pixbuf_get_height(pixbuf)*scaleicon, GDK_INTERP_BILINEAR);
+ g_object_ref_sink(pixbuf);
+ g_object_unref((gpointer)pixbuf);
if (*imageG==NULL) {
- *imageG = gtk_image_new_from_pixbuf(pixbuf);
+ *imageG = gtk_image_new_from_pixbuf(pixbuf2);
gtk_container_add(GTK_CONTAINER(widget), *imageG);
gtk_widget_show(*imageG);
} else {
- gtk_image_set_from_pixbuf(GTK_IMAGE(*imageG), pixbuf);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(*imageG), pixbuf2);
}
- g_object_ref_sink(pixbuf);
- g_object_unref((gpointer)pixbuf);
+ g_object_ref_sink(pixbuf2);
+ g_object_unref((gpointer)pixbuf2);
} else {
if (*labelG==NULL) {
*labelG = (GtkLabel*)gtk_label_new(wlibConvertInput(labelStr));
@@ -172,6 +180,18 @@ static void pushButt(
}
/**
+ * Called after expose event default hander - allows the button to be outlined
+ */
+static wBool_t exposeButt(
+ GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer g)
+{
+ wControl_p b = (wControl_p)g;
+ return wControlExpose(widget,event,b);
+}
+
+/**
* Create a button
*
* \param parent IN parent window
@@ -198,7 +218,10 @@ wButton_p wButtonCreate(
void * data)
{
wButton_p b;
- b = wlibAlloc(parent, B_BUTTON, x, y, labelStr, sizeof *b, data);
+ if (option&BO_ICON) //The labelStr here is a wIcon_p
+ b = wlibAlloc(parent, B_BUTTON, x, y, " ", sizeof *b, data);
+ else
+ b = wlibAlloc(parent, B_BUTTON, x, y, labelStr, sizeof *b, data);
b->option = option;
b->action = action;
wlibComputePos((wControl_p)b);
@@ -206,9 +229,12 @@ wButton_p wButtonCreate(
b->widget = gtk_toggle_button_new();
g_signal_connect(GTK_OBJECT(b->widget), "clicked",
G_CALLBACK(pushButt), b);
+ g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event",
+ G_CALLBACK(exposeButt), b);
if (width > 0) {
gtk_widget_set_size_request(b->widget, width, -1);
}
+
if( labelStr ){
wButtonSetLabel(b, labelStr);
}
@@ -484,6 +510,8 @@ wChoice_p wRadioCreate(
b->valueP = valueP;
wlibComputePos((wControl_p)b);
+ ((wControl_p)b)->outline = FALSE;
+
if (option&BC_HORZ) {
b->widget = gtk_hbox_new(FALSE, 0);
} else {
@@ -506,6 +534,8 @@ wChoice_p wRadioCreate(
gtk_widget_show(butt);
g_signal_connect(GTK_OBJECT(butt), "toggled",
G_CALLBACK(pushChoice), b);
+ g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event",
+ G_CALLBACK(exposeButt), b);
wlibAddHelpString(butt, helpStr);
}
@@ -586,6 +616,8 @@ wChoice_p wToggleCreate(
b->action = action;
wlibComputePos((wControl_p)b);
+ ((wControl_p)b)->outline = FALSE;
+
if (option&BC_HORZ) {
b->widget = gtk_hbox_new(FALSE, 0);
} else {
@@ -604,6 +636,8 @@ wChoice_p wToggleCreate(
gtk_widget_show(butt);
g_signal_connect(GTK_OBJECT(butt), "toggled",
G_CALLBACK(pushChoice), b);
+ g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event",
+ G_CALLBACK(exposeButt), b);
wlibAddHelpString(butt, helpStr);
}
diff --git a/app/wlib/gtklib/color.c b/app/wlib/gtklib/color.c
index 64b96ef..e1689d2 100644
--- a/app/wlib/gtklib/color.c
+++ b/app/wlib/gtklib/color.c
@@ -100,7 +100,7 @@ static colorMap_t colorMap[] = {
{ 208, 208, 208 }, /* Gray */
{ 224, 224, 224 }, /* Gray */
{ 240, 240, 240 }, /* Gray */
- { 0, 0, 0 } /* BlackPixel */
+ { 255, 255, 255 } /* WhitePixel */
};
#define NUM_GRAYS (16)
@@ -125,7 +125,7 @@ wDrawColor wDrawColorGray(
if (n <= 0) {
return wDrawColorBlack;
- } else if (n > NUM_GRAYS) {
+ } else if (n >= NUM_GRAYS) {
return wDrawColorWhite;
} else {
n = (n*256)/NUM_GRAYS;
@@ -209,7 +209,7 @@ wDrawColor wDrawFindColor(
long rgb0)
{
wDrawColor cc;
- int r0, g0, b0;
+ int r0, g0, b0, r1, g1, b1;
int d0;
int i;
colorMap_t tempMapValue;
@@ -231,7 +231,10 @@ wDrawColor wDrawFindColor(
colorMap_t * cm_p;
cm_p = &g_array_index(colorMap_garray, colorMap_t, i);
- d1 = abs(r0-cm_p->red) + abs(g0-cm_p->green) + abs(b0-cm_p->blue);
+ r1 = (int)cm_p->red;
+ g1 = (int)cm_p->green;
+ b1 = (int)cm_p->blue;
+ d1 = abs(r0-r1) + abs(g0-g1) + abs(b0-b1);
if (d1 == 0) {
return i;
diff --git a/app/wlib/gtklib/control.c b/app/wlib/gtklib/control.c
index c891924..07d9210 100644
--- a/app/wlib/gtklib/control.c
+++ b/app/wlib/gtklib/control.c
@@ -35,7 +35,7 @@
#include "gtkint.h"
-#define GTKCONTROLHILITEWIDTH (3)
+#define GTKCONTROLHILITEWIDTH (4)
/**
* Cause the control <b> to be displayed or hidden.
@@ -252,6 +252,46 @@ void wControlSetFocus(
{
}
+wBool_t wControlExpose (
+ GtkWidget * widget,
+ GdkEventExpose * event,
+ wControl_p b
+ )
+{
+ GdkWindow * win = gtk_widget_get_window(b->widget);
+ cairo_t * cr = NULL;
+ if (win) {
+ cr = gdk_cairo_create(win);
+ } else return TRUE;
+
+#ifdef CURSOR_SURFACE
+ if (b && b->cursor_surface.surface && b->cursor_surface.show) {
+ cairo_set_source_surface(cr,b->cursor_surface.surface,event->area.x, event->area.y);
+ cairo_set_operator(cr,CAIRO_OPERATOR_OVER);
+ cairo_rectangle(cr,event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill(cr);
+ }
+#endif
+
+ if (b->outline) {
+ cairo_set_source_rgb(cr, 0.23, 0.37, 0.80);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_line_width(cr, GTKCONTROLHILITEWIDTH);
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
+ cairo_rectangle(cr,event->area.x+2, event->area.y+2,
+ event->area.width-4, event->area.height-4);
+ cairo_stroke(cr);
+ }
+
+
+ cairo_destroy(cr);
+
+
+ return FALSE;
+}
+
/**
* Draw a rectangle around a control
* \param b IN the control
@@ -279,17 +319,8 @@ void wControlHilite(
return;
}
- cr = gdk_cairo_create(gtk_widget_get_window(b->parent->gtkwin));
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_set_operator(cr, CAIRO_OPERATOR_XOR);
- cairo_set_line_width(cr, GTKCONTROLHILITEWIDTH);
- cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
- cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
- cairo_rectangle(cr,
- b->realX - GTKCONTROLHILITEWIDTH,
- b->realY - off,
- b->w + GTKCONTROLHILITEWIDTH,
- b->h + off + 1);
- cairo_stroke(cr);
- cairo_destroy(cr);
+ b->outline = hilite;
+
+ if (b->widget)
+ gtk_widget_queue_draw(b->widget);
}
diff --git a/app/wlib/gtklib/droplist.c b/app/wlib/gtklib/droplist.c
index 5fbdd17..69a2efd 100644
--- a/app/wlib/gtklib/droplist.c
+++ b/app/wlib/gtklib/droplist.c
@@ -235,43 +235,16 @@ wBool_t wDropListSetValues(
}
/**
- * Signal handler for the "changed"-signal in drop list's entry field.
- * Get the entered text and calls the 'action' for handling of entered
- * value.
- * *
- * \param entry IN entry field of the droplist
- * \param data IN the drop list handle
- * \return
- */
-
-static void DropListEntryEntered(
- GtkEntry * entry,
- gpointer userData)
-{
- const gchar * text;
-
- text = gtk_entry_get_text(entry);
-
- if (text && *text != '\0') {
- gchar *copyOfText = g_strdup(text);
- ((wList_p)userData)->editted = TRUE;
- ((wList_p)userData)->action(-1, copyOfText, 1, ((wList_p)userData)->data, NULL);
- g_free((gpointer)copyOfText);
- } else {
- wBeep();
- }
-}
-
-/**
- * Signal handler for the "changed"-signal in drop list. Gets the selected
- * text and determines the selected row in the tree model.
+ * Signal handler for the "changed"-signal in drop list.
+ * Gets the selected text and determines the selected row in the tree model.
+ * Or handles user entered text.
*
* \param comboBox IN the combo_box
* \param data IN the drop list handle
* \return
*/
-static int DropListSelectChild(
+static int DropListChanged(
GtkComboBox * comboBox,
gpointer data)
{
@@ -279,17 +252,14 @@ static int DropListSelectChild(
GtkTreeIter iter;
wIndex_t inx = 0;
- gchar *string;
- wListItem_p addData;
+ gchar *string = NULL;
+ wListItem_p listItemP = NULL;
if (bl->recursion) {
return 0;
}
- bl->editted = FALSE;
-
- /* Obtain currently selected item from combo box.
- * If nothing is selected, do nothing. */
+ /* Obtain currently selected item from combo box. */
if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboBox), &iter)) {
GtkTreeModel *model;
@@ -301,19 +271,30 @@ static int DropListSelectChild(
&iter);
inx = atoi(string);
g_free(string);
+ string = NULL;
/* Obtain string from model. */
gtk_tree_model_get(model, &iter,
LISTCOL_TEXT, &string,
- LISTCOL_DATA, (void *)&addData,
+ LISTCOL_DATA, (void *)&listItemP,
-1);
+ bl->editted = FALSE;
} else {
- return 0;
+ /* Nothing selected, user is entering text directly */
+ inx = -1;
+ GtkEntry * entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(bl->widget)));
+ if ( entry == NULL )
+ return 0;
+ const char * string1 = gtk_entry_get_text(entry);
+ if ( string1 == NULL )
+ return 0;
+ string = g_strdup(string1);
+ bl->editted = TRUE;
}
/* selection changed, store new selections and call back */
- if (bl->last != inx) {
+ if (bl->last != inx || bl->editted == TRUE) {
bl->last = inx;
@@ -323,11 +304,12 @@ static int DropListSelectChild(
/* selection changed -> callback */
if (string && bl->action) {
- bl->action(inx, string, 1, bl->data, addData->itemData);
+ bl->action(inx, string, 1, bl->data, listItemP?listItemP->itemData:NULL);
}
}
- g_free(string);
+ if ( string )
+ g_free(string);
return 1;
}
@@ -429,14 +411,7 @@ wList_p wDropListCreate(
gtk_widget_set_name(b->widget,"mycombo");
g_signal_connect(GTK_OBJECT(b->widget), "changed",
- G_CALLBACK(DropListSelectChild), b);
-
- if (option & BL_EDITABLE) {
- g_signal_connect(gtk_bin_get_child(GTK_BIN(b->widget)),
- "changed",
- G_CALLBACK(DropListEntryEntered),
- b);
- }
+ G_CALLBACK(DropListChanged), b);
gtk_widget_set_size_request(b->widget, width, -1);
diff --git a/app/wlib/gtklib/filesel.c b/app/wlib/gtklib/filesel.c
index ca30c7f..a1fb7cc 100644
--- a/app/wlib/gtklib/filesel.c
+++ b/app/wlib/gtklib/filesel.c
@@ -34,24 +34,92 @@
#define GSEAL_ENABLE
#include <gtk/gtk.h>
+#include <glib-object.h>
#include "gtkint.h"
#include "i18n.h"
#define MAX_ALLOWEDFILTERS 10
struct wFilSel_t {
- GtkWidget * window;
- wFilSelCallBack_p action;
- void * data;
- int pattCount;
- GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ];
- wFilSelMode_e mode;
- int opt;
- const char * title;
- wWin_p parent;
- char *defaultExtension;
+ GtkWidget * window; /**< file selector handle*/
+ wFilSelCallBack_p action; /**< */
+ void * data; /**< */
+ int pattCount; /**< number of file patterns*/
+ wBool_t loadPatternsAdded; /** Already loaded */
+ GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ]; /**< array of file patterns */
+ wFilSelMode_e mode; /**< used for load or save */
+ int opt; /**< see FS_ options */
+ const char * title; /**< dialog box title */
+ wWin_p parent; /**< parent window */
+ char *defaultExtension; /**< to use if no extension specified */
};
+/**
+ * Signal handler for 'changed' signal of custom combo box. The filter
+ * is set accordinng to the file format active in the combo box
+ *
+ * \param comboBox the combo box
+ * \param fileSelector data of the file selector
+ *
+ */
+
+static void FileFormatChanged( GtkWidget *comboBox,
+ struct wFilSel_t *fileSelector )
+{
+ // get active entry
+ int entry = (int)gtk_combo_box_get_active (GTK_COMBO_BOX(comboBox));
+
+ if( entry>=0 ) {
+ g_object_ref(G_OBJECT( (fileSelector->filter)[ entry ]));
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileSelector->window ),
+ (fileSelector->filter)[ entry ]);
+ }
+}
+
+/**
+ * Create a widget containing a combo box for selecting a file format.
+ * From an array of filters, the names are retrieved and used to populate
+ * the combo box.
+ * \param IN dialogBox
+ * \param patterns IN number of entries for combo
+ * \param filters IN
+ * \returns the newly created widget
+ */
+
+static GtkWidget *CreateFileformatSelector(struct wFilSel_t *dialogBox,
+ int patterns,
+ GtkFileFilter **filters)
+{
+ GtkWidget *hbox = gtk_hbox_new(FALSE, 12);
+ GtkWidget *text = gtk_label_new(_("Save format:"));
+ GtkWidget *combo = gtk_combo_box_text_new ();
+
+ g_signal_connect(G_OBJECT(combo),
+ "changed",
+ (GCallback)FileFormatChanged,
+ dialogBox );
+
+
+ gtk_box_pack_start (GTK_BOX(hbox),
+ text,
+ FALSE,
+ FALSE,
+ 0);
+ gtk_box_pack_end (GTK_BOX(hbox),
+ combo,
+ TRUE,
+ TRUE,
+ 0);
+ for(int i=0; i < patterns; i++ ) {
+ const char *nameOfFilter = gtk_file_filter_get_name( filters[ i ] );
+ gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(combo), nameOfFilter );
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
+
+ gtk_widget_show_all(hbox);
+
+ return(hbox);
+}
/**
* Create a new file selector. Only the internal data structures are
@@ -89,31 +157,75 @@ struct wFilSel_t * wFilSelCreate(
fs->title = strdup( title );
fs->action = action;
fs->data = data;
+ fs->pattCount = 0;
+ fs->loadPatternsAdded = FALSE;
if (pattList) {
- char * cp = strdup(pattList);
+ char * cps = strdup(pattList);
+ char *cp, *cp2;
int count = 0;
+ char *patternState, *patternState2;
//create filters for the passed filter list
// names and patterns are separated by |
- cp = strtok( cp, "|" );
- while ( cp && count < (MAX_ALLOWEDFILTERS - 1)) {
+ // filter elements are also separated by |
+ cp = cps;
+ while (cp && cp[0]) {
+ if (cp[0] == '|') {
+ count++;
+ if (count && count%2==0) {
+ cp[0] = ':'; //Replace every second "|" with ":"
+ }
+ }
+ cp++;
+ }
+ count = 0;
+ cp = cps; //Restart
+ if (opt&FS_PICTURES) { //Put first
fs->filter[ count ] = gtk_file_filter_new ();
- gtk_file_filter_set_name ( fs->filter[ count ], cp );
- cp = strtok( NULL, "|" );
- gtk_file_filter_add_pattern (fs->filter[ count ], cp );
- // the first pattern is considered to match the default extension
- if( count == 0 ) {
- fs->defaultExtension = strdup( cp );
- }
- cp = strtok( NULL, "|" );
- count++;
+ g_object_ref_sink( G_OBJECT(fs->filter[ count ] ));
+ gtk_file_filter_set_name( fs->filter[ count ], _("Image files") );
+ gtk_file_filter_add_pixbuf_formats( fs->filter[ count ]);
+ fs->pattCount = ++count;
+ }
+ cp = strtok_r( cp, ":", &patternState ); // Break up by colons
+ while ( cp && count < (MAX_ALLOWEDFILTERS - 1)) {
+ cp2 = strtok_r( cp, "|", &patternState2 );
+ if (cp2) {
+ fs->filter[ count ] = gtk_file_filter_new ();
+ gtk_file_filter_set_name ( fs->filter[ count ], cp2 );
+
+ cp2 = strtok_r( NULL, "|", &patternState2 );
+ // find multiple patterns separated by ";"
+ if (cp2) {
+ char * cp1s = strdup(cp2);
+ char *cp1;
+ char *filterState;
+
+ cp1 = cp1s;
+ cp1 = strtok_r(cp1, ";", &filterState );
+ while (cp1) {
+ gtk_file_filter_add_pattern (fs->filter[ count ], cp1 );
+ cp1 = strtok_r(NULL, ";", &filterState );
+ }
+ if (cp1s)
+ free(cp1s);
+ }
+ // the first pattern is considered to match the default extension
+ if( count == 0 && !(opt&FS_PICTURES)) {
+ fs->defaultExtension = strdup( cp2 );
+ int i = 0;
+ for (i=0; i<strlen(cp2) && cp2[i] != ' ' && cp2[i] != ';';i++) ;
+ if (i<strlen(cp2)) fs->defaultExtension[i] = '\0';
+ }
+ fs->pattCount = ++count;
+ }
+ cp = strtok_r( NULL, ":", &patternState );
}
- // finally add the all files pattern
- fs->filter[ count ] = gtk_file_filter_new ();
- gtk_file_filter_set_name( fs->filter[ count ], _("All files") );
- gtk_file_filter_add_pattern( fs->filter[ count ], "*" );
- fs->pattCount = count++;
+ if (cps)
+ free(cps);
+
+
} else {
fs->filter[ 0 ] = NULL;
fs->pattCount = 0;
@@ -145,33 +257,41 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )
(fs->mode == FS_LOAD ? GTK_STOCK_OPEN : GTK_STOCK_SAVE ), GTK_RESPONSE_ACCEPT,
NULL );
if (fs->window==0) abort();
- // get confirmation before overwritting an existing file
- gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE );
+ if ( fs->mode == FS_SAVE ) {
+ // get confirmation before overwritting an existing file
+ gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE );
+ }
- // allow selecting multiple files
- if( fs->opt & FS_MULTIPLEFILES ) {
- gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE);
- }
- // add the file filters to the dialog box
- if( fs->pattCount ) {
- for( i = 0; i <= fs->pattCount; i++ ) {
- gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] );
- }
- }
/** \todo for loading a shortcut folder could be added linking to the example directory */
}
strcpy( name, dirName );
- if( fs->mode == FS_SAVE )
- gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );
+ gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );
+ if( fs->mode == FS_SAVE || fs->mode == FS_UPDATE ) {
+ gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER(fs->window),
+ CreateFileformatSelector(fs, fs->pattCount, fs->filter ));
+ }
// Add a current folder and a shortcut to it for Load/import dialogs
if( fs->mode == FS_LOAD ) {
- gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );
gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER(fs->window), name, NULL );
+ // allow selecting multiple files
+ if( fs->opt & FS_MULTIPLEFILES ) {
+ gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE);
+ }
+ // add the file filters to the dialog box
+ if( fs->pattCount && !fs->loadPatternsAdded) {
+
+ for( i = 0; i < fs->pattCount; i++ ) {
+ gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] );
+ }
+ fs->loadPatternsAdded = TRUE;
+ }
}
- if( gtk_dialog_run( GTK_DIALOG( fs->window )) == GTK_RESPONSE_ACCEPT ) {
+ int resp = gtk_dialog_run( GTK_DIALOG( fs->window ));
+
+ if( resp == GTK_RESPONSE_ACCEPT || resp == GTK_RESPONSE_APPLY) {
char **fileNames;
GSList *fileNameList;
@@ -184,21 +304,36 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )
file = g_filename_from_uri( g_slist_nth_data( fileNameList, i ), &host, &err );
// check for presence of file extension
- // jump behind tha last directory delimiter
+ // jump behind the last directory delimiter
namePart = strrchr( file, '/' ) + 1;
// is there a dot in the last part, yes->extension present
if( !strchr( namePart, '.' ) ){
- // make room for the extension
- file = g_realloc( file, strlen(file)+strlen(fs->defaultExtension));
- strcat( file, fs->defaultExtension + 1 );
+
+ // else try to find the current filter and parse its name
+ GtkFileFilter *currentFilter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER(fs->window) );
+ if (currentFilter) {
+ const char *nameOfFilter = gtk_file_filter_get_name( currentFilter );
+ char *pattern = strdup( nameOfFilter );
+ char *extension = fs->defaultExtension;
+ char *startDelimiter = strstr( pattern, "(*." );
+
+ if(startDelimiter) {
+ char *endDelimiter = strpbrk(startDelimiter + 3, ",;) ");
+ if( endDelimiter ) {
+ *endDelimiter = '\0';
+ extension = startDelimiter + 2;
+ }
+ }
+ file = g_realloc( file, strlen(file)+strlen(extension));
+ strcat( file, extension );
+ free( pattern );
+ }
}
fileNames[ i ] = file;
g_free( g_slist_nth_data ( fileNameList, i));
}
- if (fs->data)
- strcpy( fs->data, fileNames[ 0 ] );
-
+ gtk_widget_hide( GTK_WIDGET( fs->window ));
if (fs->action) {
fs->action( g_slist_length(fileNameList), fileNames, fs->data );
}
@@ -208,8 +343,9 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )
}
free( fileNames );
g_slist_free (fileNameList);
+ } else {
+ gtk_widget_hide( GTK_WIDGET( fs->window ));
}
- gtk_widget_hide( GTK_WIDGET( fs->window ));
return 1;
}
diff --git a/app/wlib/gtklib/font.c b/app/wlib/gtklib/font.c
index 68ba87b..e2f741b 100644
--- a/app/wlib/gtklib/font.c
+++ b/app/wlib/gtklib/font.c
@@ -185,7 +185,8 @@ PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget,
int *width_p,
int *height_p,
int *ascent_p,
- int *descent_p)
+ int *descent_p,
+ int *baseline_p)
{
if (!fontInitted) {
fontInit();
@@ -214,14 +215,16 @@ PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget,
FONTSIZE_TO_PANGOSIZE(fs) * PANGO_SCALE);
pango_layout_set_font_description(layout, fontDescription);
/* get layout measures */
- pango_layout_get_pixel_size(layout, width_p, height_p);
+ pango_layout_get_size(layout, width_p, height_p);
+ *width_p = *width_p / PANGO_SCALE;
+ *height_p = *height_p / PANGO_SCALE;
context = gtk_widget_create_pango_context(widget);
metrics = pango_context_get_metrics(context, fontDescription,
pango_context_get_language(context));
- *ascent_p = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
- *descent_p = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
+ *baseline_p = pango_layout_get_baseline(layout) / PANGO_SCALE;
+ *ascent_p = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
+ *descent_p = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
pango_font_metrics_unref(metrics);
- g_object_ref_sink(context);
g_object_unref(context);
#if WLIB_FONT_DEBUG >= 3
fprintf(stderr, "font layout created:\n");
@@ -347,9 +350,9 @@ wFontSize_t wSelectedFontSize(void)
* \return describe the return value
*/
-void wSetSelectedFontSize(int size)
+void wSetSelectedFontSize(wFontSize_t size)
{
- absoluteFontSize = (wFontSize_t)size;
+ absoluteFontSize = size;
}
/**
diff --git a/app/wlib/gtklib/gtkdraw-cairo.c b/app/wlib/gtklib/gtkdraw-cairo.c
index 5042667..4498a2c 100644
--- a/app/wlib/gtklib/gtkdraw-cairo.c
+++ b/app/wlib/gtklib/gtkdraw-cairo.c
@@ -32,6 +32,9 @@
#include <gtk/gtk.h>
#include <gdk/gdk.h>
+// Trace low level drawing actions
+int iDrawLog = 0;
+
#include "gtkint.h"
#include "gdk/gdkkeysyms.h"
@@ -41,12 +44,16 @@
static long drawVerbose = 0;
+// Hack to do TempRedraw or MainRedraw
+// For Windows only
+wBool_t wDrawDoTempDraw = TRUE;
+
struct wDrawBitMap_t {
int w;
int h;
int x;
int y;
- const char * bits;
+ const unsigned char * bits;
GdkPixmap * pixmap;
GdkBitmap * mask;
};
@@ -102,64 +109,148 @@ struct wDraw_t psPrint_d;
*
*******************************************************************************/
-
-
-static GdkGC * selectGC(
- wDraw_p bd,
+static cairo_t* gtkDrawCreateCairoCursorContext(
+ wControl_p ct,
+ cairo_surface_t * surf,
wDrawWidth width,
wDrawLineType_e lineType,
wDrawColor color,
wDrawOpts opts )
{
- if(width < 0.0)
- {
- width = - width;
- }
+ cairo_t* cairo;
+
+ cairo = cairo_create(surf);
+
+ width = width ? abs(width) : 1;
+ cairo_set_line_width(cairo, width);
+
+ cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join(cairo, CAIRO_LINE_JOIN_MITER);
- if(opts & wDrawOptTemp)
+ switch(lineType)
{
- if(bd->lastColor != color || !bd->lastColorInverted)
+ case wDrawLineSolid:
{
- gdk_gc_set_foreground( bd->gc, wlibGetColor(color,FALSE) );
- bd->lastColor = color;
- bd->lastColorInverted = TRUE;
+ cairo_set_dash(cairo, 0, 0, 0);
+ break;
}
- gdk_gc_set_function( bd->gc, GDK_XOR );
- gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
- }
- else
- {
- if(bd->lastColor != color || bd->lastColorInverted)
+ case wDrawLineDash:
{
- gdk_gc_set_foreground( bd->gc, wlibGetColor(color,TRUE) );
- bd->lastColor = color;
- bd->lastColorInverted = FALSE;
+ double dashes[] = { 5, 3 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
}
- gdk_gc_set_function( bd->gc, GDK_COPY );
- if (lineType==wDrawLineDash)
+ case wDrawLineDot:
{
- gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ double dashes[] = { 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
}
- else
+ case wDrawLineDashDot:
+ {
+ double dashes[] = { 5, 2, 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
+ }
+ case wDrawLineDashDotDot:
{
- gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ double dashes[] = { 5, 2, 1, 2, 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
+ }
+ case wDrawLineCenter:
+ {
+ double dashes[] = { 8, 3, 5, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLinePhantom:
+ {
+ double dashes[] = { 8, 3, 5, 3, 5, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0.0);
+ break;
}
- gdk_gc_set_function(bd->gc, GDK_NOOP);
}
- return bd->gc;
+ GdkColor * gcolor;
+
+
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
+ gcolor = wlibGetColor(color, TRUE);
+
+ if (ct->type == B_DRAW) {
+ wDraw_p bd = (wDraw_p)ct;
+ bd->lastColor = color;
+ }
+
+ cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0);
+
+ return cairo;
+}
+
+
+wBool_t wDrawSetTempMode(
+ wDraw_p bd,
+ wBool_t bTemp )
+{
+ wBool_t ret = bd->bTempMode;
+ bd->bTempMode = bTemp;
+ if ( ret == FALSE && bTemp == TRUE ) {
+ // Main to Temp drawing
+ wDrawClearTemp( bd );
+ }
+ return ret;
}
static cairo_t* gtkDrawCreateCairoContext(
wDraw_p bd,
+ GdkDrawable * win,
wDrawWidth width,
wDrawLineType_e lineType,
wDrawColor color,
wDrawOpts opts )
{
- cairo_t* cairo = gdk_cairo_create(bd->pixmap);
+ cairo_t* cairo;
+
+ if (win)
+ cairo = gdk_cairo_create(win);
+ else {
+ if (opts & wDrawOptTemp) {
+ if ( ! bd->bTempMode )
+ printf( "Temp draw in Main Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 );
+/* Temp Draw In Main Mode:
+ You are seeing this message because there is a wDraw*() call on tempD but you are not in the context of TempRedraw()
+ Typically this happens when Cmd<Object>() is processing a C_DOWN or C_MOVE action and it writes directly to tempD
+ Instead it sould set some state which allows c_redraw to do the actual drawing
+ If you set a break point on the printf you'll see the offending wDraw*() call in the traceback
+ It should be sufficient to remove that draw code or move it to C_REDRAW
+ This is not fatal but the draw will be ineffective because the next TempRedraw() will erase the temp surface
+ before the expose event can copy (or bitblt) it
+*/
+ cairo = cairo_create(bd->temp_surface);
+ } else {
+ if ( bd->bTempMode )
+ printf( "Main draw in Temp Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 );
+/* Main Draw In Temp Mode:
+ You are seeing this message because there is a wDraw*() call on mainD but you are in the context of TempRedraw()
+ Typically this happens when C_REDRAW action calls wDraw*() on mainD, in which case it should be writing to tempD.
+ Or the wDraw*() call should be removed if it is redundant.
+ If you set a break point on the printf you'll see the offending wDraw*() call in the traceback
+ This is not fatal but could result in garbage being left on the screen if the command is cancelled.
+*/
+ cairo = gdk_cairo_create(bd->pixmap);
+ }
+ }
width = width ? abs(width) : 1;
+ if ( color == wDrawColorWhite )
+ width += 1; // Remove ghosts
cairo_set_line_width(cairo, width);
cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT);
@@ -179,24 +270,52 @@ static cairo_t* gtkDrawCreateCairoContext(
cairo_set_dash(cairo, dashes, len_dashes, 0);
break;
}
- }
+ case wDrawLineDot:
+ {
+ double dashes[] = { 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
+ }
+ case wDrawLineDashDot:
+ {
+ double dashes[] = { 5, 2, 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
+ }
+ case wDrawLineDashDotDot:
+ {
+ double dashes[] = { 5, 2, 1, 2, 1, 2 };
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0);
+ break;
+ }
+ case wDrawLineCenter:
+ {
+ double dashes[] = { 8, 3, 5, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLinePhantom:
+ {
+ double dashes[] = { 8, 3, 5, 3, 5, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cairo, dashes, len_dashes, 0.0);
+ break;
+ }
- if(opts & wDrawOptTemp)
- {
- cairo_set_source_rgba(cairo, 0, 0, 0, 0);
- cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
- }
- else
- {
- long rgbcolor = wDrawGetRGB(color);
- int r0, g0, b0;
- r0 = (int)(rgbcolor>>16)&0xFF;
- g0 = (int)(rgbcolor>>8)&0xFF;
- b0 = (int)(rgbcolor)&0xFF;
- cairo_set_source_rgb(cairo, r0/255.0, g0/255.0, b0/255.0);
-
- cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
}
+ GdkColor * gcolor;
+
+
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
+ gcolor = wlibGetColor(color, TRUE);
+
+ bd->lastColor = color;
+
+ cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0);
return cairo;
}
@@ -206,6 +325,36 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
return NULL;
}
+#ifdef CURSOR_SURFACE
+cairo_t* CreateCursorSurface(wControl_p ct, wSurface_p surface, wPos_t width, wPos_t height, wDrawColor color, wDrawOpts opts) {
+
+ cairo_t * cairo = NULL;
+
+ if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv)) {
+
+ if (surface!=NULL || surface->width != width || surface->height != height) {
+ if (surface->surface) cairo_surface_destroy(surface->surface);
+ surface->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height );
+ surface->width = width;
+ surface->height = height;
+
+ }
+
+ cairo = gtkDrawCreateCairoCursorContext(ct,surface->surface,0,wDrawLineSolid, color, opts);
+ cairo_save(cairo);
+ cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0);
+ cairo_paint(cairo);
+ cairo_restore(cairo);
+ surface->show = TRUE;
+ cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE);
+
+ }
+
+ return cairo;
+
+}
+#endif
+
void wDrawDelayUpdate(
wDraw_p bd,
wBool_t delay )
@@ -239,36 +388,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
psPrintLine( x0, y0, x1, y1, width, lineType, color, opts );
return;
}
- gc = selectGC( bd, width, lineType, color, opts );
x0 = INMAPX(bd,x0);
y0 = INMAPY(bd,y0);
x1 = INMAPX(bd,x1);
y1 = INMAPY(bd,y1);
- gdk_draw_line( bd->pixmap, gc, x0, y0, x1, y1 );
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts);
cairo_move_to(cairo, x0 + 0.5, y0 + 0.5);
cairo_line_to(cairo, x1 + 0.5, y1 + 0.5);
cairo_stroke(cairo);
gtkDrawDestroyCairoContext(cairo);
+ if (bd->widget)
+ gtk_widget_queue_draw(GTK_WIDGET(bd->widget)); //,x0,y0+1,x1,y1+1);
- if ( bd->delayUpdate || bd->widget == NULL ) return;
- width /= 2;
- if (x0 < x1) {
- update_rect.x = x0-1-width;
- update_rect.width = x1-x0+2+width+width;
- } else {
- update_rect.x = x1-1-width;
- update_rect.width = x0-x1+2+width+width;
- }
- if (y0 < y1) {
- update_rect.y = y0-1-width;
- update_rect.height = y1-y0+2+width+width;
- } else {
- update_rect.y = y1-1-width;
- update_rect.height = y0-y1+2+width+width;
- }
- gtk_widget_draw( bd->widget, &update_rect );
}
/**
@@ -299,33 +431,20 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
wDrawOpts opts )
{
int x, y, w, h;
- GdkGC * gc;
- GdkRectangle update_rect;
if ( bd == &psPrint_d ) {
psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );
return;
}
- gc = selectGC( bd, width, lineType, color, opts );
+
if (r < 6.0/75.0) return;
x = INMAPX(bd,x0-r);
y = INMAPY(bd,y0+r);
w = 2*r;
h = 2*r;
- // remove the old arc
- gdk_draw_arc( bd->pixmap, gc, FALSE, x, y, w, h, (int)((-angle0 + 90)*64.0), (int)(-angle1*64.0) );
-
- // and its center point
- if (drawCenter) {
- x = INMAPX(bd,x0);
- y = INMAPY(bd,y0);
- gdk_draw_line( bd->pixmap, gc, x - ( CENTERMARK_LENGTH/2), y, x + ( CENTERMARK_LENGTH/2), y );
- gdk_draw_line( bd->pixmap, gc, x, y - ( CENTERMARK_LENGTH/2), x, y + ( CENTERMARK_LENGTH/2));
- }
-
// now create the new arc
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts);
cairo_new_path(cairo);
// its center point marker
@@ -337,6 +456,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
cairo_move_to(cairo, INMAPX(bd, x0), INMAPY(bd, y0 - (CENTERMARK_LENGTH / 2 )));
cairo_line_to(cairo, INMAPX(bd, x0) , INMAPY(bd, y0 + (CENTERMARK_LENGTH / 2)));
cairo_new_sub_path( cairo );
+
}
// draw the curve itself
@@ -344,14 +464,10 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
cairo_stroke(cairo);
gtkDrawDestroyCairoContext(cairo);
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(bd->widget,x,y,w,h);
+
- if ( bd->delayUpdate || bd->widget == NULL) return;
- width /= 2;
- update_rect.x = x-1-width;
- update_rect.y = y-1-width;
- update_rect.width = w+2+width+width;
- update_rect.height = h+2+width+width;
- gtk_widget_draw( bd->widget, &update_rect );
}
@@ -361,28 +477,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
wDrawColor color,
wDrawOpts opts )
{
- GdkGC * gc;
GdkRectangle update_rect;
if ( bd == &psPrint_d ) {
/*psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );*/
return;
}
- gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
- gdk_draw_point( bd->pixmap, gc, INMAPX(bd, x0 ), INMAPY(bd, y0 ) );
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);
cairo_new_path(cairo);
cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), 0.75, 0, 2 * M_PI);
cairo_stroke(cairo);
gtkDrawDestroyCairoContext(cairo);
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(bd->widget,INMAPX(bd,x0-0.75),INMAPY(bd,y0+0.75),2,2);
- if ( bd->delayUpdate || bd->widget == NULL) return;
- update_rect.x = INMAPX(bd, x0 )-1;
- update_rect.y = INMAPY(bd, y0 )-1;
- update_rect.width = 2;
- update_rect.height = 2;
- gtk_widget_draw( bd->widget, &update_rect );
}
/*******************************************************************************
@@ -407,6 +516,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
int h;
gint ascent;
gint descent;
+ gint baseline;
double angle = -M_PI * a / 180.0;
if ( bd == &psPrint_d ) {
@@ -418,23 +528,27 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
y = INMAPY(bd,y);
/* draw text */
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);
cairo_save( cairo );
- cairo_translate( cairo, x, y );
- cairo_rotate( cairo, angle );
+ cairo_identity_matrix(cairo);
layout = wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s,
(int *) &w, (int *) &h,
- (int *) &ascent, (int *) &descent);
+ (int *) &ascent, (int *) &descent, (int *) &baseline);
- /* cairo does not support the old method of text removal by overwrite; force always write here and
- refresh on cancel event */
+ /* cairo does not support the old method of text removal by overwrite;
+ * if color is White, then overwrite old text with a White rectangle */
GdkColor* const gcolor = wlibGetColor(color, TRUE);
cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0);
- cairo_move_to( cairo, 0, -ascent );
+ cairo_translate( cairo, x, y );
+ cairo_rotate( cairo, angle );
+ cairo_translate( cairo, 0, -baseline);
+
+ cairo_move_to(cairo, 0, 0);
+ pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout);
wlibFontDestroyPangoLayout(layout);
cairo_restore( cairo );
@@ -446,17 +560,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
* for simplicity sake I added plain text height ascent and descent,
* mathematically correct would be to use the trigonometrical functions as well
*/
- update_rect.x = (gint) x - ascent - descent - 1;
- update_rect.y = (gint) y - (gint) ascent - 1;
- update_rect.width = (gint) (w * cos( angle ) + 2 + ascent + descent);
- update_rect.height = (gint) (h * sin( angle ) + ascent + descent + 2 );
+ update_rect.x = (gint) x - 2;
+ update_rect.y = (gint) y - (gint) (baseline + descent) - 2;
+ update_rect.width = (gint) (w * cos( angle ) + h * sin(angle))+2;
+ update_rect.height = (gint) (h * sin( angle ) + w * cos(angle))+2;
gtk_widget_draw(bd->widget, &update_rect);
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(bd->widget, update_rect.x, update_rect.y, update_rect.width, update_rect.height);
+
}
void wDrawGetTextSize(
wPos_t *w,
wPos_t *h,
wPos_t *d,
+ wPos_t *a,
wDraw_p bd,
const char * s,
wFont_p fp,
@@ -466,21 +584,31 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
int textHeight;
int ascent;
int descent;
+ int baseline;
*w = 0;
*h = 0;
+ /* draw text */
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorBlack, bd->bTempMode?wDrawOptTemp:0 );
+
+ cairo_identity_matrix(cairo);
+
wlibFontDestroyPangoLayout(
- wlibFontCreatePangoLayout(bd->widget, NULL, fp, fs, s,
+ wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s,
&textWidth, (int *) &textHeight,
- (int *) &ascent, (int *) &descent));
+ (int *) &ascent, (int *) &descent, (int *) &baseline) );
*w = (wPos_t) textWidth;
*h = (wPos_t) textHeight;
- *d = (wPos_t) textHeight-ascent;
+ *a = (wPos_t) ascent;
+ //*d = (wPos_t) textHeight-ascent;
+ *d = (wPos_t) descent;
if (debugWindow >= 3)
fprintf(stderr, "text metrics: w=%d, h=%d, d=%d\n", *w, *h, *d);
+
+ gtkDrawDestroyCairoContext(cairo);
}
@@ -490,6 +618,28 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
*
*******************************************************************************/
+static void wlibDrawFilled(
+ cairo_t * cairo,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ if ( (opt & wDrawOptTransparent) != 0 ) {
+ if ( (opt & wDrawOptTemp) == 0 ) {
+ cairo_set_source_rgb(cairo, 0,0,0);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_DIFFERENCE);
+ cairo_fill_preserve(cairo);
+ }
+ GdkColor * gcolor = wlibGetColor(color, TRUE);
+ cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
+ cairo_stroke_preserve(cairo);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 0.3);
+ }
+ cairo_fill(cairo);
+}
+
+
void wDrawFilledRectangle(
wDraw_p bd,
wPos_t x,
@@ -499,7 +649,6 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
wDrawColor color,
wDrawOpts opt )
{
- GdkGC * gc;
GdkRectangle update_rect;
if ( bd == &psPrint_d ) {
@@ -507,47 +656,46 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
return;
}
- gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
x = INMAPX(bd,x);
y = INMAPY(bd,y)-h;
- gdk_draw_rectangle( bd->pixmap, gc, TRUE, x, y, w, h );
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt);
cairo_move_to(cairo, x, y);
cairo_rel_line_to(cairo, w, 0);
cairo_rel_line_to(cairo, 0, h);
cairo_rel_line_to(cairo, -w, 0);
- cairo_fill(cairo);
+ cairo_rel_line_to(cairo, 0, -h);
+ wlibDrawFilled( cairo, color, opt );
+
gtkDrawDestroyCairoContext(cairo);
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h);
- if ( bd->delayUpdate || bd->widget == NULL) return;
- update_rect.x = x-1;
- update_rect.y = y-1;
- update_rect.width = w+2;
- update_rect.height = h+2;
- gtk_widget_draw( bd->widget, &update_rect );
}
- void wDrawFilledPolygon(
+ void wDrawPolygon(
wDraw_p bd,
wPos_t p[][2],
+ wPolyLine_e type[],
int cnt,
wDrawColor color,
- wDrawOpts opt )
+ wDrawWidth dw,
+ wDrawLineType_e lt,
+ wDrawOpts opt,
+ int fill,
+ int open )
{
- GdkGC * gc;
static int maxCnt = 0;
static GdkPoint *points;
int i;
- GdkRectangle update_rect;
if ( bd == &psPrint_d ) {
- psPrintFillPolygon( p, cnt, color, opt );
+ psPrintFillPolygon( p, type, cnt, color, opt, fill, open );
return;
}
- if (cnt > maxCnt) {
+ if (cnt > maxCnt) {
if (points == NULL)
points = (GdkPoint*)malloc( cnt*sizeof *points );
else
@@ -556,43 +704,100 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
abort();
maxCnt = cnt;
}
-
- update_rect.x = bd->w;
- update_rect.y = bd->h;
- update_rect.width = 0;
- update_rect.height = 0;
- for (i=0; i<cnt; i++) {
- points[i].x = INMAPX(bd,p[i][0]);
- points[i].y = INMAPY(bd,p[i][1]);
- if (update_rect.x > points[i].x)
- update_rect.x = points[i].x;
- if (update_rect.width < points[i].x)
- update_rect.width = points[i].x;
- if (update_rect.y > points[i].y)
- update_rect.y = points[i].y;
- if (update_rect.height < points[i].y)
- update_rect.height = points[i].y;
+ wPos_t min_x,max_x,min_y,max_y;
+ min_x = max_x = INMAPX(bd,p[0][0]);
+ min_y = max_y = INMAPY(bd,p[0][1]);
+ for (i=0; i<cnt; i++) {
+ points[i].x = INMAPX(bd,p[i][0]);
+ if (points[i].x < min_x) min_x = points[i].x;
+ if (points[i].x > max_x) max_x = points[i].x;
+ if (points[i].y > max_y) max_y = points[i].y;
+ points[i].y = INMAPY(bd,p[i][1]);
}
- update_rect.x -= 1;
- update_rect.y -= 1;
- update_rect.width -= update_rect.x-2;
- update_rect.height -= update_rect.y-2;
- gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
- gdk_draw_polygon( bd->pixmap, gc, TRUE, points, cnt );
-
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, fill?0:dw, fill?wDrawLineSolid:lt, color, opt);
+
for(i = 0; i < cnt; ++i)
{
- if(i)
+ int j = i-1;
+ int k = i+1;
+ if (j < 0) j = cnt-1;
+ if (k > cnt-1) k = 0;
+ GdkPoint mid0, mid1, mid3, mid4;
+ // save is static because of an apparent compiler bug on Linux
+ // This happens with RelWithDebInfo target
+ // If the first segment is a line then save should = points[0]
+ // However it becomes mid0 instead which causes the last corner to be misplaced.
+ static GdkPoint save;
+ double len0, len1;
+ double d0x = (points[i].x-points[j].x);
+ double d0y = (points[i].y-points[j].y);
+ double d1x = (points[k].x-points[i].x);
+ double d1y = (points[k].y-points[i].y);
+ len0 = (d0x*d0x+d0y*d0y);
+ len1 = (d1x*d1x+d1y*d1y);
+ mid0.x = (d0x/2)+points[j].x;
+ mid0.y = (d0y/2)+points[j].y;
+ mid1.x = (d1x/2)+points[i].x;
+ mid1.y = (d1y/2)+points[i].y;
+ if (type && (type[i] == wPolyLineRound) && (len1>0) && (len0>0)) {
+ double ratio = sqrt(len0/len1);
+ if (len0 < len1) {
+ mid1.x = ((d1x*ratio)/2)+points[i].x;
+ mid1.y = ((d1y*ratio)/2)+points[i].y;
+ } else {
+ mid0.x = points[i].x-(d0x/(2*ratio));
+ mid0.y = points[i].y-(d0y/(2*ratio));
+ }
+ }
+ mid3.x = (points[i].x-mid0.x)/2+mid0.x;
+ mid3.y = (points[i].y-mid0.y)/2+mid0.y;
+ mid4.x = (mid1.x-points[i].x)/2+points[i].x;
+ mid4.y = (mid1.y-points[i].y)/2+points[i].y;
+ points[i].x = round(points[i].x)+0.5;
+ points[i].y = round(points[i].y)+0.5;
+ mid0.x = round(mid0.x)+0.5;
+ mid0.y = round(mid0.y)+0.5;
+ mid1.x = round(mid1.x)+0.5;
+ mid1.y = round(mid1.y)+0.5;
+ mid3.x = round(mid3.x)+0.5;
+ mid3.y = round(mid3.y)+0.5;
+ mid4.x = round(mid4.x)+0.5;
+ mid4.y = round(mid4.y)+0.5;
+ if(i==0) {
+ if (!type || type[i] == wPolyLineStraight || open) {
+ cairo_move_to(cairo, points[i].x, points[i].y);
+ save = points[0];
+ } else {
+ cairo_move_to(cairo, mid0.x, mid0.y);
+ if (type[i] == 1)
+ cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y);
+ else
+ cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y);
+ save = mid0;
+ }
+ } else if (!type || type[i] == wPolyLineStraight || (open && (i==cnt-1))) {
cairo_line_to(cairo, points[i].x, points[i].y);
- else
- cairo_move_to(cairo, points[i].x, points[i].y);
+ } else {
+ cairo_line_to(cairo, mid0.x, mid0.y);
+ if (type[i] == wPolyLineSmooth)
+ cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y);
+ else
+ cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y);
+ }
+ if ((i==cnt-1) && !open) {
+ cairo_line_to(cairo, save.x, save.y);
+ }
+ }
+ if (fill && !open) {
+ wlibDrawFilled( cairo, color, opt );
+ } else {
+ cairo_stroke(cairo);
}
- cairo_fill(cairo);
gtkDrawDestroyCairoContext(cairo);
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),min_x,min_y,max_x-min_y,max_y-min_y);
- if ( bd->delayUpdate || bd->widget == NULL) return;
- gtk_widget_draw( bd->widget, &update_rect );
}
void wDrawFilledCircle(
@@ -603,60 +808,64 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
wDrawColor color,
wDrawOpts opt )
{
- GdkGC * gc;
int x, y, w, h;
- GdkRectangle update_rect;
if ( bd == &psPrint_d ) {
psPrintFillCircle( x0, y0, r, color, opt );
return;
}
- gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
x = INMAPX(bd,x0-r);
y = INMAPY(bd,y0+r);
w = 2*r;
h = 2*r;
- gdk_draw_arc( bd->pixmap, gc, TRUE, x, y, w, h, 0, 360*64 );
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt);
cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), r, 0, 2 * M_PI);
- cairo_fill(cairo);
+ wlibDrawFilled( cairo, color, opt );
gtkDrawDestroyCairoContext(cairo);
- if ( bd->delayUpdate || bd->widget == NULL) return;
- update_rect.x = x-1;
- update_rect.y = y-1;
- update_rect.width = w+2;
- update_rect.height = h+2;
- gtk_widget_draw( bd->widget, &update_rect );
+ if (bd->widget)
+ gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h);
}
+ void wDrawClearTemp(wDraw_p bd) {
+ //Wipe out temp space with 0 alpha (transparent)
+
+ static long cDCT = 0;
+ if ( iDrawLog )
+ printf( "wDrawClearTemp %ld\n", cDCT++ );
+ cairo_t* cairo = cairo_create(bd->temp_surface);
+
+ cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0);
+ cairo_set_operator (cairo, CAIRO_OPERATOR_SOURCE);
+ cairo_move_to(cairo, 0, 0);
+ cairo_rel_line_to(cairo, bd->w, 0);
+ cairo_rel_line_to(cairo, 0, bd->h);
+ cairo_rel_line_to(cairo, -bd->w, 0);
+ cairo_fill(cairo);
+ cairo_destroy(cairo);
+
+ if (bd->widget && !bd->delayUpdate)
+ gtk_widget_queue_draw(bd->widget);
+ }
void wDrawClear(
wDraw_p bd )
{
- GdkGC * gc;
- GdkRectangle update_rect;
- gc = selectGC( bd, 0, wDrawLineSolid, wDrawColorWhite, 0 );
- gdk_draw_rectangle(bd->pixmap, gc, TRUE, 0, 0, bd->w, bd->h);
-
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, wDrawColorWhite, 0);
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, 0);
cairo_move_to(cairo, 0, 0);
cairo_rel_line_to(cairo, bd->w, 0);
cairo_rel_line_to(cairo, 0, bd->h);
cairo_rel_line_to(cairo, -bd->w, 0);
cairo_fill(cairo);
+ if (bd->widget)
+ gtk_widget_queue_draw(bd->widget);
gtkDrawDestroyCairoContext(cairo);
- if ( bd->delayUpdate || bd->widget == NULL) return;
- update_rect.x = 0;
- update_rect.y = 0;
- update_rect.width = bd->w;
- update_rect.height = bd->h;
- gtk_widget_draw( bd->widget, &update_rect );
+ wDrawClearTemp(bd);
}
void * wDrawGetContext(
@@ -678,7 +887,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
int h,
int x,
int y,
- const char * fbits )
+ const unsigned char * fbits )
{
wDrawBitMap_p bm;
@@ -700,72 +909,107 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
wDrawColor color,
wDrawOpts opts )
{
- //GdkGC * gc;
- GdkRectangle update_rect;
int i, j, wb;
wPos_t xx, yy;
wControl_p b;
- GdkDrawable * gdk_window;
+ wWin_p win;
+ GdkDrawable * gdk_drawable, * cairo_surface;
+ GtkWidget * widget = bd->widget;
+
+ static long cDBM = 0;
+ if ( iDrawLog )
+ printf( "wDrawBitMap %ld\n", cDBM++ );
x = INMAPX( bd, x-bm->x );
y = INMAPY( bd, y-bm->y )-bm->h;
wb = (bm->w+7)/8;
- //gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
- cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts);
+
+ cairo_t* cairo;
+
+#ifdef CURSOR_SURFACE
+ if (opts&wDrawOptCursorRmv) color = wDrawColorWhite; //Wipeout existing cursor draw (simplistic first)
+
+
+ if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) {
+
+ cairo = CreateCursorSurface((wControl_p)bd,&bd->cursor_surface, bd->w, bd->h, color, opts);
+
+ if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) {
+ bd->cursor_surface.show = FALSE;
+ } else bd->cursor_surface.show = TRUE;
+
+ widget = bd->widget;
+
+
+ } else {
+ cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);
+ widget = bd->widget;
+ }
+
+ GtkWidget * new_widget = widget;
+ GdkGC * gc = NULL;
+ GdkWindow * gdk_window = NULL;
+
+ win = bd->parent;
+#endif
+ cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);
+
for ( i=0; i<bm->w; i++ )
for ( j=0; j<bm->h; j++ )
if ( bm->bits[ j*wb+(i>>3) ] & (1<<(i&07)) ) {
xx = x+i;
yy = y+j;
+#ifdef CURSOR_SURFACE
if ( 0 <= xx && xx < bd->w &&
0 <= yy && yy < bd->h ) {
- gdk_window = bd->pixmap;
b = (wControl_p)bd;
} else if ( (opts&wDrawOptNoClip) != 0 ) {
xx += bd->realX;
yy += bd->realY;
b = wlibGetControlFromPos( bd->parent, xx, yy );
- if ( b ) {
- if ( b->type == B_DRAW )
- gdk_window = ((wDraw_p)b)->pixmap;
- else
- gdk_window = b->widget->window;
+ if ( b) {
xx -= b->realX;
yy -= b->realY;
+ new_widget = b->widget;
} else {
- gdk_window = bd->parent->widget->window;
+ new_widget = bd->parent->widget;
}
} else {
continue;
}
-/*printf( "gdk_draw_point( %ld, gc, %d, %d )\n", (long)gdk_window, xx, yy );*/
- //gdk_draw_point( gdk_window, gc, xx, yy );
- cairo_rectangle(cairo, xx-0.5, yy-0.5, 1, 1);
- cairo_fill(cairo);
- if ( b && b->type == B_DRAW ) {
- update_rect.x = xx-1;
- update_rect.y = yy-1;
- update_rect.width = 3;
- update_rect.height = 3;
- gtk_widget_draw( b->widget, &update_rect );
+
+ if (new_widget != widget) {
+ if (cairo)
+ cairo_destroy(cairo);
+ cairo = NULL;
+ if (widget && (widget != bd->parent->widget))
+ gtk_widget_queue_draw(GTK_WIDGET(widget));
+ if ( (opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) {
+ if (!b) b = (wControl_p)(bd->parent->widget);
+ cairo = CreateCursorSurface(b,&b->cursor_surface, b->w, b->h, color, opts);
+ widget = b->widget;
+ gc = NULL;
+ if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit))
+ b->cursor_surface.show = FALSE;
+ else
+ b->cursor_surface.show = TRUE;
+ } else {
+ continue;
+ }
+ widget = new_widget;
}
- }
- gtkDrawDestroyCairoContext(cairo);
-#ifdef LATER
- gdk_draw_pixmap(bd->pixmap, gc,
- bm->pixmap,
- 0, 0,
- x, y,
- bm->w, bm->h );
+ if ((opts&wDrawOptCursorQuit) || (opts&wDrawOptCursorQuit) ) continue;
#endif
- if ( bd->delayUpdate || bd->widget == NULL) return;
+ cairo_rectangle(cairo, xx, yy, 1, 1);
+ cairo_fill(cairo);
+ }
+
+ cairo_destroy(cairo);
+
+ if (widget && !bd->delayUpdate)
+ gtk_widget_queue_draw_area(GTK_WIDGET(widget), x, y, bm->w, bm->h);
- update_rect.x = x;
- update_rect.y = y;
- update_rect.width = bm->w;
- update_rect.height = bm->h;
- gtk_widget_draw( bd->widget, &update_rect );
}
@@ -780,19 +1024,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
void wDrawSaveImage(
wDraw_p bd )
{
+ cairo_t * cr;
if ( bd->pixmapBackup ) {
gdk_pixmap_unref( bd->pixmapBackup );
}
bd->pixmapBackup = gdk_pixmap_new( bd->widget->window, bd->w, bd->h, -1 );
- selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
- gdk_gc_set_function(bd->gc, GDK_COPY);
+ cr = gdk_cairo_create(bd->pixmapBackup);
+ gdk_cairo_set_source_pixmap(cr, bd->pixmap, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ cr = NULL;
- gdk_draw_pixmap( bd->pixmapBackup, bd->gc,
- bd->pixmap,
- 0, 0,
- 0, 0,
- bd->w, bd->h );
}
@@ -802,14 +1046,13 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
GdkRectangle update_rect;
if ( bd->pixmapBackup ) {
- selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
- gdk_gc_set_function(bd->gc, GDK_COPY);
+ cairo_t * cr;
+ cr = gdk_cairo_create(bd->pixmap);
+ gdk_cairo_set_source_pixmap(cr, bd->pixmapBackup, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
- gdk_draw_pixmap( bd->pixmap, bd->gc,
- bd->pixmapBackup,
- 0, 0,
- 0, 0,
- bd->w, bd->h );
+ cr = NULL;
if ( bd->delayUpdate || bd->widget == NULL ) return;
update_rect.x = 0;
@@ -845,6 +1088,9 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
if (bd->pixmap)
gdk_pixmap_unref( bd->pixmap );
bd->pixmap = gdk_pixmap_new( bd->widget->window, w, h, -1 );
+ if (bd->temp_surface)
+ cairo_surface_destroy( bd->temp_surface);
+ bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w,h );
wDrawClear( bd );
if (!redraw)
@@ -914,13 +1160,37 @@ static gint draw_expose_event(
GdkEventExpose *event,
wDraw_p bd)
{
- gdk_draw_pixmap(widget->window,
- widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
- bd->pixmap,
- event->area.x, event->area.y,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- return FALSE;
+ static long cDEE = 0;
+ if ( iDrawLog )
+ printf( "draw_expose_event %ld %dx%d+%dx%d %dx%d+%dx%d\n", cDEE++,
+ event->area.x, event->area.y, event->area.width, event->area.height,
+ 0, bd->w, 0, bd->h );
+
+ cairo_t* cairo = gdk_cairo_create (widget->window);
+ gdk_cairo_set_source_pixmap(cairo,bd->pixmap,0,0);
+ cairo_rectangle(cairo,event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE);
+ cairo_fill(cairo);
+
+ cairo_set_source_surface(cairo,bd->temp_surface,0,0);
+ cairo_rectangle(cairo,event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_set_operator(cairo,CAIRO_OPERATOR_OVER);
+ cairo_fill(cairo);
+
+#ifdef CURSOR_SURFACE
+ if (bd->cursor_surface.surface && bd->cursor_surface.show) {
+ cairo_set_source_surface(cairo,bd->cursor_surface.surface,0,0);
+ cairo_set_operator(cairo,CAIRO_OPERATOR_OVER);
+ cairo_rectangle(cairo,event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill(cairo);
+ }
+#endif
+ cairo_destroy(cairo);
+
+ return TRUE;
}
@@ -929,32 +1199,113 @@ static gint draw_configure_event(
GdkEventConfigure *event,
wDraw_p bd)
{
- return FALSE;
+ return TRUE;
}
-static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown" };
+static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown", "DblL", "ModK", "ScrU", "ScrD", "ScrL", "ScrR" };
/**
* Handler for scroll events, ie mouse wheel activity
*/
+static int scrollTimer;
+static int timer_busy_count;
+static wAction_t lastAction;
+
+static int ScrollTimerPop(wDraw_p bd) {
+
+ if (timer_busy_count>1) {
+ timer_busy_count = 0;
+ scrollTimer = 0;
+ } else {
+ timer_busy_count++;
+ return TRUE;
+ }
+ if (drawVerbose >= 2)
+ printf( "%s-Pop\n", actionNames[lastAction] );
+ bd->action( bd, bd->context, lastAction, 0, 0 );
+
+ return FALSE;
+}
+
+
static gint draw_scroll_event(
GtkWidget *widget,
GdkEventScroll *event,
wDraw_p bd)
{
wAction_t action;
+ static int oldEventX = 0;
+ static int oldEventY = 0;
+ static int newEventX = 0;
+ static int newEventY = 0;
+
+ if (event->state & (GDK_SHIFT_MASK|GDK_BUTTON2_MASK|GDK_MOD1_MASK)) {
+
+ newEventX = OUTMAPX(bd, event->x);
+ newEventY = OUTMAPY(bd, event->y);
+ oldEventX = OUTMAPX(bd, event->x_root);
+ oldEventY = OUTMAPX(bd, event->y_root);
+
+ switch( event->direction ) {
+ case GDK_SCROLL_UP:
+ if (event->state & GDK_CONTROL_MASK)
+ action = wActionScrollRight;
+ else
+ action = wActionScrollUp;
+ break;
+ case GDK_SCROLL_DOWN:
+ if (event->state & GDK_CONTROL_MASK)
+ action = wActionScrollLeft;
+ else
+ action = wActionScrollDown;
+ break;
+ case GDK_SCROLL_LEFT:
+ action = wActionScrollLeft;
+ break;
+ case GDK_SCROLL_RIGHT:
+ action = wActionScrollRight;
+ break;
+ default:
+ return TRUE;
+ break;
+ }
- switch( event->direction ) {
- case GDK_SCROLL_UP:
- action = wActionWheelUp;
- break;
- case GDK_SCROLL_DOWN:
- action = wActionWheelDown;
- break;
- default:
- action = 0;
- break;
+ if (drawVerbose >= 2)
+ printf( "%sNew[%dx%d]Delta[%dx%d]\n", actionNames[action],
+ newEventX, newEventY, oldEventX, oldEventY );
+
+
+
+ if (scrollTimer) { // Already have a timer
+ lastAction = action;
+ return TRUE;
+ } else {
+ lastAction = action;
+ timer_busy_count = 0;
+ scrollTimer = g_timeout_add(25,(GSourceFunc)ScrollTimerPop,bd); // 25ms delay
+ return TRUE;
+ }
+
+
+ } else {
+
+ switch( event->direction ) {
+ case GDK_SCROLL_UP:
+ action = wActionWheelUp;
+ break;
+ case GDK_SCROLL_DOWN:
+ action = wActionWheelDown;
+ break;
+ case GDK_SCROLL_LEFT:
+ return TRUE;
+ break;
+ case GDK_SCROLL_RIGHT:
+ return TRUE;
+ break;
+ default:
+ break;
+ }
}
if (action != 0) {
@@ -973,7 +1324,7 @@ static gint draw_leave_event(
GdkEvent * event )
{
wlibHelpHideBalloon();
- return FALSE;
+ return TRUE;
}
@@ -996,6 +1347,7 @@ static gint draw_button_event(
switch ( event->button ) {
case 1: /* left mouse button */
action = event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp;
+ if (event->type==GDK_2BUTTON_PRESS) action = wActionLDownDouble;
/*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp, bd->lastX, bd->lastY );*/
break;
case 3: /* right mouse button */
@@ -1050,6 +1402,35 @@ static gint draw_motion_event(
return TRUE;
}
+static gint draw_char_release_event(
+ GtkWidget * widget,
+ GdkEventKey *event,
+ wDraw_p bd )
+{
+ GdkModifierType modifiers;
+ guint key = event->keyval;
+ wModKey_e modKey = wModKey_None;
+ switch (key) {
+ case GDK_KEY_Alt_L: modKey = wModKey_Alt; break;
+ case GDK_KEY_Alt_R: modKey = wModKey_Alt; break;
+ case GDK_KEY_Shift_L: modKey = wModKey_Shift; break;
+ case GDK_KEY_Shift_R: modKey = wModKey_Shift; break;
+ case GDK_KEY_Control_L: modKey = wModKey_Ctrl; break;
+ case GDK_KEY_Control_R: modKey = wModKey_Ctrl; break;
+ default: ;
+ }
+
+ if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) {
+ bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY );
+ if (!(bd->option & BD_NOFOCUS))
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ return FALSE;
+}
+
static gint draw_char_event(
GtkWidget * widget,
@@ -1059,6 +1440,7 @@ static gint draw_char_event(
GdkModifierType modifiers;
guint key = event->keyval;
wAccelKey_e extKey = wAccelKey_None;
+ wModKey_e modKey = wModKey_None;
switch (key) {
case GDK_KEY_Escape: key = 0x1B; break;
case GDK_KEY_Return:
@@ -1092,17 +1474,37 @@ static gint draw_char_event(
case GDK_KEY_F10: extKey = wAccelKey_F10; break;
case GDK_KEY_F11: extKey = wAccelKey_F11; break;
case GDK_KEY_F12: extKey = wAccelKey_F12; break;
- default: ;
+ case GDK_KEY_Alt_L: modKey = wModKey_Alt; break;
+ case GDK_KEY_Alt_R: modKey = wModKey_Alt; break;
+ case GDK_KEY_Shift_L: modKey = wModKey_Shift; break;
+ case GDK_KEY_Shift_R: modKey = wModKey_Shift; break;
+ case GDK_KEY_Control_L: modKey = wModKey_Ctrl; break;
+ case GDK_KEY_Control_R: modKey = wModKey_Ctrl; break;
+ default: ;
}
if (extKey != wAccelKey_None) {
if ( wlibFindAccelKey( event ) == NULL ) {
bd->action( bd, bd->context, wActionExtKey + ((int)extKey<<8), bd->lastX, bd->lastY );
}
+ if (!(bd->option & BD_NOFOCUS))
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+ } else if ((key >=wAccelKey_Up) && (key<=wAccelKey_Left) && bd->action) {
+ bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY );
+ if (!(bd->option & BD_NOFOCUS))
+ gtk_widget_grab_focus( bd->widget );
return TRUE;
} else if (key <= 0xFF && (event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 && bd->action) {
bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY );
+ if (!(bd->option & BD_NOFOCUS))
+ gtk_widget_grab_focus( bd->widget );
return TRUE;
+ } else if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) {
+ bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY );
+ if (!(bd->option & BD_NOFOCUS))
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
} else {
return FALSE;
}
@@ -1140,6 +1542,7 @@ int xw, xh, cw, ch;
bd->context = context;
bd->redraw = redraw;
bd->action = action;
+ bd->bTempMode = FALSE;
wlibComputePos( (wControl_p)bd );
bd->widget = gtk_drawing_area_new();
@@ -1159,6 +1562,8 @@ int xw, xh, cw, ch;
(GtkSignalFunc) draw_scroll_event, bd);
gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_press_event",
(GtkSignalFunc) draw_char_event, bd);
+ gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_release_event",
+ (GtkSignalFunc) draw_char_release_event, bd);
gtk_signal_connect (GTK_OBJECT (bd->widget), "leave_notify_event",
(GtkSignalFunc) draw_leave_event, bd);
gtk_widget_set_can_focus(bd->widget,!(option & BD_NOFOCUS));
@@ -1168,7 +1573,7 @@ int xw, xh, cw, ch;
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
-/* | GDK_SCROLL_MASK */
+ | GDK_SCROLL_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
| GDK_KEY_PRESS_MASK
@@ -1182,6 +1587,8 @@ int xw, xh, cw, ch;
wlibControlGetSize( (wControl_p)bd );
gtk_widget_realize( bd->widget );
bd->pixmap = gdk_pixmap_new( bd->widget->window, width, height, -1 );
+ bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height );
+ wDrawClear(bd);
bd->gc = gdk_gc_new( parent->gtkwin->window );
gdk_gc_copy( bd->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
{
@@ -1219,6 +1626,7 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int arg )
bd->maxH = bd->h = h;
bd->pixmap = gdk_pixmap_new( gtkMainW->widget->window, w, h, -1 );
+ bd->widget = gtk_pixmap_new(bd->pixmap, NULL);
if ( bd->pixmap == NULL ) {
wNoticeEx( NT_ERROR, "CreateBitMap: pixmap_new failed", "Ok", NULL );
return FALSE;
@@ -1242,3 +1650,76 @@ wBool_t wBitMapDelete( wDraw_p d )
return TRUE;
}
+/*******************************************************************************
+ *
+ * Background
+ *
+ ******************************************************************************/
+int wDrawSetBackground( wDraw_p bd, char * path, char ** error) {
+
+ GError *err = NULL;
+
+ if (bd->background) {
+ g_object_unref(bd->background);
+ }
+
+ if (path) {
+ bd->background = gdk_pixbuf_new_from_file (path, &err);
+ if (!bd->background) {
+ *error = err->message;
+ return -1;
+ }
+ } else {
+ bd->background = NULL;
+ return 1;
+ }
+ return 0;
+
+}
+
+void wDrawShowBackground( wDraw_p bd, wPos_t pos_x, wPos_t pos_y, wPos_t size, wAngle_t angle, int screen) {
+
+ if (bd->background) {
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, bd->bTempMode?wDrawOptTemp:0 );
+ cairo_save(cairo);
+ int pixels_width = gdk_pixbuf_get_width(bd->background);
+ int pixels_height = gdk_pixbuf_get_height(bd->background);
+ double scale;
+ double posx,posy,width,sized;
+ posx = (double)pos_x;
+ posy = (double)pos_y;
+ if (size == 0) {
+ scale = 1.0;
+ } else {
+ sized = (double)size;
+ width = (double)pixels_width;
+ scale = sized/width;
+ }
+ cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
+ double rad = M_PI*(angle/180);
+ posy = (double)bd->h-((pixels_height*fabs(cos(rad))+pixels_width*fabs(sin(rad)))*scale)-posy;
+ //width = (double)(pixels_width*scale);
+ //height = (double)(pixels_height*scale);
+ cairo_translate(cairo,posx,posy);
+ cairo_scale(cairo, scale, scale);
+ cairo_translate(cairo, fabs(pixels_width/2.0*cos(rad))+fabs(pixels_height/2.0*sin(rad)),
+ fabs(pixels_width/2.0*sin(rad))+fabs(pixels_height/2.0*cos(rad)));
+ cairo_rotate(cairo, M_PI*(angle/180.0));
+ // We need to clip around the image, or cairo will paint garbage data
+ cairo_rectangle(cairo, -pixels_width/2.0, -pixels_height/2.0, pixels_width, pixels_height);
+ cairo_clip(cairo);
+ gdk_cairo_set_source_pixbuf(cairo, bd->background, -pixels_width/2.0, -pixels_height/2.0);
+ cairo_pattern_t *mask = cairo_pattern_create_rgba (1.0,1.0,1.0,(100.0-screen)/100.0);
+ cairo_mask(cairo,mask);
+ cairo_pattern_destroy(mask);
+ cairo_restore(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ gtk_widget_queue_draw(bd->widget);
+ }
+
+}
+
+
+
+
diff --git a/app/wlib/gtklib/gtkint.h b/app/wlib/gtklib/gtkint.h
index 2e0511a..410fd7f 100644
--- a/app/wlib/gtklib/gtkint.h
+++ b/app/wlib/gtklib/gtkint.h
@@ -32,7 +32,9 @@
#define strcasecmp _stricmp
#endif
+#ifndef MISC_H
#include "dynarr.h"
+#endif
#define BORDERSIZE (4)
#define LABEL_OFFSET (3)
@@ -40,6 +42,16 @@
extern wWin_p gtkMainW;
+#ifdef CURSOR_SURFACE
+typedef struct {
+ cairo_surface_t* surface;
+ wPos_t width;
+ wPos_t height;
+ wBool_t show;
+} wCursorSurface_t, * wSurface_p;
+#endif
+
+
typedef enum {
W_MAIN, W_POPUP,
B_BUTTON, B_CANCEL, B_POPUP, B_TEXT, B_INTEGER, B_FLOAT,
@@ -59,6 +71,7 @@ typedef void (*setTriggerCallback_p)( wControl_p b );
wWin_p parent; \
wPos_t origX, origY; \
wPos_t realX, realY; \
+ wPos_t default_size_x, default_size_y; \
wPos_t labelW; \
wPos_t w, h; \
int maximize_initially; \
@@ -68,6 +81,8 @@ typedef void (*setTriggerCallback_p)( wControl_p b );
GtkWidget * widget; \
GtkWidget * label; \
doneProcCallback_p doneProc; \
+ /* CURSOR_SURFACE wCursorSurface_t cursor_surface;*/ \
+ wBool_t outline; \
void * data;
struct wWin_t {
@@ -171,6 +186,7 @@ typedef struct {
GdkColor *wlibGetColor(wDrawColor color, wBool_t normal);
/* control.c */
+wBool_t wControlExpose (GtkWidget * widget, GdkEventExpose * event, wControl_p b);
/* droplist.c */
enum columns {
@@ -191,7 +207,7 @@ wList_p wDropListCreate(wWin_p parent, wPos_t x, wPos_t y, const char *helpStr,
/* filesel.c */
/* font.c */
-PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget, void *cairo, wFont_p fp, wFontSize_t fs, const char *s, int *width_p, int *height_p, int *ascent_p, int *descent_p);
+PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget, void *cairo, wFont_p fp, wFontSize_t fs, const char *s, int *width_p, int *height_p, int *ascent_p, int *descent_p, int *baseline_p);
void wlibFontDestroyPangoLayout(PangoLayout *layout);
const char *wlibFontTranslate(wFont_p fp);
@@ -255,6 +271,7 @@ struct wDraw_t {
GdkPixmap * pixmap;
GdkPixmap * pixmapBackup;
+ cairo_surface_t * temp_surface;
double dpi;
@@ -273,6 +290,9 @@ struct wDraw_t {
wBool_t delayUpdate;
cairo_t *printContext;
cairo_surface_t *curPrintSurface;
+ GdkPixbuf * background;
+
+ wBool_t bTempMode;
};
void WlibApplySettings(GtkPrintOperation *op);
@@ -280,7 +300,7 @@ void WlibSaveSettings(GtkPrintOperation *op);
void psPrintLine(wPos_t x0, wPos_t y0, wPos_t x1, wPos_t y1, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts);
void psPrintArc(wPos_t x0, wPos_t y0, wPos_t r, double angle0, double angle1, wBool_t drawCenter, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts);
void psPrintFillRectangle(wPos_t x0, wPos_t y0, wPos_t x1, wPos_t y1, wDrawColor color, wDrawOpts opts);
-void psPrintFillPolygon(wPos_t p[][2], int cnt, wDrawColor color, wDrawOpts opts);
+void psPrintFillPolygon(wPos_t p[][2], wPolyLine_e type[], int cnt, wDrawColor color, wDrawOpts opts, int fill, int open);
void psPrintFillCircle(wPos_t x0, wPos_t y0, wPos_t r, wDrawColor color, wDrawOpts opts);
void psPrintString(wPos_t x, wPos_t y, double a, char *s, wFont_p fp, double fs, wDrawColor color, wDrawOpts opts);
static void WlibGetPaperSize(void);
diff --git a/app/wlib/gtklib/help.c b/app/wlib/gtklib/help.c
index dbb69f6..8f2766d 100644
--- a/app/wlib/gtklib/help.c
+++ b/app/wlib/gtklib/help.c
@@ -28,9 +28,12 @@
#include <gtk/gtk.h>
#include <gdk/gdk.h>
+#include "misc.h"
+
#include "gtkint.h"
#include "i18n.h"
+
/**
* Handle the commands issued from the Help drop-down. Currently, we only have a table
* of contents, but search etc. might be added in the future.
@@ -44,11 +47,19 @@ DoHelpMenu(void *data)
{
int func = (intptr_t)data;
+ const char * topic;
+
switch (func) {
case 1:
wHelp("index");
break;
+ case 3:
+ topic = GetCurCommandName();
+ if (topic && topic[0])
+ wHelp(topic);
+ break;
+
default:
break;
}
@@ -56,6 +67,10 @@ DoHelpMenu(void *data)
return;
}
+void wDoAccelHelp(wAccelKey_e key, void * context) {
+ DoHelpMenu(context);
+}
+
/**
* Add the entries for Help to the drop-down.
*
@@ -66,4 +81,5 @@ DoHelpMenu(void *data)
void wMenuAddHelp(wMenu_p m)
{
wMenuPushCreate(m, NULL, _("&Contents"), 0, DoHelpMenu, (void*)1);
+ wMenuPushCreate(m, NULL, _("Co&mmand Context help"), 0, DoHelpMenu, (void*)3);
}
diff --git a/app/wlib/gtklib/ixhelp.c b/app/wlib/gtklib/ixhelp.c
index f1e3983..5079f61 100644
--- a/app/wlib/gtklib/ixhelp.c
+++ b/app/wlib/gtklib/ixhelp.c
@@ -404,6 +404,13 @@ void wHelp(const char * topic)
{
char *htmlFile;
+ //Take off any topic characters after a '-'
+
+ if (!topic || !topic[0]) return;
+
+
+ if (!CheckHelpTopicExists(topic)) return;
+
if (!wHelpWindow) {
directory = malloc(BUFSIZ);
assert(directory != NULL);
@@ -417,6 +424,7 @@ void wHelp(const char * topic)
/* need space for the 'html' extension plus dot plus \0 */
htmlFile = malloc(strlen(topic) + 6);
+
assert(htmlFile != NULL);
sprintf(htmlFile, "%s.html", topic);
@@ -424,4 +432,6 @@ void wHelp(const char * topic)
load_into_view(htmlFile, MAIN_VIEW);
gtk_widget_show_all(wHelpWindow);
gtk_window_present(GTK_WINDOW(wHelpWindow));
+
+ free(htmlFile);
}
diff --git a/app/wlib/gtklib/list.c b/app/wlib/gtklib/list.c
index 8e99efe..ac66aba 100644
--- a/app/wlib/gtklib/list.c
+++ b/app/wlib/gtklib/list.c
@@ -238,6 +238,7 @@ wIndex_t wListGetValues(
if (bl->type == B_DROPLIST && bl->editted) {
entry_value = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(
bl->widget))));
+ item_data = NULL;
inx = bl->last = -1;
} else {
inx = bl->last;
@@ -404,6 +405,8 @@ void wListDelete(
NULL,
inx);
gtk_list_store_remove(b->listStore, &iter);
+
+
b->count--;
}
@@ -486,7 +489,7 @@ wIndex_t wListAddValue(
wlibTreeViewAddRow(b, (char *)labelStr, bm, id_p);
}
- free(id_p->label);
+ //free(id_p->label);
b->count++;
b->recursion--;
diff --git a/app/wlib/gtklib/liststore.c b/app/wlib/gtklib/liststore.c
index 820366a..088bf33 100644
--- a/app/wlib/gtklib/liststore.c
+++ b/app/wlib/gtklib/liststore.c
@@ -127,6 +127,8 @@ wlibListStoreClear(GtkListStore *listStore)
id_p = wlibListStoreGetContext(listStore, i++);
while (id_p) {
+ if (id_p->label)
+ g_free(id_p->label);
g_free(id_p);
id_p = wlibListStoreGetContext(listStore, i++);
}
diff --git a/app/wlib/gtklib/menu.c b/app/wlib/gtklib/menu.c
index d19805a..79695d4 100644
--- a/app/wlib/gtklib/menu.c
+++ b/app/wlib/gtklib/menu.c
@@ -555,7 +555,7 @@ wMenuList_p wMenuListCreate(
* behind it. In case the maximum number of items is reached the last item is removed.
*
* \param ml IN handle for the menu list - the placeholder item
- * \param index IN currently ignored
+ * \param index IN position of new menu item
* \param labelStr IN the menu label for the new item
* \param data IN application data for the new item
* \return
@@ -611,7 +611,11 @@ void wMenuListAdd(
g_object_set_data( G_OBJECT(MMENUITEM( mi )), WLISTITEM, mi );
// add the item to the menu
- gtk_menu_shell_insert((GtkMenuShell *)(MPARENT( ml )->menu), MMENUITEM( mi ), i + 1 );
+ if ( index < 0 )
+ index = 0;
+ if ( index >= ml->count )
+ index = ml->count - 1;
+ gtk_menu_shell_insert((GtkMenuShell *)(MPARENT( ml )->menu), MMENUITEM( mi ), i + index + 1 );
g_signal_connect( GTK_OBJECT(MMENUITEM( mi )), "activate", G_CALLBACK(pushMenuList), mi );
gtk_widget_show(MMENUITEM( mi ));
diff --git a/app/wlib/gtklib/notice.c b/app/wlib/gtklib/notice.c
index b72afd6..0134b4f 100644
--- a/app/wlib/gtklib/notice.c
+++ b/app/wlib/gtklib/notice.c
@@ -58,8 +58,13 @@ static void doNotice(
GtkWidget * widget,
long value)
{
- noticeValue = value;
- gtk_widget_destroy(noticeW.win);
+ if (value != 2) {
+ // event not from from closing the window but from a button press
+ // Close the Notice dialog
+ gtk_widget_destroy(noticeW.win);
+ // Remember the button
+ noticeValue = value;
+ }
wlibDoModal(NULL, FALSE);
}
@@ -106,6 +111,8 @@ int wNoticeEx(int type,
parent = GTK_WINDOW(gtkMainW->gtkwin);
}
+ wDestroySplash();
+
dialog = gtk_message_dialog_new(parent,
GTK_DIALOG_DESTROY_WITH_PARENT,
flag,
@@ -113,6 +120,8 @@ int wNoticeEx(int type,
"%s", msg);
gtk_window_set_title(GTK_WINDOW(dialog), headline);
+ gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+
res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
@@ -174,6 +183,7 @@ int wNotice3(
char *can = NULL;
char *alt = NULL;
+ wDestroySplash();
nw->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -243,6 +253,9 @@ int wNotice3(
}
}
+ g_signal_connect(GTK_WINDOW(nw->win),
+ "destroy", G_CALLBACK(doNotice), (void*)2);
+
gtk_widget_grab_default(nw->butt[ 0 ]);
gtk_widget_grab_focus(nw->butt[ 0 ]);
@@ -253,6 +266,7 @@ int wNotice3(
/* gdk_window_set_group( nw->win->window, gtkMainW->gtkwin->window ); */
}
+ noticeValue = 0; // Default: Cancel
wlibDoModal(NULL, TRUE);
if (aff) {
diff --git a/app/wlib/gtklib/opendocument.c b/app/wlib/gtklib/opendocument.c
new file mode 100644
index 0000000..c03f9cb
--- /dev/null
+++ b/app/wlib/gtklib/opendocument.c
@@ -0,0 +1,117 @@
+/** \file opendocument.c
+ * open a document using the systems default application for that doc
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 Martin Fischer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+#include "dynstring.h"
+
+#if defined (_WIN32)
+
+#define DEFAULTOPENCOMMAND "start"
+
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+#define DEFAULTOPENCOMMAND "open"
+
+#else
+
+#define DEFAULTOPENCOMMAND "xdg-open"
+
+#endif
+
+/**
+ * Extend the PATH variable in the environment to include XTrackCAD's
+ * script directory.
+ *
+ * \return pointer to old path
+ */
+
+static char *
+ExtendPath(void)
+{
+ char *path = strdup(getenv("PATH"));
+ DynString newPath;
+ DynStringMalloc(&newPath, 16);
+
+ // append XTrackCAD's directory to the path as a fallback
+ DynStringCatCStrs(&newPath,
+ path,
+ ":",
+ wGetAppLibDir(),
+ NULL);
+
+ setenv("PATH",
+ DynStringToCStr(&newPath),
+ TRUE);
+
+ DynStringFree(&newPath);
+
+ return (path);
+}
+
+/**
+ * Invoke the system's default application to open a file. First the
+ * system's standard xdg-open command is attempted. If that is not available, the
+ * version included with the XTrackCAD installation is executed.
+ *
+ * \param topic IN URI of document
+ */
+
+unsigned wOpenFileExternal(char * filename)
+{
+ int rc;
+ DynString commandLine;
+ char *currentPath;
+
+ assert(filename != NULL);
+ assert(strlen(filename));
+
+ currentPath = ExtendPath();
+
+ DynStringMalloc(&commandLine, 16);
+ DynStringCatCStrs(&commandLine,
+ DEFAULTOPENCOMMAND,
+ " \"",
+ filename,
+ "\"",
+ NULL);
+
+ // the command should be found via the PATH
+ rc = system(DynStringToCStr(&commandLine));
+
+ // restore the PATH
+ setenv("PATH",
+ currentPath,
+ TRUE);
+
+ free(currentPath);
+ DynStringFree(&commandLine);
+
+ return(rc==0);
+}
diff --git a/app/wlib/gtklib/osxhelp.c b/app/wlib/gtklib/osxhelp.c
index 829ec94..4ec1f5e 100644
--- a/app/wlib/gtklib/osxhelp.c
+++ b/app/wlib/gtklib/osxhelp.c
@@ -28,6 +28,7 @@
#include <errno.h>
#include <fcntl.h>
+#include "misc.h"
#include "gtkint.h"
#include "i18n.h"
@@ -39,6 +40,7 @@ static pid_t pidOfChild;
static int handleOfPipe;
extern char *wExecutableName;
+
/**
* Create the fully qualified filename for the help helper
*
@@ -70,14 +72,21 @@ char *ChildProgramFile(char *parentProgram)
void wHelp(const char * topic)
{
pid_t newPid;
- int len;
int status;
const char html[] = ".html";
+ static char *directory; /**< base directory for HTML files */
+ char * htmlFile;
+
+ struct {
+ int length;
char *page;
-
+ } buffer;
+
+ if (!CheckHelpTopicExists(topic)) return;
+
// check whether child already exists
if (pidOfChild != 0) {
- if (waitpid(pidOfChild, &status, WNOHANG) > 0) {
+ if (waitpid(pidOfChild, &status, WNOHANG) < 0) {
// child exited -> clean up
close(handleOfPipe);
unlink(HELPCOMMANDPIPE);
@@ -88,7 +97,8 @@ void wHelp(const char * topic)
// (re)start child
if (pidOfChild == 0) {
- mkfifo(HELPCOMMANDPIPE, 0666);
+ unlink(HELPCOMMANDPIPE);
+ int rc = mkfifo(HELPCOMMANDPIPE, 0666);
newPid = fork(); /* New process starts here */
if (newPid > 0) {
@@ -107,27 +117,46 @@ void wHelp(const char * topic)
}
}
- if (!handleOfPipe) {
- handleOfPipe = open(HELPCOMMANDPIPE, O_WRONLY);
-
- if (handleOfPipe < 0) {
- kill(pidOfChild, SIGKILL); /* tidy up on next call */
- }
+ buffer.page = malloc(sizeof(int)+strlen(topic) + strlen(html) + 1);
+ if (!buffer.page) {
+ return;
}
- page = malloc(strlen(topic) + strlen(html) + 1);
+ strcpy(buffer.page, topic);
+ strcat(buffer.page, html);
+ buffer.length = strlen(buffer.page);
- if (!page) {
- return;
+ if (buffer.length>255) {
+ printf("Help Topic too long %s", buffer.page);
+ return;
}
- strcpy(page, topic);
- strcat(page, html);
- len = strlen(page);
+ if (!handleOfPipe) {
+ handleOfPipe = open(HELPCOMMANDPIPE, O_WRONLY);
+
+ if (handleOfPipe < 0) {
+ if (pidOfChild)
+ kill(pidOfChild, SIGKILL); /* tidy up on next call */
+ handleOfPipe = 0;
+ return;
+ }
+
+ }
+
+ int written = 0;
+ int towrite = sizeof(int);
+
+ while (written < towrite){
+ written += write(handleOfPipe, &buffer.length, sizeof(int));
+ }
+ written =0;
+ towrite = strlen(buffer.page);
+ while (written < towrite){
+ written += write(handleOfPipe, buffer.page+written, towrite-written);
+ }
- write(handleOfPipe, &len, sizeof(int));
- write(handleOfPipe, page, strlen(page)+1);
+ fsync(handleOfPipe);
- free(page);
+ free(buffer.page);
}
diff --git a/app/wlib/gtklib/print.c b/app/wlib/gtklib/print.c
index 8e96e3b..860a7c7 100644
--- a/app/wlib/gtklib/print.c
+++ b/app/wlib/gtklib/print.c
@@ -70,9 +70,9 @@ extern wDrawColor wDrawColorBlack;
*
*/
-static GtkPrintSettings *settings; /**< current printer settings */
+static GtkPrintSettings *settings = NULL; /**< current printer settings */
static GtkPageSetup *page_setup; /**< current paper settings */
-static GtkPrinter *selPrinter; /**< printer selected by user */
+static GtkPrinter *selPrinter = NULL; /**< printer selected by user */
static GtkPrintJob *curPrintJob; /**< currently active print job */
extern struct wDraw_t psPrint_d;
@@ -131,7 +131,6 @@ WlibApplySettings(GtkPrintOperation *op)
// create default print settings
settings = gtk_print_settings_new();
}
-
g_error_free(err);
}
@@ -247,12 +246,13 @@ void wPrintSetup(wPrintSetupCallBack_p callback)
GError *err;
GtkWidget *dialog;
- WlibApplySettings(NULL);
+ if ( !settings )
+ WlibApplySettings(NULL);
new_page_setup = gtk_print_run_page_setup_dialog(GTK_WINDOW(gtkMainW->gtkwin),
page_setup, settings);
- if (page_setup) {
+ if (page_setup && (page_setup != new_page_setup)) { //Can be the same if no mods...
g_object_unref(page_setup);
}
@@ -264,6 +264,51 @@ void wPrintSetup(wPrintSetupCallBack_p callback)
/*****************************************************************************
*
+ *
+ *
+ */
+
+
+static GtkPrinter * pDefaultPrinter = NULL;
+gboolean isDefaultPrinter( GtkPrinter * printer, gpointer data )
+{
+const char * pPrinterName = gtk_printer_get_name( printer );
+ if ( gtk_printer_is_default( printer ) ) {
+ pDefaultPrinter = printer;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void getDefaultPrinter()
+{
+ pDefaultPrinter = NULL;
+ gtk_enumerate_printers( isDefaultPrinter, NULL, NULL, TRUE );
+}
+
+const char * wPrintGetName()
+{
+ static char sPrinterName[100];
+ WlibApplySettings( NULL );
+ const char * pPrinterName =
+ gtk_print_settings_get( settings, "format-for-printer" );
+ if ( pPrinterName == NULL ) {
+ getDefaultPrinter();
+ if ( pDefaultPrinter )
+ pPrinterName = gtk_printer_get_name( pDefaultPrinter );
+ }
+ if ( pPrinterName == NULL ) {
+ pPrinterName = "";
+ }
+ strncpy (sPrinterName, pPrinterName, sizeof sPrinterName - 1 );
+ sPrinterName[ sizeof sPrinterName - 1 ] = '\0';
+ for ( char * cp = sPrinterName; *cp; cp++ )
+ if ( *cp == ':' )
+ *cp = '-';
+ return sPrinterName;
+}
+/*****************************************************************************
+ *
* BASIC PRINTING
*
*/
@@ -299,12 +344,53 @@ static void setLineType(
}
cairo_set_line_width(cr, lineWidth);
-
- if (lineType == wDrawLineDash) {
- cairo_set_dash(cr, dashes, len_dashes, 0.0);
- } else {
- cairo_set_dash(cr, NULL, 0, 0.0);
+ switch(lineType) {
+ case wDrawLineDot:
+ {
+ double dashes[] = { 1, 2 , 1, 2};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLineDash:
+ {
+ double dashes[] = { DASH_LENGTH, 3 }; //Reduce gap in between dashes
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLineDashDot:
+ {
+ double dashes[] = { 3, 2, 1, 2};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLineDashDotDot:
+ {
+ double dashes[] = { 3, 2, 1, 2, 1, 2};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLineCenter:
+ {
+ double dashes[] = { 1.5*DASH_LENGTH, 3, DASH_LENGTH, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ case wDrawLinePhantom:
+ {
+ double dashes[] = { 1.5*DASH_LENGTH, 3, DASH_LENGTH, 3, DASH_LENGTH, 3};
+ static int len_dashes = sizeof(dashes) / sizeof(dashes[0]);
+ cairo_set_dash(cr, dashes, len_dashes, 0.0);
+ break;
+ }
+ default:
+ cairo_set_dash(cr, NULL, 0, 0.0);
}
+
}
/**
@@ -479,14 +565,18 @@ void psPrintFillRectangle(
* \param cnt IN the number of points
* \param color IN fill color
* \param opts IN options
+ * \paran fill IN Fill or not
* \return
*/
void psPrintFillPolygon(
wPos_t p[][2],
+ wPolyLine_e type[],
int cnt,
wDrawColor color,
- wDrawOpts opts)
+ wDrawOpts opts,
+ int fill,
+ int open )
{
int inx;
cairo_t *cr = psPrint_d.printContext;
@@ -501,13 +591,67 @@ void psPrintFillPolygon(
psSetColor(color);
- cairo_move_to(cr, p[ 0 ][ 0 ], p[ 0 ][ 1 ]);
+ wPos_t mid0[2], mid1[2], mid2[2], mid3[2], mid4[2];
for (inx=0; inx<cnt; inx++) {
- cairo_line_to(cr, p[ inx ][ 0 ], p[ inx ][ 1 ]);
+ int j = inx-1;
+ int k = inx+1;
+ if (j < 0) j = cnt-1;
+ if (k > cnt-1) k = 0;
+ double len0, len1;
+ double d0x = (p[inx][0]-p[j][0]);
+ double d0y = (p[inx][1]-p[j][1]);
+ double d1x = (p[k][0]-p[inx][0]);
+ double d1y = (p[k][1]-p[inx][1]);
+ len0 = (d0x*d0x+d0y*d0y);
+ len1 = (d1x*d1x+d1y*d1y);
+ mid0[0] = (d0x/2)+p[j][0];
+ mid0[1] = (d0y/2)+p[j][1];
+ mid1[0] = (d1x/2)+p[inx][0];
+ mid1[1] = (d1y/2)+p[inx][1];
+ if (type && (type[inx] == wPolyLineRound) && (len1>0) && (len0>0)) {
+ double ratio = sqrt(len0/len1);
+ if (len0 < len1) {
+ mid1[0] = ((d1x*ratio)/2)+p[inx][0];
+ mid1[1] = ((d1y*ratio)/2)+p[inx][1];
+ } else {
+ mid0[0] = p[inx][0]-(d0x/(2*ratio));
+ mid0[1] = p[inx][1]-(d0y/(2*ratio));
+ }
+ }
+ mid3[0] = (p[inx][0]-mid0[0])/2+mid0[0];
+ mid3[1] = (p[inx][1]-mid0[1])/2+mid0[1];
+ mid4[0] = (mid1[0]-p[inx][0])/2+p[inx][0];
+ mid4[1] = (mid1[1]-p[inx][1])/2+p[inx][1];
+ wPos_t save[2];
+ if (inx==0) {
+ if (!type || (type && type[0] == wPolyLineStraight) || open) {
+ cairo_move_to(cr, p[ 0 ][ 0 ], p[ 0 ][ 1 ]);
+ save[0] = p[0][0]; save[1] = p[0][1];
+ } else {
+ cairo_move_to(cr, mid0[0], mid0[1]);
+ if (type[inx] == wPolyLineSmooth)
+ cairo_curve_to(cr, p[inx][0], p[inx][1], p[inx][0], p[inx][1], mid1[0], mid1[1]);
+ else
+ cairo_curve_to(cr, mid3[0], mid3[1], mid4[0], mid4[1], mid1[0], mid1[1]);
+ save[0] = mid0[0]; save[1] = mid0[1];
+ }
+ } else if (!type || (type && type[inx] == wPolyLineStraight) || (open && (inx==cnt-1)) ) {
+ cairo_line_to(cr, p[ inx ][ 0 ], p[ inx ][ 1 ]);
+ } else {
+ cairo_line_to(cr, mid0[ 0 ], mid0[ 1 ]);
+ if (type && type[inx] == wPolyLineSmooth)
+ cairo_curve_to(cr, p[inx][0],p[inx][1],p[inx][0],p[inx][1],mid1[0],mid1[1]);
+ else
+ cairo_curve_to(cr, mid3[0],mid3[1],mid4[0],mid4[1],mid1[0],mid1[1]);
+ }
+ if ((inx==cnt-1) && !open) {
+ cairo_line_to(cr, save[0], save[1]);
+ }
}
- cairo_fill(cr);
+ if (fill && !open) cairo_fill(cr);
+ else cairo_stroke(cr);
}
/**
@@ -602,6 +746,7 @@ void psPrintString(
cairo_matrix_transform_point(&matrix, &x0, &y0);
+ cairo_identity_matrix(cr);
layout = pango_cairo_create_layout(cr);
@@ -609,7 +754,6 @@ void psPrintString(
/** \todo use a getter function instead of double conversion */
desc = pango_font_description_from_string(wlibFontTranslate(fp));
-
pango_font_description_set_size(desc, fs * PANGO_SCALE * scale_text);
// render the string to a Pango layout
@@ -617,28 +761,41 @@ void psPrintString(
pango_layout_set_text(layout, s, -1);
pango_layout_set_width(layout, -1);
pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
- pango_layout_get_pixel_size(layout, &text_width, &text_height);
+ pango_layout_get_size(layout, &text_width, &text_height);
+
+ text_width = text_width / PANGO_SCALE;
+ text_height = text_height / PANGO_SCALE;
// get the height of the string
pcontext = pango_cairo_create_context(cr);
metrics = pango_context_get_metrics(pcontext, desc,
pango_context_get_language(pcontext));
- ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE *scale_adjust;
-
- cairo_identity_matrix(cr);
+ ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
- cairo_translate(cr, x0 + ((ascent + (bBorder*scale_adjust)) * sin(-a * M_PI / 180.0))+((lBorder*scale_adjust)* cos(a * M_PI / 180.0)),
- y0 - ((ascent + (bBorder*scale_adjust)) * cos( a * M_PI / 180.0))+((lBorder*scale_adjust)* sin(a * M_PI / 180.0)));
+ int baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
+ cairo_translate(cr, x0, y0 );
cairo_rotate(cr, -a * M_PI / 180.0);
+ cairo_translate( cr, 0, -baseline );
+
+ cairo_move_to(cr,0,0);
+
+ pango_cairo_update_layout(cr, layout);
+
// set the color
psSetColor(color);
// and show the string
- pango_cairo_show_layout(cr, layout);
-
+ if(!(opts & wDrawOutlineFont)) {
+ pango_cairo_show_layout(cr, layout);
+ } else {
+ PangoLayoutLine *line;
+ line = pango_layout_get_line_readonly (layout, 0);
+ pango_cairo_layout_line_path (cr, line);
+ cairo_stroke( cr );
+ }
// free unused objects
g_object_unref(layout);
g_object_unref(pcontext);
@@ -704,21 +861,20 @@ WlibGetPaperSize(void)
* \return
*/
-void wPrintGetPageSize(
- double * w,
- double * h)
-{
- // if necessary load the settings
- if (!settings) {
- WlibApplySettings(NULL);
- }
-
- WlibGetPaperSize();
- *w = paperWidth -lBorder - rBorder;
- *h = paperHeight - tBorder - bBorder;
+void wPrintGetMargins(
+ double * tMargin,
+ double * rMargin,
+ double * bMargin,
+ double * lMargin )
+{
+ if ( tMargin ) *tMargin = tBorder;
+ if ( rMargin ) *rMargin = rBorder;
+ if ( bMargin ) *bMargin = bBorder;
+ if ( lMargin ) *lMargin = lBorder;
}
+
/**
* Get the paper size. The size returned is the physical size of the
* currently selected paper.
@@ -727,7 +883,7 @@ void wPrintGetPageSize(
* \return
*/
-void wPrintGetPhysSize(
+void wPrintGetPageSize(
double * w,
double * h)
{
@@ -854,13 +1010,13 @@ wBool_t wPrintDocStart(const char * title, int fTotalPageCount, int * copiesP)
NULL);
psPrint_d.printContext = cairo_create(psPrint_d.curPrintSurface);
+ WlibApplySettings( NULL );
//update the paper dimensions
WlibGetPaperSize();
/* for all surfaces including files the resolution is always 72 ppi (as all GTK uses PDF) */
surface_type = cairo_surface_get_type(psPrint_d.curPrintSurface);
- const char * printer_name = gtk_print_settings_get_printer(settings);
/*
* Override up-scaling for some printer drivers/Linux systems that don't support the latest CUPS
* - the user sets the environment variable XTRKCADPRINTSCALE to a value
@@ -871,7 +1027,8 @@ wBool_t wPrintDocStart(const char * title, int fTotalPageCount, int * copiesP)
*/
char * sEnvScale = PRODUCT "PRINTSCALE";
- if ((strcmp(printer_name,"Print to File") == 0) || getenv(sEnvScale) == NULL) {
+ const char * sPrinterName = gtk_printer_get_name( selPrinter );
+ if ((strcmp(sPrinterName,"Print to File") == 0) || getenv(sEnvScale) == NULL) {
double p_def = 600;
cairo_surface_set_fallback_resolution(psPrint_d.curPrintSurface, p_def, p_def);
psPrint_d.dpi = p_def;
diff --git a/app/wlib/gtklib/single.c b/app/wlib/gtklib/single.c
index 45ed6e4..600f1dd 100644
--- a/app/wlib/gtklib/single.c
+++ b/app/wlib/gtklib/single.c
@@ -50,8 +50,10 @@ struct wString_t {
char *valueP; /**< pointer to result buffer */
wIndex_t valueL; /**< maximum length */
wStringCallBack_p action; /**< callback for changes */
- wBool_t busy; /**< busy flag to prevent re-entry problems? */
+ wBool_t notice_activate; /** if flag set to observe enter key **/
+ wBool_t enter_pressed; /**< flag if enter was pressed */
wBool_t hasSignal; /** needs signal to be suppressed */
+ int count; /** number of 100ms since last entry **/
guint timer; /**< timer source for inactivity timer */
};
@@ -142,33 +144,43 @@ static gboolean killTimer(
}
/**
- * Timer handler for string activity. This timer expires if the user
- * doesn't change an entry value within the preset time.
+ * Timer handler for string activity. This timer checks the input if the user
+ * doesn't change an entry value for the preset time (0.5s).
*/
static gboolean
timeoutString( wString_p bs )
{
-
+ const char *new_value;
if ( !bs )
return( FALSE );
if (bs->widget == 0)
abort();
- if (bs->action) {
- const char *s;
-
- s = gtk_entry_get_text(GTK_ENTRY(bs->widget));
- if ( s )
- bs->action(s, bs->data);
+ bs->count--;
+
+ if (bs->count==0) {
+ // get the currently entered value
+ new_value = wStringGetValue(bs);
+ if (bs->valueP != NULL)
+ strcpy(bs->valueP, new_value);
+
+ if (bs->action) {
+ bs->enter_pressed = FALSE; //Normal input
+ if ( new_value )
+ bs->action(new_value,bs->data);
+ }
+ }
+ if (bs->count<=0) {
+ bs->timer = 0;
+ return( FALSE ); //Stop timer
+ } else {
+ return TRUE; //Wait 100ms
}
-
- bs->timer = 0;
- return( FALSE );
}
/**
- * Signal handler for 'activate' signal: callback with the current value and then
+ * Signal handler for 'activate' signal: enter pressed - callback with the current value and then
* select the whole default value
*
* \param widget IN the edit field
@@ -181,6 +193,7 @@ static gboolean stringActivated(
wString_p b)
{
const char *s;
+ const char * output = "\n";
if ( !b )
return( FALSE );
@@ -191,14 +204,22 @@ static gboolean stringActivated(
strcpy(b->valueP, s);
if (b->action) {
- b->action(s, b->data);
+ b->enter_pressed = TRUE;
+ b->action( output, b->data);
}
// select the complete default value to make editing it easier
gtk_editable_select_region( GTK_EDITABLE( widget ), 0, -1 );
- return( FALSE );
+ return( TRUE );
+}
+
+static gboolean stringExposed(GtkWidget* widget, GdkEventExpose * event, gpointer g )
+{
+ wControl_p b = (wControl_p)g;
+ return wControlExpose(widget,event,b);
}
+
/**
* Signal handler for changes in an entry field
*
@@ -213,25 +234,27 @@ static void stringChanged(
{
const char *new_value;
- if ( !b || b->busy )
+ if ( !b )
return;
+ b->count = 5; /* set ~500 ms from now */
+
// get the entered value
- new_value = wStringGetValue(b);
- if (b->valueP != NULL)
- strcpy(b->valueP, new_value);
-
+ //new_value = wStringGetValue(b);
+ //if (b->valueP != NULL)
+ // strcpy(b->valueP, new_value);
+ //
//
if (b->action){
// if one exists, remove the inactivity timer
- if( b->timer )
- g_source_remove( b->timer );
+ if( !b->timer ) {
+ //g_source_remove( b->timer );
// create a new timer
- b->timer = g_timeout_add( TIMEOUT_INACTIVITY,
+ b->timer = g_timeout_add( TIMEOUT_INACTIVITY/5,
(GSourceFunc)timeoutString,
- b );
-
+ b );
+ }
}
return;
}
@@ -318,9 +341,12 @@ wString_p wStringCreate(
// link into help
wlibAddHelpString(b->widget, helpStr);
- g_signal_connect(GTK_OBJECT(b->widget), "changed", G_CALLBACK(stringChanged), b);
- //g_signal_connect(GTK_OBJECT(b->widget), "activate", G_CALLBACK(stringActivated), b);
+ //g_signal_connect(GTK_OBJECT(b->widget), "changed", G_CALLBACK(stringChanged), b);
+ //if (option&BO_ENTER)
+ g_signal_connect(GTK_OBJECT(b->widget), "activate", G_CALLBACK(stringActivated), b);
b->hasSignal = 1;
+ g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event",
+ G_CALLBACK(stringExposed), b);
// set the default text and select it to make replacing it easier
if (b->valueP) {
diff --git a/app/wlib/gtklib/splash.c b/app/wlib/gtklib/splash.c
index 0d5be50..5d56e9f 100644
--- a/app/wlib/gtklib/splash.c
+++ b/app/wlib/gtklib/splash.c
@@ -63,7 +63,7 @@ wCreateSplash(char *appName, char *appVer)
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
-#if GTK_MINOR_VERSION > 5
+#if GTK_MAJOR_VERSION > 1 || GTK_MINOR_VERSION > 5
gtk_window_set_focus_on_map(GTK_WINDOW(window), FALSE);
#endif
@@ -108,7 +108,6 @@ wCreateSplash(char *appName, char *appVer)
message = label;
gtk_widget_show(window);
-
return (TRUE);
}
@@ -121,8 +120,9 @@ wCreateSplash(char *appName, char *appVer)
int
wSetSplashInfo(char *msg)
{
- if (msg) {
- gtk_label_set_text((GtkLabel *)message, msg);
+ if (!window) return FALSE;
+ if (msg && message) {
+ gtk_label_set_text(GTK_LABEL(message), msg);
wFlush();
return TRUE;
}
@@ -139,6 +139,8 @@ void
wDestroySplash(void)
{
/* kill window */
- gtk_widget_destroy(window);
+ if (window) gtk_widget_destroy(window);
+ window = NULL;
+
return;
}
diff --git a/app/wlib/gtklib/statusbar.c b/app/wlib/gtklib/statusbar.c
index 3730eab..3a2fd0d 100644
--- a/app/wlib/gtklib/statusbar.c
+++ b/app/wlib/gtklib/statusbar.c
@@ -67,6 +67,7 @@ void wStatusSetValue(
}
gtk_entry_set_text(GTK_ENTRY(b->labelWidget), wlibConvertInput(arg));
+ gtk_widget_queue_draw (GTK_WIDGET(b->labelWidget));
}
/**
* Create a window for a simple text.
@@ -99,6 +100,9 @@ wStatus_p wStatusCreate(
gtk_editable_set_editable(GTK_EDITABLE(b->labelWidget), FALSE);
gtk_entry_set_has_frame(GTK_ENTRY(b->labelWidget), FALSE);
gtk_widget_set_can_focus(b->labelWidget, FALSE);
+ gtk_widget_set_sensitive(b->labelWidget, FALSE);
+ GdkColor black = {0, 0x0000, 0x0000, 0x0000};
+ gtk_widget_modify_text(b->labelWidget,GTK_STATE_INSENSITIVE,&black);
gtk_entry_set_text(GTK_ENTRY(b->labelWidget),
message?wlibConvertInput(message):"");
@@ -138,7 +142,7 @@ wStatusGetWidth(const char *testString)
gtk_widget_destroy(entry);
g_object_unref(entry);
- return (requisition.width+8);
+ return (requisition.width);
}
/**
diff --git a/app/wlib/gtklib/text.c b/app/wlib/gtklib/text.c
index f7ba288..0812ace 100644
--- a/app/wlib/gtklib/text.c
+++ b/app/wlib/gtklib/text.c
@@ -98,6 +98,8 @@ void wTextAppend(wText_p bt,
{
GtkTextBuffer *tb;
GtkTextIter ti1;
+ GtkTextMark *tm;
+
if (bt->text == 0) {
abort();
@@ -109,6 +111,18 @@ void wTextAppend(wText_p bt,
// append to end of buffer
gtk_text_buffer_get_end_iter(tb, &ti1);
gtk_text_buffer_insert(tb, &ti1, text, -1);
+
+ if ( bt->option & BT_TOP ) {
+ // and scroll to start of text
+ gtk_text_buffer_get_start_iter(tb, &ti1);
+ } else {
+ // and scroll to end of text
+ gtk_text_buffer_get_end_iter(tb, &ti1);
+ }
+ tm = gtk_text_buffer_create_mark(tb, NULL, &ti1, TRUE );
+ gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW(bt->text), tm );
+ gtk_text_buffer_delete_mark( tb, tm );
+
bt->changed = FALSE;
}
@@ -116,7 +130,7 @@ void wTextAppend(wText_p bt,
* Get the text from a text buffer in system codepage
* The caller is responsible for free'ing the allocated storage.
*
- * \todo handling of return from gtkConvertOutput can be improved
+ * Dont convert from UTF8
*
* \param bt IN the text widget
* \return pointer to the converted text
@@ -135,8 +149,8 @@ static char *wlibGetText(wText_p bt)
tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(bt->text));
gtk_text_buffer_get_bounds(tb, &ti1, &ti2);
cp = gtk_text_buffer_get_text(tb, &ti1, &ti2, FALSE);
- cp1 = wlibConvertOutput(cp);
- res = strdup(cp1);
+ //cp1 = wlibConvertOutput(cp);
+ res = strdup(cp);
g_free(cp);
return res;
}
@@ -375,7 +389,7 @@ wBool_t wTextPrint(
* Get the length of text
*
* \param bt IN the text widget
- * \return length of string
+ * \return length of string including terminating \0
*/
int wTextGetSize(wText_p bt)
@@ -383,7 +397,7 @@ int wTextGetSize(wText_p bt)
char *cp = wlibGetText(bt);
int len = strlen(cp);
free(cp);
- return len;
+ return len + 1;
}
/**
diff --git a/app/wlib/gtklib/timer.c b/app/wlib/gtklib/timer.c
index 812908f..80c71fb 100644
--- a/app/wlib/gtklib/timer.c
+++ b/app/wlib/gtklib/timer.c
@@ -109,6 +109,9 @@ void wlibSetTrigger(
void wPause(
long count) /* milliseconds */
{
+ while (gtk_events_pending())
+ gtk_main_iteration(); //Allow GTK to finish before pausing
+
struct timeval timeout;
sigset_t signal_mask;
sigset_t oldsignal_mask;
diff --git a/app/wlib/gtklib/util.c b/app/wlib/gtklib/util.c
index e6587a0..a265938 100644
--- a/app/wlib/gtklib/util.c
+++ b/app/wlib/gtklib/util.c
@@ -197,6 +197,8 @@ void * wlibAlloc(
abort();
}
+ w->outline = FALSE;
+
w->type = type;
w->parent = parent;
w->origX = origX;
@@ -369,7 +371,7 @@ void wFlush(
void)
{
while (gtk_events_pending()) {
- gtk_main_iteration();
+ gtk_main_iteration_do(FALSE);
}
gdk_display_sync(gdk_display_get_default());
@@ -385,13 +387,81 @@ void wWinTop(wWin_p win)
}
/**
- * Not implemented
+ * Set the cursor in GTK
*
* \param cursor IN
*/
-void wSetCursor(wCursor_t cursor)
+void wSetCursor(wDraw_p bd, wCursor_t cursor)
{
+ static GdkCursor * gdkcursors[wCursorQuestion+1];
+ GdkCursor * gdkcursor;
+ //GdkWindow * gdkwindow = gtk_widget_get_window(GTK_WIDGET(win->gtkwin));;
+ GdkWindow * gdkwindow = gdk_get_default_root_window();
+ GdkDisplay * display = gdk_window_get_display(gdkwindow);
+ if (!gdkcursors[cursor]) {
+ switch(cursor) {
+ case wCursorAppStart:
+ //gdkcursor = gdk_cursor_new_from_name (display,"progress");
+ gdkcursor = gdk_cursor_new(GDK_WATCH);
+ break;
+ case wCursorHand:
+ //gdkcursor = gdk_cursor_new_from_name (display,"pointer");
+ gdkcursor = gdk_cursor_new(GDK_HAND2);
+ break;
+ case wCursorNo:
+ //gdkcursor = gdk_cursor_new_from_name (display,"not-allowed");
+ gdkcursor = gdk_cursor_new(GDK_X_CURSOR);
+ break;
+ case wCursorSizeAll:
+ //gdkcursor = gdk_cursor_new_from_name (display,"move");
+ gdkcursor = gdk_cursor_new(GDK_FLEUR);
+ break;
+ case wCursorSizeNESW:
+ //gdkcursor = gdk_cursor_new_from_name (display,"nesw-resize");
+ gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
+ break;
+ case wCursorSizeNS:
+ //gdkcursor = gdk_cursor_new_from_name (display,"ns-resize");
+ gdkcursor = gdk_cursor_new(GDK_DOUBLE_ARROW);
+ break;
+ case wCursorSizeNWSE:
+ //gdkcursor = gdk_cursor_new_from_name (display,"nwse-resize");
+ gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
+ break;
+ case wCursorSizeWE:
+ //gdkcursor = gdk_cursor_new_from_name (display,"ew-resize");
+ gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
+ break;
+ case wCursorWait:
+ //gdkcursor = gdk_cursor_new_from_name (display,"wait");
+ gdkcursor = gdk_cursor_new(GDK_WATCH);
+ break;
+ case wCursorIBeam:
+ //gdkcursor = gdk_cursor_new_from_name (display,"text");
+ gdkcursor = gdk_cursor_new(GDK_XTERM);
+ break;
+ case wCursorCross:
+ //gdkcursor = gdk_cursor_new_from_name (display,"crosshair");
+ gdkcursor = gdk_cursor_new(GDK_TCROSS);
+ break;
+ case wCursorQuestion:
+ //gdkcursor = gdk_cursor_new_from_name (display,"help");
+ gdkcursor = gdk_cursor_new(GDK_QUESTION_ARROW);
+ break;
+ case wCursorNone:
+ gdkcursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+ case wCursorNormal:
+ default:
+ //gdkcursor = gdk_cursor_new_from_name (display,"default");
+ gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
+ break;
+
+ }
+ gdkcursors[cursor] = gdkcursor;
+ } else gdkcursor = gdkcursors[cursor];
+
+ gdk_window_set_cursor ( gtk_widget_get_window(bd->widget), gdkcursor);
}
/**
@@ -413,11 +483,17 @@ const char * wMemStats(void)
void wGetDisplaySize(wPos_t * w, wPos_t * h)
{
-
- *w = gdk_screen_width();
- *h = gdk_screen_height();
+ GdkScreen *screen = gdk_screen_get_default();
+ guint monitor = gdk_screen_get_primary_monitor(screen);
+ GdkRectangle screen_geometry = { 0, 0, 0, 0 };
+
+ gdk_screen_get_monitor_geometry( screen, monitor, &screen_geometry );
+
+ *w = screen_geometry.width;
+ *h = screen_geometry.height;
}
+
static dynArr_t conversionBuffer_da;
/**
diff --git a/app/wlib/gtklib/window.c b/app/wlib/gtklib/window.c
index 49770c5..1468c89 100644
--- a/app/wlib/gtklib/window.c
+++ b/app/wlib/gtklib/window.c
@@ -29,6 +29,9 @@
#define GTK_DISABLE_DEPRECATED
#define GSEAL_ENABLE
+#define MIN_WIDTH 100
+#define MIN_HEIGHT 100
+
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
@@ -37,8 +40,11 @@
wWin_p gtkMainW;
-#define MIN_WIN_WIDTH (50)
-#define MIN_WIN_HEIGHT (50)
+#define MIN_WIN_WIDTH 150
+#define MIN_WIN_HEIGHT 150
+
+#define MIN_WIN_WIDTH_MAIN 400
+#define MIN_WIN_HEIGHT_MAIN 400
#define SECTIONWINDOWSIZE "gtklib window size"
#define SECTIONWINDOWPOS "gtklib window pos"
@@ -93,6 +99,7 @@ static GdkRectangle getMonitorDimensions(GtkWidget * widget) {
gdk_screen_get_monitor_geometry(screen,monitor,&monitor_dimensions);
+
return monitor_dimensions;
}
@@ -106,40 +113,47 @@ static GdkRectangle getMonitorDimensions(GtkWidget * widget) {
static void getWinSize(wWin_p win, const char * nameStr)
{
- int w, h;
+ int w=50, h=50;
const char *cp;
char *cp1, *cp2;
+
/*
* Clamp window to be no bigger than one monitor size (to start - the user can always maximize)
*/
GdkRectangle monitor_dimensions = getMonitorDimensions(GTK_WIDGET(win->gtkwin));
- wPos_t maxDisplayWidth = monitor_dimensions.width-5;
- wPos_t maxDisplayHeight = monitor_dimensions.height-25;
+ wPos_t maxDisplayWidth = monitor_dimensions.width-10;
+ wPos_t maxDisplayHeight = monitor_dimensions.height-50;
- if ((win->option&F_RESIZE) &&
+
+ if ((win->option&F_RECALLSIZE) &&
(win->option&F_RECALLPOS) &&
(cp = wPrefGetString(SECTIONWINDOWSIZE, nameStr)) &&
(w = strtod(cp, &cp1), cp != cp1) &&
(h = strtod(cp1, &cp2), cp1 != cp2)) {
- if (w < 10) {
- w = 10;
- }
-
- if (h < 10) {
- h = 10;
- }
+ win->option &= ~F_AUTOSIZE;
- if (w > maxDisplayWidth) w = maxDisplayWidth;
- if (h > maxDisplayHeight) h = maxDisplayHeight;
+ if (w < 50) {
+ w = 50;
+ }
- win->w = win->origX = w;
- win->h = win->origY = h;
- win->option &= ~F_AUTOSIZE;
+ if (h < 50) {
+ h = 50;
+ }
}
+
+ if (w > maxDisplayWidth) w = maxDisplayWidth;
+ if (h > maxDisplayHeight) h = maxDisplayHeight;
+
+ if (w<MIN_WIDTH) w = MIN_WIDTH;
+ if (h<MIN_HEIGHT) h = MIN_HEIGHT;
+
+ win->w = win->origX = w;
+ win->h = win->origY = h;
+
}
/**
@@ -152,8 +166,7 @@ static void getWinSize(wWin_p win, const char * nameStr)
static void saveSize(wWin_p win)
{
- if ((win->option&F_RESIZE) &&
- (win->option&F_RECALLPOS) &&
+ if ((win->option&F_RECALLSIZE) &&
gtk_widget_get_visible(GTK_WIDGET(win->gtkwin))) {
char pos_s[20];
@@ -210,7 +223,7 @@ static void getPos(wWin_p win)
}
gtk_window_move(GTK_WINDOW(win->gtkwin), x, y);
- gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h);
+ //gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h);
}
}
}
@@ -285,9 +298,17 @@ void wWinSetSize(
{
win->busy = TRUE;
win->w = width;
- win->h = height + BORDERSIZE + ((win->option&F_MENUBAR)?win->menu_height:0);
- gtk_widget_set_size_request(win->gtkwin, win->w, win->h);
- gtk_widget_set_size_request(win->widget, win->w, win->h);
+ win->h = height + BORDERSIZE + ((win->option&F_MENUBAR)?MENUH:0);
+ if (win->option&F_RESIZE) {
+ gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h);
+ gtk_widget_set_size_request(win->widget, win->w-10, win->h-10);
+ }
+ else {
+ gtk_widget_set_size_request(win->gtkwin, win->w, win->h);
+ gtk_widget_set_size_request(win->widget, win->w, win->h);
+ }
+
+
win->busy = FALSE;
}
@@ -304,7 +325,7 @@ void wWinShow(
wWin_p win, /* Window */
wBool_t show) /* Command */
{
- GtkRequisition requisition;
+ //GtkRequisition min_req, pref_req;
if (debugWindow >= 2) {
printf("Set Show %s\n", win->labelStr?win->labelStr:"No label");
@@ -314,31 +335,48 @@ void wWinShow(
abort();
}
+ int width, height;
+
if (show) {
keyState = 0;
getPos(win);
+ if (!win->shown) {
+ gtk_widget_show(win->gtkwin);
+ gtk_widget_show(win->widget);
+ }
+
if (win->option & F_AUTOSIZE) {
- gtk_widget_size_request(win->gtkwin, &requisition);
+ GtkAllocation allocation;
+ GtkRequisition requistion;
+ gtk_widget_size_request(win->widget,&requistion);
+
+ width = win->w;
+ height = win->h;
+
+ if (requistion.width != width || requistion.height != height ) {
- if (requisition.width != win->w || requisition.height != win->h) {
- //gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h);
- gtk_widget_set_size_request(win->gtkwin, win->w, win->h);
- gtk_widget_set_size_request(win->widget, win->w-20, win->h);
+ width = requistion.width;
+ height = requistion.height;
+
+ win->w = width;
+ win->h = height;
+
+
+ gtk_window_set_resizable(GTK_WINDOW(win->gtkwin),TRUE);
if (win->option&F_MENUBAR) {
gtk_widget_set_size_request(win->menubar, win->w-20, MENUH);
- GtkAllocation allocation;
+
gtk_widget_get_allocation(win->menubar, &allocation);
win->menu_height = allocation.height;
}
}
+ gtk_window_resize(GTK_WINDOW(win->gtkwin), width+10, height+10);
}
- if (!win->shown) {
- gtk_widget_show(win->gtkwin);
- gtk_widget_show(win->widget);
- }
+ gtk_window_present(GTK_WINDOW(win->gtkwin));
+
gdk_window_raise(gtk_widget_get_window(win->gtkwin));
@@ -606,11 +644,24 @@ static int fixed_expose_event(
GdkEventExpose * event,
wWin_p win)
{
+ int rc;
+
if (event->count==0) {
- return window_redraw(win, TRUE);
+ rc = window_redraw(win, TRUE);
} else {
- return FALSE;
+ rc = FALSE;
}
+ cairo_t* cr = gdk_cairo_create (gtk_widget_get_window(widget));
+#ifdef CURSOR_SURFACE
+ if (win && win->cursor_surface.surface && win->cursor_surface.show) {
+ cairo_set_source_surface(cr,win->cursor_surface.surface,event->area.x, event->area.y);
+ cairo_set_operator(cr,CAIRO_OPERATOR_OVER);
+ cairo_rectangle(cr,event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill(cr);
+ }
+#endif
+ return rc;
}
static int resizeTime(wWin_p win) {
@@ -738,10 +789,8 @@ wBool_t catch_shift_ctrl_alt_keys(
GdkEventKey *event,
void * data)
{
- int state;
- state = 0;
-
- switch (event->keyval) {
+ int state = 0;
+ switch (event->keyval ) {
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
state |= WKEY_SHIFT;
@@ -756,6 +805,13 @@ wBool_t catch_shift_ctrl_alt_keys(
case GDK_KEY_Alt_R:
state |= WKEY_ALT;
break;
+
+ case GDK_KEY_Meta_L:
+ case GDK_KEY_Meta_R:
+ // Pressing SHIFT and then ALT generates a Meta key
+ //printf( "Meta\n" );
+ state |= WKEY_ALT;
+ break;
}
if (state != 0) {
@@ -764,10 +820,8 @@ wBool_t catch_shift_ctrl_alt_keys(
} else {
keyState &= ~state;
}
-
return TRUE;
}
-
return FALSE;
}
@@ -786,7 +840,7 @@ static gint window_char_event(
return FALSE;
}
- if (event->state == 0) {
+ if ( ( event->state & GDK_MODIFIER_MASK ) == 0 ) {
if (event->keyval == GDK_KEY_Escape) {
for (bb=win->first; bb; bb=bb->next) {
if (bb->type == B_BUTTON && (bb->option&BB_CANCEL)) {
@@ -804,6 +858,31 @@ static gint window_char_event(
}
}
+void wSetGeometry(wWin_p win, int min_width, int max_width, int min_height, int max_height, int base_width, int base_height, double aspect_ratio ) {
+ GdkGeometry hints;
+ GdkWindowHints hintMask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
+ hints.min_width = min_width;
+ hints.max_width = max_width;
+ hints.min_height = min_height;
+ hints.max_height = max_height;
+ hints.min_aspect = hints.max_aspect = aspect_ratio;
+ hints.base_width = base_width;
+ hints.base_height = base_height;
+ if( base_width != -1 && base_height != -1 ) {
+ hintMask |= GDK_HINT_BASE_SIZE;
+ }
+
+ if(aspect_ratio > -1.0 ) {
+ hintMask |= GDK_HINT_ASPECT;
+ }
+
+ gtk_window_set_geometry_hints(
+ GTK_WINDOW(win->gtkwin),
+ win->gtkwin,
+ &hints,
+ hintMask);
+}
+
/*
*******************************************************************************
@@ -862,12 +941,14 @@ static wWin_p wWinCommonCreate(
w->gtkwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
if (gtkMainW) {
- gtk_window_set_transient_for(GTK_WINDOW(w->gtkwin),
- GTK_WINDOW(gtkMainW->gtkwin));
+ if (!(w->option&F_NOTTRANSIENT))
+ gtk_window_set_transient_for(GTK_WINDOW(w->gtkwin),
+ GTK_WINDOW(gtkMainW->gtkwin));
}
}
+ getWinSize(w, nameStr);
if (winType != W_MAIN) {
- getWinSize(w, nameStr);
+ gtk_widget_set_app_paintable (w->gtkwin,TRUE);
}
if (option & F_HIDE) {
@@ -898,21 +979,39 @@ static wWin_p wWinCommonCreate(
gtk_container_add(GTK_CONTAINER(w->gtkwin), w->widget);
+
+
+
if (w->option&F_AUTOSIZE) {
w->realX = 0;
- w->w = 0;
+ w->w = MIN_WIN_WIDTH+20;
w->realY = h;
- w->h = 0;
+ w->h = MIN_WIN_HEIGHT;
} else if (w->origX != 0){
- w->w = w->realX = w->origX;
- w->h = w->realY = w->origY+h;
- gtk_window_set_default_size(GTK_WINDOW(w->gtkwin), w->w, w->h);
+ w->realX = w->origX;
+ w->realY = w->origY+h;
+
+ w->default_size_x = w->w;
+ w->default_size_y = w->h;
//gtk_widget_set_size_request(w->widget, w->w-20, w->h);
if (w->option&F_MENUBAR) {
gtk_widget_set_size_request(w->menubar, w->w-20, MENUH);
}
}
+ int scr_w, scr_h;
+ wGetDisplaySize(&scr_w, &scr_h);
+ if (scr_w < MIN_WIN_WIDTH) scr_w = MIN_WIN_WIDTH+10;
+ if (scr_h < MIN_WIN_HEIGHT) scr_h = MIN_WIN_HEIGHT;
+ if (winType != W_MAIN) {
+ wSetGeometry(w, MIN_WIN_WIDTH, scr_w-10, MIN_WIN_HEIGHT, scr_h, -1, -1, -1);
+ } else {
+ if (scr_w < MIN_WIN_WIDTH_MAIN+10) scr_w = MIN_WIN_WIDTH_MAIN+200;
+ if (scr_h < MIN_WIN_HEIGHT_MAIN+10) scr_h = MIN_WIN_HEIGHT_MAIN+200;
+ wSetGeometry(w, MIN_WIN_WIDTH_MAIN, scr_w-10, MIN_WIN_HEIGHT_MAIN, scr_h-10, -1, -1, -1);
+ }
+
+
w->first = w->last = NULL;
w->winProc = winProc;
@@ -934,6 +1033,7 @@ static wWin_p wWinCommonCreate(
if (w->option & F_RESIZE) {
gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), TRUE);
+ gtk_window_resize(GTK_WINDOW(w->gtkwin), w->w, w->h);
} else {
gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), FALSE);
}
diff --git a/app/wlib/gtklib/wpref.c b/app/wlib/gtklib/wpref.c
index c2541f9..124305a 100644
--- a/app/wlib/gtklib/wpref.c
+++ b/app/wlib/gtklib/wpref.c
@@ -168,7 +168,7 @@ const char * wGetAppWorkDir(
if ( stat( appEtcConfig, &stFileInfo ) == 0 ) {
char copyConfigCmd[(BUFSIZ * 2) + 3];
sprintf( copyConfigCmd, "cp %s %s", appEtcConfig, appWorkDir );
- system( copyConfigCmd );
+ int rc = system( copyConfigCmd );
}
}
}
@@ -293,7 +293,7 @@ void wPrefSetString(
if (p->val)
free(p->val);
p->dirty = TRUE;
- p->val = strdup( sval );
+ p->val = (sval?strdup( sval ):NULL);
return;
}
}
@@ -302,7 +302,7 @@ void wPrefSetString(
p->name = strdup(name);
p->section = strdup(section);
p->dirty = TRUE;
- p->val = strdup(sval);
+ p->val = (sval?strdup(sval):NULL);
}
/**
@@ -456,7 +456,9 @@ void wPrefFlush(
return;
for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) {
- fprintf( prefFile, "%s.%s: %s\n", p->section, p->name, p->val );
+ if(p->val) {
+ fprintf( prefFile, "%s.%s: %s\n", p->section, p->name, p->val );
+ }
}
fclose( prefFile );
}
diff --git a/app/wlib/include/mswlib.h b/app/wlib/include/mswlib.h
index 4a3f799..59260bb 100644
--- a/app/wlib/include/mswlib.h
+++ b/app/wlib/include/mswlib.h
@@ -1,8 +1,6 @@
#define WAPPICON (980)
#define WM_F1DOWN (WM_USER+10)
-#define WM_NOTVALID (WM_USER+11)
-#define IDM_DOHELP 999
#define IDM_PRINTAPP 998
#define IDM_PRINTPAGE 997
#define IDM_ABOUT 100
diff --git a/app/wlib/include/wlib.h b/app/wlib/include/wlib.h
index 699eefb..d3bfc18 100644
--- a/app/wlib/include/wlib.h
+++ b/app/wlib/include/wlib.h
@@ -11,6 +11,8 @@
#define FILE_SEP_CHAR "/"
#endif
+#include <stdbool.h>
+
#ifdef USE_SIMPLE_GETTEXT
char *bindtextdomain( char *domainname, char *dirname );
char *bind_textdomain_codeset(char *domainname, char *codeset );
@@ -20,6 +22,11 @@ char *gettext( const char *msgid );
char *g_win32_getlocale (void);
#endif
+// conversion routines to and from UTF-8
+bool wSystemToUTF8(const char *inString, char *outString, unsigned outStringLength);
+bool wUTF8ToSystem(const char *inString, char *outString, unsigned outStringLength);
+bool wIsUTF8(const char * string);
+
/*
* Interface types
*/
@@ -148,12 +155,14 @@ wBool_t wNotice( const char *, const char *, const char * );
int wNotice3( const char *, const char *, const char *, const char * );
void wHelp( const char * );
+
#define NT_INFORMATION 1
#define NT_WARNING 2
#define NT_ERROR 4
wBool_t wNoticeEx( int type, const char * msg, const char * yes, const char * no );
+unsigned wOpenFileExternal(char *filename);
void wSetBalloonHelp ( wBalloonHelp_t * );
@@ -170,11 +179,21 @@ unsigned long wGetTimer( void );
void wExit( int );
typedef enum { wCursorNormal,
+ wCursorNone,
+ wCursorAppStart,
+ wCursorHand,
+ wCursorNo,
+ wCursorSizeAll,
+ wCursorSizeNESW,
+ wCursorSizeNS,
+ wCursorSizeNWSE,
+ wCursorSizeWE,
wCursorWait,
wCursorIBeam,
wCursorCross,
wCursorQuestion } wCursor_t;
-void wSetCursor( wCursor_t );
+void wSetCursor( wDraw_p, wCursor_t );
+#define defaultCursor wCursorCross
const char * wMemStats( void );
@@ -224,6 +243,8 @@ typedef void (*wWinCallBack_p)( wWin_p, winProcEvent, void *, void * );
#define F_CENTER (1L<<12)
#define F_HIDE (1L<<13)
#define F_MAXIMIZE (1L<<14)
+#define F_RESTRICT (1L<<15)
+#define F_NOTTRANSIENT (1L<<16)
wWin_p wWinMainCreate( const char *, wPos_t, wPos_t, const char *, const char *, const char *,
long, wWinCallBack_p, void * );
@@ -246,6 +267,7 @@ void wMessage( wWin_p, const char *, wBool_t );
void wWinTop( wWin_p );
void wWinDoCancel( wWin_p );
void wWinBlockEnable( wBool_t );
+void wSetGeometry(wWin_p, int min_width, int max_width, int min_height, int max_height, int base_width, int base_height, double aspect_ratio);
int wCreateSplash( char *appName, char *appVer );
int wSetSplashInfo( char *msg );
@@ -262,6 +284,7 @@ void wDestroySplash( void );
#define BO_READONLY (1L<<2)
#define BO_NOTAB (1L<<8)
#define BO_BORDER (1L<<9)
+#define BO_ENTER (1L<<10)
wPos_t wLabelWidth( const char * );
const char * wControlGetHelp( wControl_p );
@@ -290,7 +313,7 @@ void wControlLinkedActive( wControl_p b, int active );
#define BS_TRIM (1<<12)
/* Creation CallBacks */
-typedef void (*wStringCallBack_p)( const char *, void * );
+typedef void (*wStringCallBack_p)( const char *, void *);
wString_p wStringCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
wPos_t, char *, wIndex_t, wStringCallBack_p,
void * );
@@ -305,8 +328,8 @@ const char * wStringGetValue( wString_p );
*/
/* Creation CallBacks */
-typedef void (*wIntegerCallBack_p)( long, void * );
-typedef void (*wFloatCallBack_p)( double, void * );
+typedef void (*wIntegerCallBack_p)( long, void * , int);
+typedef void (*wFloatCallBack_p)( double, void * , int);
wInteger_p wIntegerCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
wPos_t, wInteger_t, wInteger_t, wInteger_t *,
wIntegerCallBack_p, void * );
@@ -414,6 +437,7 @@ wLine_p wLineCreate( wWin_p, const char *, int, wLines_t *);
#define BT_CHARUNITS (1L<<23)
#define BT_FIXEDFONT (1L<<22)
#define BT_DOBOLD (1L<<21)
+#define BT_TOP (1L<<20) /* Show the top of the text */
wText_p wTextCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
wPos_t, wPos_t );
@@ -440,12 +464,34 @@ void wTextSetPosition( wText_p bt, int pos );
typedef int wDrawOpts;
#define wDrawOptTemp (1<<0)
#define wDrawOptNoClip (1<<1)
+#define wDrawOptTransparent (1<<2)
+#define wDrawOutlineFont (1<<3)
+#ifdef CURSOR_SURFACE
+#define wDrawOptCursor (1<<4)
+#define wDrawOptCursorClr (1<<5)
+#define wDrawOptCursorClr (1<<6)
+#define wDrawOptCursorRmv (1<<7)
+#define wDrawOptCursorQuit (1<<8)
+#define wDrawOptOpaque (1<<9)
+#endif
+
typedef enum {
wDrawLineSolid,
- wDrawLineDash }
+ wDrawLineDash,
+ wDrawLineDot,
+ wDrawLineDashDot,
+ wDrawLineDashDotDot,
+ wDrawLineCenter,
+ wDrawLinePhantom}
wDrawLineType_e;
+typedef enum {
+ wPolyLineStraight,
+ wPolyLineSmooth,
+ wPolyLineRound}
+ wPolyLine_e;
+
typedef int wAction_t;
#define wActionMove (1)
#define wActionLDown (2)
@@ -458,7 +504,13 @@ typedef int wAction_t;
#define wActionExtKey (9)
#define wActionWheelUp (10)
#define wActionWheelDown (11)
-#define wActionLast wActionWheelDown
+#define wActionLDownDouble (12)
+#define wActionModKey (13)
+#define wActionScrollUp (14)
+#define wActionScrollDown (15)
+#define wActionScrollLeft (16)
+#define wActionScrollRight (17)
+#define wActionLast wActionScrollRight
#define wRGB(R,G,B)\
@@ -474,6 +526,7 @@ typedef void (*wDrawActionCallBack_p)( wDraw_p, void*, wAction_t, wPos_t, wPos_t
#define BD_DIRECT (1L<<26)
#define BD_NOCAPTURE (1L<<27)
#define BD_NOFOCUS (1L<<28)
+#define BD_MODKEYS (1L<<29)
/* Create: */
wDraw_p wDrawCreate( wWin_p, wPos_t, wPos_t, const char *, long,
@@ -496,13 +549,15 @@ void wDrawString( wDraw_p, wPos_t, wPos_t, wAngle_t, const char *, wFont_p,
wFontSize_t, wDrawColor, wDrawOpts );
void wDrawFilledRectangle( wDraw_p, wPos_t, wPos_t, wPos_t, wPos_t,
wDrawColor, wDrawOpts );
-void wDrawFilledPolygon( wDraw_p, wPos_t [][2], wIndex_t, wDrawColor,
- wDrawOpts );
+void wDrawPolygon( wDraw_p, wPos_t [][2], wPolyLine_e [], wIndex_t, wDrawColor, wDrawWidth, wDrawLineType_e,
+ wDrawOpts, int, int );
void wDrawFilledCircle( wDraw_p, wPos_t, wPos_t, wPos_t, wDrawColor, wDrawOpts );
-void wDrawGetTextSize( wPos_t *, wPos_t *, wPos_t *, wDraw_p, const char *, wFont_p,
+void wDrawGetTextSize( wPos_t *, wPos_t *, wPos_t *, wPos_t *, wDraw_p, const char *, wFont_p,
wFontSize_t );
void wDrawClear( wDraw_p );
+void wDrawClearTemp( wDraw_p );
+wBool_t wDrawSetTempMode( wDraw_p, wBool_t );
void wDrawDelayUpdate( wDraw_p, wBool_t );
void wDrawClip( wDraw_p, wPos_t, wPos_t, wPos_t, wPos_t );
@@ -517,7 +572,7 @@ void wDrawSetSize( wDraw_p, wPos_t, wPos_t, void * );
void wDrawGetSize( wDraw_p, wPos_t *, wPos_t * );
/* Bitmaps */
-wDrawBitMap_p wDrawBitMapCreate( wDraw_p, int, int, int, int, const char * );
+wDrawBitMap_p wDrawBitMapCreate( wDraw_p, int, int, int, int, const unsigned char * );
void wDrawBitMap( wDraw_p, wDrawBitMap_p, wPos_t, wPos_t,
wDrawColor, wDrawOpts );
@@ -529,6 +584,8 @@ wBool_t wBitMapWriteFile( wDraw_p, const char * );
void * wDrawGetContext( wDraw_p );
void wDrawSaveImage( wDraw_p );
void wDrawRestoreImage( wDraw_p );
+int wDrawSetBackground( wDraw_p, char * path, char ** error);
+void wDrawShowBackground( wDraw_p, wPos_t pos_x, wPos_t pos_y, wPos_t width, wAngle_t angle, int screen);
/*------------------------------------------------------------------------------
*
@@ -537,7 +594,7 @@ void wDrawRestoreImage( wDraw_p );
void wInitializeFonts();
void wSelectFont( const char * );
wFontSize_t wSelectedFontSize( void );
-void wSetSelectionFontSize(int);
+void wSetSelectionFontSize(wFontSize_t);
#define F_TIMES (1)
#define F_HELV (2)
wFont_p wStandardFont( int, wBool_t, wBool_t );
@@ -548,22 +605,19 @@ wFont_p wStandardFont( int, wBool_t, wBool_t );
* Printing
*/
-typedef void (*wAddPrinterCallBack_p)( const char *, const char * );
-typedef void (*wAddMarginCallBack_p)( const char *, double, double, double, double );
-typedef void (*wAddFontAliasCallBack_p)( const char *, const char * );
typedef void (*wPrintSetupCallBack_p)( wBool_t );
wBool_t wPrintInit( void );
void wPrintSetup( wPrintSetupCallBack_p );
-void wPrintSetCallBacks( wAddPrinterCallBack_p, wAddMarginCallBack_p, wAddFontAliasCallBack_p );
+void wPrintGetMargins( double *, double *, double *, double * );
void wPrintGetPageSize( double *, double * );
-void wPrintGetPhysSize( double *, double * );
wBool_t wPrintDocStart( const char *, int, int * );
wDraw_p wPrintPageStart( void );
wBool_t wPrintPageEnd( wDraw_p );
void wPrintDocEnd( void );
wBool_t wPrintQuit( void );
void wPrintClip( wPos_t, wPos_t, wPos_t, wPos_t );
+const char * wPrintGetName( void );
/*------------------------------------------------------------------------------
@@ -607,6 +661,15 @@ typedef enum {
wAccelKey_LineFeed }
wAccelKey_e;
+typedef enum {
+ wModKey_None,
+ wModKey_Alt,
+ wModKey_Shift,
+ wModKey_Ctrl }
+ wModKey_e;
+
+void wDoAccelHelp( wAccelKey_e key, void * );
+
/* Creation CallBacks */
typedef void (*wMenuCallBack_p)( void * );
typedef void (*wMenuListCallBack_p)( int, const char *, void * );
@@ -656,6 +719,7 @@ void wAttachAccelKey( wAccelKey_e, int, wAccelKeyCallBack_p, void * );
*/
#define FS_MULTIPLEFILES 1
+#define FS_PICTURES 2
struct wFilSel_t;
typedef enum {
@@ -726,4 +790,11 @@ wPos_t wStatusGetHeight(long flags);
void wStatusSetValue(wStatus_p b, const char * arg);
void wStatusSetWidth(wStatus_p b, wPos_t width);
+
+/*-------------------------------------------------------------------------------
+ * User Preferences
+ */
+
+#define PREFSECTION "Preference"
+#define LARGEICON "LargeIcons"
#endif
diff --git a/app/wlib/mswlib/CMakeLists.txt b/app/wlib/mswlib/CMakeLists.txt
index 82d8371..07558f9 100644
--- a/app/wlib/mswlib/CMakeLists.txt
+++ b/app/wlib/mswlib/CMakeLists.txt
@@ -1,12 +1,13 @@
+find_package(FreeImage REQUIRED)
+
FILE(GLOB HEADERS *.h)
SET(SOURCES
-# checksum.c
+ backgnd.c
getopt.c
mswbox.c
mswbutt.c
mswbitmap.c
- mswchksm.c
mswchoic.c
mswcolor.c
mswdraw.c
@@ -19,14 +20,15 @@ SET(SOURCES
mswpref.c
mswprint.c
mswsplash.c
- mswstatus.c
+ mswstatus.c
mswtext.c
gwin32.c
simple-gettext.c
+ utf8conv.c
)
+include_directories(${FREEIMAGE_INCLUDE_PATH})
INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR})
-# INCLUDE_DIRECTORIES(${XTRKCAD_BINARY_DIR})
IF(XTRKCAD_USE_GETTEXT)
IF(WIN32)
@@ -37,4 +39,13 @@ ENDIF(XTRKCAD_USE_GETTEXT)
ADD_LIBRARY(xtrkcad-wlib ${HEADERS} ${SOURCES})
TARGET_LINK_LIBRARIES(xtrkcad-wlib Htmlhelp msimg32 shlwapi)
+target_link_libraries(xtrkcad-wlib ${FREEIMAGE_LIBRARY})
+
+install(FILES
+ ${FREEIMAGE_SHAREDLIB}
+ DESTINATION ${XTRKCAD_BIN_INSTALL_DIR}
+ )
+if(XTRKCAD_TESTING AND CMOCKA_FOUND)
+ add_subdirectory( unittest )
+endif()
diff --git a/app/wlib/mswlib/backgnd.c b/app/wlib/mswlib/backgnd.c
new file mode 100644
index 0000000..d35f19a
--- /dev/null
+++ b/app/wlib/mswlib/backgnd.c
@@ -0,0 +1,220 @@
+/** \file backgnd.c
+* Layout background image
+*/
+
+/* XTrkCad - Model Railroad CAD
+* Copyright (C) 2018 Martin Fischer
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <windows.h>
+
+#include <FreeImage.h>
+#include "i18n.h"
+#include "mswint.h"
+
+static char *lastErrorMessage; /**< store last message from FreeImage */
+#define ERRORPUNCTUATION " : "
+
+/**
+ * FreeImage error handler
+ * \param fif Format / Plugin responsible for the error
+ * \param message Error message
+ */
+
+static void
+HandleFreeImageError(FREE_IMAGE_FORMAT fif, const char *message)
+{
+ unsigned totalLength = strlen(message) + 1;
+
+ if (fif != FIF_UNKNOWN) {
+ totalLength += strlen(FreeImage_GetFormatFromFIF(fif)) + strlen(ERRORPUNCTUATION);
+ }
+
+ lastErrorMessage = malloc(totalLength);
+
+ if (fif != FIF_UNKNOWN) {
+ sprintf(lastErrorMessage,
+ "%s" ERRORPUNCTUATION "%s",
+ FreeImage_GetFormatFromFIF(fif),
+ message);
+ } else {
+ strcpy(lastErrorMessage, message);
+ }
+}
+
+/**
+* Load the background image
+* \param bd drawing context
+* \param path filename for image file, if NULL the existing background will be removed
+* \param error returned error message
+* \return -1 unsupported or invalid file, 0 success, 1 background removed
+*/
+
+int
+wDrawSetBackground(wDraw_p bd, char * path, char ** error)
+{
+ FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
+
+ FreeImage_SetOutputMessage(HandleFreeImageError);
+
+ if (lastErrorMessage) {
+ free(lastErrorMessage);
+ lastErrorMessage = NULL;
+ }
+
+ if (path) {
+ // check the file signature and deduce its format
+ // (the second argument is currently not used by FreeImage)
+ fif = FreeImage_GetFileType(path, 0);
+
+ if (fif == FIF_UNKNOWN) {
+ // no signature ?
+ // try to guess the file format from the file extension
+ fif = FreeImage_GetFIFFromFilename(path);
+ }
+
+ // check that the plugin has reading capabilities ...
+ if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
+ // ok, let's load the file
+ bd->background = FreeImage_Load(fif, path, 0);
+
+ // unless a bad file format, we are done !
+ if (!bd->background) {
+ *error = lastErrorMessage;
+ return (-1);
+ } else {
+ return (0);
+ }
+ } else {
+ *error = strdup(_("Image file is invalid or cannot be read."));
+ return (-1);
+ }
+ } else {
+ if (bd->background) {
+ FreeImage_Unload(bd->background);
+ bd->background = 0;
+ }
+
+ return (1);
+ }
+}
+
+/**
+* Draw background to screen. The background will be sized and rotated before being shown. The bitmap
+* is scaled so that the width is equal to size. The height is changed proportionally.
+*
+* \param bd drawing context
+* \param pos_x, pos_y bitmap position
+* \param size desired width after scaling
+* \param angle
+* \param screen visibility of bitmap in percent
+*/
+
+void
+wDrawShowBackground(wDraw_p bd, wPos_t pos_x, wPos_t pos_y, wPos_t size,
+ wAngle_t angle, int screen)
+{
+ if (bd->background) {
+ double scale;
+ FIBITMAP *tmp;
+ FIBITMAP *rotated;
+
+ if (size == 0) {
+ scale = 1.0;
+ } else {
+ scale = (double)size / FreeImage_GetWidth(bd->background);
+ }
+
+ tmp = FreeImage_RescaleRect(bd->background,
+ (int)((double)FreeImage_GetWidth(bd->background) * scale),
+ (int)((double)FreeImage_GetHeight(bd->background) * scale),
+ 0,
+ 0,
+ FreeImage_GetWidth(bd->background),
+ FreeImage_GetHeight(bd->background),
+ FILTER_BILINEAR,
+ 0);
+ FreeImage_AdjustColors(tmp, screen, -screen, 1.0, FALSE);
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(tmp);
+
+ switch (image_type) {
+ case FIT_BITMAP:
+ switch (FreeImage_GetBPP(tmp)) {
+ case 8: {
+ BYTE color = 255;
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+
+ case 24: // we could also use 'RGBTRIPLE color' here
+ case 32: {
+ RGBQUAD color = { 255, 255, 255, 0 };
+ // for 24-bit images, the first 3 bytes will be read
+ // for 32-bit images, the first 4 bytes will be read
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+ }
+
+ break;
+
+ case FIT_UINT16: {
+ WORD color = 255;
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+
+ case FIT_RGB16: // we could also use 'FIRGB16 color' here
+ case FIT_RGBA16: {
+ FIRGBA16 color = { 255, 255, 255, 0 };
+ // for RGB16 images, the first 3 WORD will be read
+ // for RGBA16 images, the first 4 WORD will be read
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+
+ case FIT_FLOAT: {
+ float color = 1.0F;
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+
+ case FIT_RGBF: // we could also use 'FIRGBF color' here
+ case FIT_RGBAF: {
+ FIRGBAF color = { 1, 1, 1, 0 };
+ // for RGBF images, the first 3 float will be read
+ // for RGBAF images, the first 4 float will be read
+ rotated = FreeImage_Rotate(tmp, angle, &color);
+ }
+ break;
+ }
+
+ SetDIBitsToDevice(bd->hDc,
+ pos_x,
+ bd->h - pos_y - FreeImage_GetHeight(rotated),
+ FreeImage_GetWidth(rotated),
+ FreeImage_GetHeight(rotated),
+ 0, 0,
+ 0,
+ FreeImage_GetHeight(rotated),
+ FreeImage_GetBits(rotated),
+ FreeImage_GetInfo(rotated),
+ DIB_RGB_COLORS);
+ FreeImage_Unload(tmp);
+ FreeImage_Unload(rotated);
+ }
+} \ No newline at end of file
diff --git a/app/wlib/mswlib/mswbitmap.c b/app/wlib/mswlib/mswbitmap.c
index e369e78..95b8a69 100644
--- a/app/wlib/mswlib/mswbitmap.c
+++ b/app/wlib/mswlib/mswbitmap.c
@@ -24,10 +24,12 @@
#include <windows.h>
#include <string.h>
#include <malloc.h>
+#include <math.h>
#include <stdlib.h>
#include <commdlg.h>
#include <stdio.h>
#include <assert.h>
+#include "misc.h"
#include "mswint.h"
#include "i18n.h"
@@ -177,14 +179,15 @@ void mswDrawIcon(
memset( bmiInfo->bmiColors, 0, bm->colorcnt * sizeof( RGBQUAD ));
memset( &bmiInfo->bmiColors[ bm->transparent ], 0xFF, sizeof( RGBQUAD ));
}
+
StretchDIBits(hDc, offw, offh,
- bmiInfo->bmiHeader.biWidth,
- bmiInfo->bmiHeader.biHeight,
- 0, 0,
- bmiInfo->bmiHeader.biWidth,
- bmiInfo->bmiHeader.biHeight,
- bm->pixels, bmiInfo,
- DIB_RGB_COLORS, SRCAND);
+ (int)ceil(bmiInfo->bmiHeader.biWidth*scaleIcon),
+ (int)ceil(bmiInfo->bmiHeader.biHeight*scaleIcon),
+ 0, 0,
+ bmiInfo->bmiHeader.biWidth,
+ bmiInfo->bmiHeader.biHeight,
+ bm->pixels, bmiInfo,
+ DIB_RGB_COLORS, SRCAND);
/* now paint the bitmap with transparent set to black */
if( bm->type == mswIcon_bitmap ) {
@@ -221,16 +224,16 @@ void mswDrawIcon(
}
memset( &bmiInfo->bmiColors[ bm->transparent ], 0, sizeof( RGBQUAD ));
}
-
+
/* show the bitmap */
StretchDIBits(hDc, offw, offh,
- bmiInfo->bmiHeader.biWidth,
- bmiInfo->bmiHeader.biHeight,
- 0, 0,
- bmiInfo->bmiHeader.biWidth,
- bmiInfo->bmiHeader.biHeight,
- bm->pixels, bmiInfo,
- DIB_RGB_COLORS, SRCPAINT);
+ (int)ceil(bmiInfo->bmiHeader.biWidth*scaleIcon),
+ (int)ceil(bmiInfo->bmiHeader.biHeight*scaleIcon),
+ 0, 0,
+ bmiInfo->bmiHeader.biWidth,
+ bmiInfo->bmiHeader.biHeight,
+ bm->pixels, bmiInfo,
+ DIB_RGB_COLORS, SRCPAINT);
/* forget the data */
free( bmiInfo );
@@ -434,11 +437,14 @@ wIcon_p wIconCreatePixMap( char *pm[])
/* look up pixel info in color table */
k = 0;
- while( pixel != keys[ k ] )
+ while(k < col && pixel != keys[ k ] )
k++;
-
- /* save the index into color table */
- *(cq + j) = k;
+ if (pixel == keys[k]) {
+ /* save the index into color table */
+ *(cq + j) = k;
+ } else {
+ *(cq + j) = 0;
+ }
}
}
free( keys );
@@ -507,4 +513,4 @@ wBitmapCreate( wWin_p parent, wPos_t x, wPos_t y, long option, wIcon_p iconP )
control->data = iconP;
return (wControl_p)control;
-} \ No newline at end of file
+}
diff --git a/app/wlib/mswlib/mswbutt.c b/app/wlib/mswlib/mswbutt.c
index d213695..16f31c1 100644
--- a/app/wlib/mswlib/mswbutt.c
+++ b/app/wlib/mswlib/mswbutt.c
@@ -37,11 +37,7 @@ int kludge12 = 0;
*****************************************************************************
*/
-
-
static XWNDPROC oldButtProc = NULL;
-static XWNDPROC newButtProc;
-
struct wButton_t {
WOBJ_COMMON
@@ -88,9 +84,9 @@ static void drawButton(
COLORREF colF;
#define LEFT (0)
-#define RIGHT (bm->w+10)
+#define RIGHT (LONG)ceil(bm->w*scaleIcon+10)
#define TOP (0)
-#define BOTTOM (bm->h+10)
+#define BOTTOM (LONG)ceil(bm->h*scaleIcon+10)
/* get the lightest and the darkest color to use */
colL = GetSysColor( COLOR_BTNHIGHLIGHT );
@@ -239,6 +235,7 @@ static LRESULT buttPush( wControl_p b, HWND hWnd, UINT message, WPARAM wParam, L
DRAWITEMSTRUCT * di = (DRAWITEMSTRUCT *)lParam;
wBool_t selected;
+
switch (message) {
case WM_COMMAND:
if (bb->action /*&& !bb->busy*/) {
@@ -253,8 +250,8 @@ static LRESULT buttPush( wControl_p b, HWND hWnd, UINT message, WPARAM wParam, L
break;
mi->CtlType = ODT_BUTTON;
mi->CtlID = wParam;
- mi->itemWidth = bb->w;
- mi->itemHeight = bb->h;
+ mi->itemWidth = (UINT)ceil(bb->w*scaleIcon);
+ mi->itemHeight = (UINT)ceil(bb->h*scaleIcon);
} return 0L;
case WM_DRAWITEM:
@@ -369,8 +366,8 @@ wButton_p wButtonCreate(
b->selected = 0;
mswComputePos( (wControl_p)b, x, y );
if (b->option&BO_ICON) {
- width = bm->w+10;
- h = bm->h+10;
+ width = (wPos_t)ceil(bm->w*scaleIcon)+10;
+ h = (int)ceil(bm->h*scaleIcon)+10;
b->icon = bm;
} else {
width = (wPos_t)(width*mswScale);
@@ -405,5 +402,9 @@ wButton_p wButtonCreate(
}
if ( !mswThickFont )
SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L );
+
+
+ InvalidateRect(b->hWnd, &rect, TRUE);
+
return b;
}
diff --git a/app/wlib/mswlib/mswchksm.c b/app/wlib/mswlib/mswchksm.c
deleted file mode 100644
index 602c204..0000000
--- a/app/wlib/mswlib/mswchksm.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include <stdio.h>
-#include <sys/stat.h>
-#include "../include/wlib.h"
-#ifdef WINDOWS
-#include <windows.h>
-#include "mswint.h"
-#endif
-
-#define HEWHDROFFSET (0x3C)
-
-static FILE * openfile( const char * fn, const char * mode, long * fileSize )
-{
- unsigned short PageCnt;
- long FileSize;
- FILE *fp;
- struct stat Stat;
- fp = fopen( fn, mode );
- if (fp == NULL) {
- perror( "fopen" );
- return NULL;
- }
- fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past signature */
- fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past pagesize */
- FileSize = PageCnt;
- fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past pagesize */
- if ( FileSize == 0L )
- FileSize = PageCnt * 512L;
- else
- FileSize += (PageCnt - 1) * 512L;
- *fileSize = FileSize;
- stat( fn, &Stat );
- *fileSize = (long)Stat.st_size;
- fprintf( stderr, "size1 = %ld, size2 = %ld\n", FileSize, (long)Stat.st_size );
- return fp;
-}
-
-
-static unsigned short mswCheck16( FILE * fp, long FileSize, unsigned short * sum16stored )
-{
- unsigned short int sum16, NxtInt;
- long x;
- unsigned char NxtChar;
- sum16 = 0;
- fseek(fp, 0, SEEK_SET);
-
- for (x=0L; x<FileSize/2L; x++) {
- fread( &NxtInt, sizeof NxtInt, 1, fp );
- if (x == 9)
- *sum16stored = NxtInt;
- else
- sum16 += NxtInt;
- }
- if (FileSize%2) {
- fread( &NxtChar, sizeof NxtChar, 1, fp );
- sum16 += (unsigned int)NxtChar;
- }
- return sum16;
-}
-
-
-static int mswCheck32( FILE * fp, long FileSize, long * sum32off, unsigned long * sum32computed, unsigned long * sum32stored )
-{
- unsigned long sum32, NxtLong;
- long x;
- long NewHdrOffset;
- unsigned char NxtByte, y;
-
- fseek( fp, HEWHDROFFSET, SEEK_SET );
- fread( &NewHdrOffset, sizeof NewHdrOffset, 1, fp );
- if (NewHdrOffset == 0) {
- fprintf( stderr, "NewHdrOffset == 0\n" );
- return 0;
- }
- NewHdrOffset = (NewHdrOffset/4)*4;
- *sum32off = NewHdrOffset + 8;
- sum32 = 0L;
- fseek( fp, 0, SEEK_SET );
- for (x = ( NewHdrOffset + 8 ) / 4; x; x-- ) {
- fread( &NxtLong, sizeof NxtLong, 1, fp );
- sum32 += NxtLong;
- }
- fread( sum32stored, sizeof sum32stored, 1, fp );
-
- for (x=0; x<(FileSize-NewHdrOffset - 12)/4; x++) {
- fread( &NxtLong, sizeof NxtLong, 1, fp );
- sum32 += NxtLong;
- }
- if ( 0L != (x=FileSize%4L) ) {
- NxtLong = 0L;
- for (y=0; y<x; y++ ) {
- fread( &NxtByte, sizeof NxtByte, 1, fp );
- NxtLong += (unsigned long)NxtByte << (8*y);
- }
- sum32 += NxtLong;
- }
- *sum32computed = sum32;
- return 1;
-}
-
-
-#ifdef WINDOWS
-wBool_t wCheckExecutable( void )
-{
- char fileName[1024];
- FILE * fp;
- long FileSize;
- GetModuleFileName( mswHInst, fileName, sizeof fileName );
- fp = openfile( fileName, "rb", &FileSize );
-#ifdef LATER
- {
- unsigned long int sum32offset, sum32computed, sum32stored;
- if ( ! mswCheck32( fp, FileSize, &sum32offset, &sum32computed, &sum32stored ) )
- return FALSE;
- return sum32computed == sum32stored;
- }
-#else
- {
- unsigned short int sum16computed, sum16stored;
- sum16computed = mswCheck16( fp, FileSize, &sum16stored );
- sum16computed += sum16stored;
- return sum16computed == 0xFFFF;
- }
-#endif
-}
-#endif
diff --git a/app/wlib/mswlib/mswdraw.c b/app/wlib/mswlib/mswdraw.c
index bf0ab76..c2739e6 100644
--- a/app/wlib/mswlib/mswdraw.c
+++ b/app/wlib/mswlib/mswdraw.c
@@ -1,8 +1,26 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswdraw.c,v 1.6 2009-05-15 18:16:16 m_fischer Exp $
+/** \file mswdraw.c
+ * Draw basic geometric shapes
*/
-#define _WIN32_WINNT 0x0500 /* for wheel mouse supposrt */
+/* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _WIN32_WINNT 0x0600 /* for wheel mouse supposrt */
#include <windows.h>
#include <string.h>
#include <malloc.h>
@@ -16,8 +34,12 @@
#else
#define wFont_t tagLOGFONT
#endif
+
+#include "misc.h"
#include "mswint.h"
+#include <FreeImage.h>
+wBool_t wDrawDoTempDraw = TRUE;
/*
*****************************************************************************
*
@@ -39,6 +61,8 @@ static long clrOp = 0xbb0226;
#define CENTERMARK_LENGTH 6
+bool bDrawMainBM = 0;
+
#ifdef SLOW
static wPos_t XPIX2INCH( wDraw_p d, int ix )
{
@@ -119,6 +143,31 @@ void wDrawDelayUpdate(
{
}
+wBool_t wDrawSetTempMode(
+ wDraw_p bd,
+ wBool_t bTemp )
+{
+ wBool_t rc = bd->bTempMode;
+ bd->bTempMode = bTemp;
+ if (rc == FALSE && bTemp == TRUE) {
+ // Main to Temp drawing
+ // Copy mainBM to tempBM
+ wDrawClearTemp( bd );
+ if (bDrawMainBM) return rc;
+ HDC hDcOld = CreateCompatibleDC(bd->hDc);
+ HBITMAP hBmOld = SelectObject(hDcOld, bd->hBmMain);
+ SelectObject(bd->hDc, bd->hBmTemp);
+ BitBlt(bd->hDc, 0, 0,
+ bd->w, bd->h,
+ hDcOld, 0, 0,
+ SRCCOPY);
+ SelectObject(hDcOld, hBmOld);
+ DeleteDC(hDcOld);
+ bd->bCopiedMain = TRUE;
+ }
+ return rc;
+}
+
/**
* Sets the proper pen and composition for the next drawing operation
*
@@ -130,68 +179,83 @@ void wDrawDelayUpdate(
* \param dc IN color
* \param dopt IN ????
*/
-
static void setDrawMode(
- HDC hDc,
wDraw_p d,
wDrawWidth dw,
wDrawLineType_e lt,
wDrawColor dc,
wDrawOpts dopt )
{
- int mode;
+ long centerPen[] = {40,10,20,10};
+ long phantomPen[] = {40,10,20,10,20,10};
+
HPEN hOldPen;
static wDraw_p d0;
static wDrawWidth dw0 = -1;
static wDrawLineType_e lt0 = (wDrawLineType_e)-1;
static wDrawColor dc0 = -1;
- static int mode0 = -1;
static LOGBRUSH logBrush = { 0, 0, 0 };
DWORD penStyle;
+ if ( wDrawDoTempDraw && (dopt & wDrawOptTemp) )
+ SelectObject(d->hDc, d->hBmTemp);
+ else
+ SelectObject(d->hDc, d->hBmMain);
+
if ( d->hasPalette ) {
int winPaletteClock = mswGetPaletteClock();
if ( d->paletteClock < winPaletteClock ) {
- RealizePalette( hDc );
+ RealizePalette( d->hDc );
d->paletteClock = winPaletteClock;
}
}
- if (dopt & wDrawOptTemp) {
- mode = R2_NOTXORPEN;
- } else {
- mode = R2_COPYPEN;
- }
- SetROP2( hDc, mode );
- if ( d == d0 && mode == mode0 && dw0 == dw && lt == lt0 && dc == dc0 )
+ SetROP2( d->hDc, R2_COPYPEN );
+ if ( d == d0 && dw0 == dw && lt == lt0 && dc == dc0 )
return;
// make sure that the line width is at least 1!
if( !dw )
dw++;
- d0 = d; mode0 = mode; dw0 = dw; lt0 = lt; dc0 = dc;
+ d0 = d; dw0 = dw; lt0 = lt; dc0 = dc;
+
+ void * penarray = NULL;
+ int penarray_size = 0;
logBrush.lbColor = mswGetColor(d->hasPalette,dc);
if ( lt==wDrawLineSolid ) {
penStyle = PS_GEOMETRIC | PS_SOLID;
if ( noFlatEndCaps == FALSE )
penStyle |= PS_ENDCAP_FLAT;
- d->hPen = ExtCreatePen( penStyle,
- dw,
- &logBrush,
- 0,
- NULL );
- /*colorPalette.palPalEntry[dc] );*/
- } else {
- d->hPen = CreatePen( PS_DOT, 0, mswGetColor( d->hasPalette, dc ) );
- }
- hOldPen = SelectObject( hDc, d->hPen );
+ } else if (lt == wDrawLineDot) {
+ penStyle = PS_GEOMETRIC | PS_DOT;
+ } else if (lt == wDrawLineDash) {
+ penStyle = PS_GEOMETRIC | PS_DASH;
+ } else if (lt == wDrawLineDashDot) {
+ penStyle = PS_GEOMETRIC | PS_DASHDOT;
+ } else if ( lt == wDrawLineDashDotDot){
+ penStyle = PS_GEOMETRIC | PS_DASHDOTDOT;
+ } else if ( lt == wDrawLineCenter) {
+ penStyle = PS_GEOMETRIC | PS_USERSTYLE;
+ penarray = &centerPen;
+ penarray_size = sizeof(centerPen)/sizeof(long);
+ } else if ( lt == wDrawLinePhantom) {
+ penStyle = PS_GEOMETRIC | PS_USERSTYLE;
+ penarray = &phantomPen;
+ penarray_size = sizeof(phantomPen) / sizeof(long);
+ } else
+ penStyle = PS_GEOMETRIC | PS_SOLID;
+ d->hPen = ExtCreatePen( penStyle,
+ dw,
+ &logBrush,
+ penarray_size,
+ penarray );
+ hOldPen = SelectObject( d->hDc, d->hPen );
DeleteObject( hOldPen );
}
static void setDrawBrush(
- HDC hDc,
wDraw_p d,
wDrawColor dc,
wDrawOpts dopt )
@@ -200,7 +264,7 @@ static void setDrawBrush(
static wDraw_p d0;
static wDrawColor dc0 = -1;
- setDrawMode( hDc, d, 0, wDrawLineSolid, dc, dopt );
+ setDrawMode( d, 0, wDrawLineSolid, dc, dopt );
if ( d == d0 && dc == dc0 )
return;
@@ -208,7 +272,7 @@ static void setDrawBrush(
d->hBrush = CreateSolidBrush(
mswGetColor(d->hasPalette,dc) );
- hOldBrush = SelectObject( hDc, d->hBrush );
+ hOldBrush = SelectObject( d->hDc, d->hBrush );
DeleteObject( hOldBrush );
}
@@ -270,7 +334,7 @@ void wDrawLine(
{
POINT p0, p1;
RECT rect;
- setDrawMode( d->hDc, d, dw, lt, dc, dopt );
+ setDrawMode( d, dw, lt, dc, dopt );
p0.x = XINCH2PIX(d,p0x);
p0.y = YINCH2PIX(d,p0y);
p1.x = XINCH2PIX(d,p1x);
@@ -381,7 +445,7 @@ void wDrawArc(
pe.x = XINCH2PIX(d,(wPos_t)pex);
pe.y = YINCH2PIX(d,(wPos_t)pey);
- setDrawMode( d->hDc, d, dw, lt, dc, dopt );
+ setDrawMode( d, dw, lt, dc, dopt );
if (dw == 0)
dw = 1;
@@ -495,7 +559,7 @@ void wDrawPoint(
return;
if ( p0.x >= d->w || p0.y >= d->h )
return;
- setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt );
+ setDrawMode( d, 0, wDrawLineSolid, dc, dopt );
SetPixel( d->hDc, p0.x, p0.y, mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/ );
if (d->hWnd) {
@@ -689,6 +753,7 @@ void wDrawGetTextSize(
wPos_t *w,
wPos_t *h,
wPos_t *d,
+ wPos_t *a,
wDraw_p bd,
const char * text,
wFont_p fp,
@@ -717,12 +782,25 @@ void wDrawGetTextSize(
*w = XPIXELSTOINCH( bd, x );
*h = YPIXELSTOINCH( bd, y );
*d = YPIXELSTOINCH(bd, textMetric.tmDescent );
+ *a = YPIXELSTOINCH(bd, textMetric.tmAscent );
SelectObject( bd->hDc, prevFont );
DeleteObject( newFont );
fp->lfHeight = oldLfHeight;
}
-
+/**
+ * Draw text
+ *
+ * \param d device context
+ * \param px position x
+ * \param py position y
+ * \param angle drawing angle
+ * \param text text to print
+ * \param fp font
+ * \param siz font size
+ * \param dc color
+ * \param dopts drawing options
+ */
void wDrawString(
wDraw_p d,
wPos_t px,
@@ -736,8 +814,6 @@ void wDrawString(
{
int x, y;
HFONT newFont, prevFont;
- HDC newDc;
- HBITMAP oldBm, newBm;
DWORD extent;
int w, h;
RECT rect;
@@ -756,61 +832,47 @@ void wDrawString(
y = YINCH2PIX(d,py) + (int)(mswcos(angle)*fp->lfHeight-0.5);
if (noNegDrawArgs > 0 && (x < 0 || y < 0)) {
+ DeleteObject(newFont);
return;
}
- if (dopts & wDrawOptTemp) {
- setDrawMode(d->hDc, d, 0, wDrawLineSolid, dc, dopts);
- newDc = CreateCompatibleDC(d->hDc);
- prevFont = SelectObject(newDc, newFont);
- extent = GetTextExtent(newDc, CAST_AWAY_CONST text, strlen(text));
- w = LOWORD(extent);
- h = HIWORD(extent);
+ setDrawMode( d, 0, wDrawLineSolid, dc, dopts );
+ prevFont = SelectObject(d->hDc, newFont);
+ SetBkMode(d->hDc, TRANSPARENT);
- if (h > w) {
- w = h;
+ if (dopts & wDrawOutlineFont) {
+ HPEN oldPen;
+ BeginPath(d->hDc);
+ TextOut(d->hDc, x, y, text, strlen(text));
+ EndPath(d->hDc);
+
+ // Now draw outline text
+ oldPen = SelectObject(d->hDc,
+ CreatePen(PS_SOLID, 1,
+ mswGetColor(d->hasPalette, dc)));
+ StrokePath(d->hDc);
+ SelectObject(d->hDc, oldPen);
+ } else {
+ COLORREF old;
+
+ old = SetTextColor(d->hDc, mswGetColor(d->hasPalette,
+ dc));
+ TextOut(d->hDc, x, y, text, strlen(text));
+ SetTextColor(d->hDc, old);
}
- newBm = CreateCompatibleBitmap(d->hDc, w*2, w*2);
- oldBm = SelectObject(newDc, newBm);
- rect.top = rect.left = 0;
- rect.bottom = rect.right = w*2;
- FillRect(newDc, &rect, GetStockObject(WHITE_BRUSH));
- TextOut(newDc, w, w, text, strlen(text));
- BitBlt(d->hDc, x-w, y-w, w*2, w*2, newDc, 0, 0, tmpOp);
- SelectObject(newDc, oldBm);
- DeleteObject(newBm);
- SelectObject(newDc, prevFont);
- DeleteDC(newDc);
-
- if (d->hWnd) {
- rect.top = y-(w+1);
- rect.bottom = y+(w+1);
- rect.left = x-(w+1);
- rect.right = x+(w+1);
- myInvalidateRect(d, &rect);
- }
- } else {
- COLORREF old;
- prevFont = SelectObject(d->hDc, newFont);
- SetBkMode(d->hDc, TRANSPARENT);
- old = SetTextColor(d->hDc, mswGetColor(d->hasPalette,
- dc));
- TextOut(d->hDc, x, y, text, strlen(text));
- SetTextColor(d->hDc, old);
extent = GetTextExtent(d->hDc, CAST_AWAY_CONST text, strlen(text));
SelectObject(d->hDc, prevFont);
w = LOWORD(extent);
h = HIWORD(extent);
if (d->hWnd) {
- rect.top = y-(w+h+1);
- rect.bottom = y+(w+h+1);
- rect.left = x-(w+h+1);
- rect.right = x+(w+h+1);
+ rect.top = y - (w + h + 1);
+ rect.bottom = y + (w + h + 1);
+ rect.left = x - (w + h + 1);
+ rect.right = x + (w + h + 1);
myInvalidateRect(d, &rect);
}
- }
DeleteObject(newFont);
fp->lfHeight = oldLfHeight;
@@ -846,9 +908,9 @@ wFontSize_t wSelectedFontSize( void )
return fontSize;
}
-void wSetSelectedFontSize(int size)
+void wSetSelectedFontSize(wFontSize_t size)
{
- fontSize = (wFontSize_t)size;
+ fontSize = size;
}
/*
@@ -870,10 +932,18 @@ void wDrawFilledRectangle(
wDrawColor color,
wDrawOpts opts )
{
+ int mode;
RECT rect;
if (d == NULL)
return;
- setDrawBrush( d->hDc, d, color, opts );
+ setDrawBrush( d, color, opts );
+ if (opts & wDrawOptTransparent) {
+ mode = R2_NOTXORPEN;
+ }
+ else {
+ mode = R2_COPYPEN;
+ }
+ SetROP2(d->hDc, mode);
rect.left = XINCH2PIX(d,px);
rect.right = XINCH2PIX(d,px+sx);
rect.top = YINCH2PIX(d,py+sy);
@@ -903,103 +973,230 @@ void wDrawFilledRectangle(
}
#ifdef DRAWFILLPOLYLOG
-static FILE * logF;
+ static FILE * logF;
#endif
-static int wFillPointsMax = 0;
-static POINT * wFillPoints;
+
+static dynArr_t wFillPoints_da;
+static dynArr_t wFillType_da;
+
+#define POINTTYPE(N) DYNARR_N( BYTE, wFillType_da, (N) )
+#define POINTPOS(N) DYNARR_N( POINT, wFillPoints_da, (N) )
+
+/**
+ * Add a point definition to the list. The clipping rectangle is recalculated to
+ * include the new point.
+ *
+ * \param d IN drawing context
+ * \param pk IN index of new point
+ * \param pp IN pointer to the point's coordinates
+ * \param type IN line type
+ * \param pr IN/OUT clipping rectangle
+ */
static void addPoint(
- int * pk,
- POINT * pp,
- RECT * pr )
+ wDraw_p d,
+ int pk,
+ coOrd * pp,
+ BYTE type, RECT * pr)
{
+ POINT p;
+ p.x = XINCH2PIX(d, pp->x);
+ p.y = YINCH2PIX(d, pp->y);
+
#ifdef DRAWFILLPOLYLOG
-fprintf( logF, " q[%d] = {%d,%d}\n", *pk, pp->x, pp->y );
+ fprintf(logF, " q[%d] = {%d,%d}\n", pk, p.x, p.y);
#endif
- if ( *pk > 0 &&
- wFillPoints[(*pk)-1].x == pp->x && wFillPoints[(*pk)-1].y == pp->y )
- return;
- wFillPoints[ (*pk)++ ] = *pp;
- if (pp->x<pr->left)
- pr->left = pp->x;
- if (pp->x>pr->right)
- pr->right = pp->x;
- if (pp->y<pr->top)
- pr->top = pp->y;
- if (pp->y>pr->bottom)
- pr->bottom = pp->y;
+
+ DYNARR_N(POINT, wFillPoints_da, pk) = p;
+ DYNARR_N(BYTE, wFillType_da, pk) = type;
+
+ if (p.x < pr->left) {
+ pr->left = p.x;
+ }
+ if (p.x > pr->right) {
+ pr->right = p.x;
+ }
+ if (p.y < pr->top) {
+ pr->top = p.y;
+ }
+ if (p.y > pr->bottom) {
+ pr->bottom = p.y;
+ }
}
-void wDrawFilledPolygon(
- wDraw_p d,
- wPos_t p[][2],
- int cnt,
- wDrawColor color,
- wDrawOpts opts )
-{
- RECT rect;
- int i, k;
- POINT p0, p1, q0, q1;
- static POINT zero = { 0, 0 };
- wBool_t p1Clipped;
+/**
+ * Draw a polyline consisting of straights with smoothed or rounded corners.
+ * Optionally the area can be filled.
+ *
+ * \param d IN drawing context
+ * \param node IN 2 dimensional array of coordinates
+ * \param type IN type of corener (vertex, smooth or round)
+ * \param cnt IN number of points
+ * \param color IN color
+ * \param dw IN line width
+ * \param lt IN line type
+ * \param opts IN drawing options
+ * \param fill IN area will be filled if true
+ * \param open IN do not close area
+ */
- if (d == NULL)
- return;
- if (cnt*2 > wFillPointsMax) {
- wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL );
- if (wFillPoints == NULL) {
- fputs("can't realloc wFillPoints\n", stderr);
- abort();
+void wDrawPolygon(
+ wDraw_p d,
+ wPos_t node[][2],
+ wPolyLine_e type[],
+ wIndex_t cnt,
+ wDrawColor color,
+ wDrawWidth dw,
+ wDrawLineType_e lt,
+ wDrawOpts opts,
+ int fill,
+ int open)
+{
+ RECT rect;
+ int i, prevNode, nextNode;
+ int pointCount = 0;
+ coOrd endPoint0, endPoint1, controlPoint0, controlPoint1;
+ coOrd point, startingPoint;
+ BOOL rc;
+ int closed = 0;
+
+ if (d == NULL) {
+ return;
+ }
+
+ // make sure the array for the points is large enough
+ // worst case are rounded corners that require 4 points
+ DYNARR_RESET(POINT,wFillPoints_da);
+ DYNARR_SET(POINT,wFillPoints_da,(cnt + 1) * 4);
+ DYNARR_RESET(BYTE,wFillType_da);
+ DYNARR_SET(POINT,wFillType_da, (cnt + 1) * 4);
+
+ BeginPath(d->hDc);
+
+ if (fill) {
+ int mode;
+ setDrawBrush(d, color, opts);
+ if (opts & wDrawOptTransparent) {
+ mode = R2_NOTXORPEN;
}
- wFillPointsMax = cnt*2;
- }
- setDrawBrush( d->hDc, d, color, opts );
- p1.x = rect.left = rect.right = XINCH2PIX(d,p[cnt-1][0]-1);
- p1.y = rect.top = rect.bottom = YINCH2PIX(d,p[cnt-1][1]+1);
-#ifdef DRAWFILLPOLYLOG
-logF = fopen( "log.txt", "a" );
-fprintf( logF, "\np[%d] = {%d,%d}\n", cnt-1, p1.x, p1.y );
-#endif
- p1Clipped = FALSE;
- for ( i=k=0; i<cnt; i++ ) {
- p0 = p1;
- p1.x = XINCH2PIX(d,p[i][0]-1);
- p1.y = YINCH2PIX(d,p[i][1]+1);
-#ifdef DRAWFILLPOLYLOG
-fprintf( logF, "p[%d] = {%d,%d}\n", i, p1.x, p1.y );
-#endif
- q0 = p0;
- q1 = p1;
- if ( clip0( &q0, &q1, NULL ) ) {
-#ifdef DRAWFILLPOLYLOG
-fprintf( logF, " clip( {%d,%d} {%d,%d} ) = {%d,%d} {%d,%d}\n", p0.x, p0.y, p1.x, p1.y, q0.x, q0.y, q1.x, q1.y );
-#endif
- if ( q0.x != p0.x || q0.y != p0.y ) {
- if ( k > 0 && ( q0.x > q0.y ) != ( wFillPoints[k-1].x > wFillPoints[k-1].y ) )
- addPoint( &k, &zero, &rect );
- addPoint( &k, &q0, &rect );
- }
- addPoint( &k, &q1, &rect );
- p1Clipped = ( q1.x != p1.x || q1.y != p1.y );
+ else {
+ mode = R2_COPYPEN;
}
- }
- if ( p1Clipped &&
- ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) )
- addPoint( &k, &zero, &rect );
+ SetROP2(d->hDc, mode);
+
+ } else {
+ setDrawMode(d, dw, lt, color, opts);
+ }
+
+ rect.left = rect.right = XINCH2PIX(d,node[cnt-1][0]-1);
+ rect.top = rect.bottom = YINCH2PIX(d,node[cnt-1][1]+1);
+
#ifdef DRAWFILLPOLYLOG
-fflush( logF );
-fclose( logF );
+ logF = fopen("log.txt", "a");
+ fprintf(logF, "\np[%d] = {%d,%d}\n", cnt-1, node[0][0], node[0][1]);
#endif
- if ( k <= 2 )
- return;
- Polygon( d->hDc, wFillPoints, k );
- if (d->hWnd) {
- rect.top--;
- rect.left--;
- rect.bottom++;
- rect.right++;
- myInvalidateRect( d, &rect );
- }
+
+ for (i=0; i<cnt; i++) {
+ wPolyLine_e type1;
+ point.x = node[i][0];
+ point.y = node[i][1];
+ if (type != NULL)
+ type1 = type[i];
+ else
+ type1 = wPolyLineStraight;
+
+ if (type1 == wPolyLineRound || type1 == wPolyLineSmooth) {
+ prevNode = (i == 0) ? cnt - 1 : i - 1;
+ nextNode = (i == cnt - 1) ? 0 : i + 1;
+
+ // calculate distance to neighboring nodes
+ int prevXDistance = node[i][0] - node[prevNode][0];
+ int prevYDistance = node[i][1] - node[prevNode][1];
+ int nextXDistance = node[nextNode][0]-node[i][0];
+ int nextYDistance = node[nextNode][1]-node[i][1];
+
+ // distance from node to endpoints of curve is half the line length
+ endPoint0.x = (prevXDistance/2)+node[prevNode][0];
+ endPoint0.y = (prevYDistance/2)+node[prevNode][1];
+ endPoint1.x = (nextXDistance/2)+node[i][0];
+ endPoint1.y = (nextYDistance/2)+node[i][1];
+
+ if (type1 == wPolyLineRound) {
+ double distNext = (nextXDistance*nextXDistance + nextYDistance * nextYDistance);
+ double distPrev = (prevXDistance*prevXDistance + prevYDistance * prevYDistance);
+ // but should be half of the shortest line length (equidistant from node) for round
+ if ((distPrev > 0) && (distNext > 0)) {
+ double ratio = sqrt(distPrev / distNext);
+ if (distPrev < distNext) {
+ endPoint1.x = ((nextXDistance*ratio) / 2) + node[i][0];
+ endPoint1.y = ((nextYDistance*ratio) / 2) + node[i][1];
+ } else {
+ endPoint0.x = node[i][0] - (prevXDistance / (2 * ratio));
+ endPoint0.y = node[i][1] - (prevYDistance / (2 * ratio));
+ }
+ }
+ // experience says that the best look is achieved if the
+ // control points are in the middle between end point and node
+ controlPoint0.x = (node[i][0] - endPoint0.x) / 2 + endPoint0.x;
+ controlPoint0.y = (node[i][1] - endPoint0.y) / 2 + endPoint0.y;
+
+ controlPoint1.x = (endPoint1.x - node[i][0]) / 2 + node[i][0];
+ controlPoint1.y = (endPoint1.y - node[i][1]) / 2 + node[i][1];
+ } else {
+ controlPoint0 = point;
+ controlPoint1 = point;
+ }
+ }
+
+ if (i==0) {
+ if (type1 == wPolyLineStraight || open) {
+ // for straight lines or open shapes use the starting point as passed
+ addPoint(d, pointCount++, &point, PT_MOVETO, &rect);
+ startingPoint = point;
+ } else {
+ // for Bezier begin with the calculated starting point
+ addPoint(d, pointCount++, &endPoint0, PT_MOVETO, &rect);
+ addPoint(d, pointCount++, &controlPoint0, PT_BEZIERTO, &rect);
+ addPoint(d, pointCount++, &controlPoint1, PT_BEZIERTO, &rect);
+ addPoint(d, pointCount++, &endPoint1, PT_BEZIERTO, &rect);
+ startingPoint = endPoint0;
+ }
+ } else {
+ if (type1 == wPolyLineStraight || (open && (i==cnt-1))) {
+ addPoint(d, pointCount++, &point, PT_LINETO, &rect);
+ } else {
+ if (i==cnt-1 && !open) {
+ closed = TRUE;
+ }
+ addPoint(d, pointCount++, &endPoint0, PT_LINETO, &rect);
+ addPoint(d, pointCount++, &controlPoint0, PT_BEZIERTO, &rect);
+ addPoint(d, pointCount++, &controlPoint1, PT_BEZIERTO, &rect);
+ addPoint(d, pointCount++, &endPoint1,
+ PT_BEZIERTO | (closed ? PT_CLOSEFIGURE : 0), &rect);
+ }
+ }
+ }
+
+ if (!open && !closed) {
+ addPoint(d, pointCount++, &startingPoint, PT_LINETO, &rect);
+ }
+ rc = PolyDraw(d->hDc, wFillPoints_da.ptr, wFillType_da.ptr, pointCount);
+
+ EndPath(d->hDc);
+
+ if (fill && !open) {
+ FillPath(d->hDc);
+ } else {
+ StrokePath(d->hDc);
+ }
+
+ if (d->hWnd) {
+ rect.top--;
+ rect.left--;
+ rect.bottom++;
+ rect.right++;
+ myInvalidateRect(d, &rect);
+ }
}
#define MAX_FILLCIRCLE_POINTS (30)
@@ -1022,7 +1219,7 @@ void wDrawFilledCircle(
p1.x = XINCH2PIX(d,x+r);
p1.y = YINCH2PIX(d,y-r)+1;
- setDrawBrush( d->hDc, d, color, opts );
+ setDrawBrush( d, color, opts );
if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) {
if ( r > MAX_FILLCIRCLE_POINTS )
cnt = MAX_FILLCIRCLE_POINTS;
@@ -1035,7 +1232,8 @@ void wDrawFilledCircle(
circlePts[inx][0] = x + (int)(r * mswcos( inx*dang ) + 0.5 );
circlePts[inx][1] = y + (int)(r * mswsin( inx*dang ) + 0.5 );
}
- wDrawFilledPolygon( d, circlePts, cnt, color, opts );
+ //wDrawFilledPolygon( d, circlePts, NULL, cnt, color, opts );
+ wDrawPolygon(d, circlePts, NULL, cnt, color, 1, wDrawLineSolid,opts, TRUE, FALSE );
} else {
Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y );
if (d->hWnd) {
@@ -1084,21 +1282,30 @@ void wDrawRestoreImage(
}
-void wDrawClear( wDraw_p d )
+void wDrawClearTemp( wDraw_p d )
{
RECT rect;
- SetROP2( d->hDc, R2_WHITE );
- Rectangle( d->hDc, 0, 0, d->w, d->h );
+ SelectObject( d->hDc, d->hBmTemp );
+ BitBlt(d->hDc, 0, 0, d->w, d->h, d->hDc, 0, 0, WHITENESS);
if (d->hWnd) {
- rect.top = 0;
- rect.bottom = d->h;
- rect.left = 0;
- rect.right = d->w;
- InvalidateRect( d->hWnd, &rect, FALSE );
+ rect.top = 0;
+ rect.bottom = d->h;
+ rect.left = 0;
+ rect.right = d->w;
+ InvalidateRect( d->hWnd, &rect, FALSE );
}
}
+void wDrawClear( wDraw_p d )
+{
+ SelectObject( d->hDc, d->hBmMain );
+ // BitBlt is faster than Rectangle
+ BitBlt(d->hDc, 0, 0, d->w, d->h, d->hDc, 0, 0, WHITENESS);
+ wDrawClearTemp(d);
+}
+
+
void wDrawSetSize(
wDraw_p d,
wPos_t width,
@@ -1196,7 +1403,7 @@ void wDrawBitMap(
wDrawColor dc,
wDrawOpts dopt )
{
- HDC bmDc, hDc;
+ HDC bmDc;
HBITMAP oldBm;
DWORD mode;
int x0, y0;
@@ -1208,9 +1415,7 @@ void wDrawBitMap(
if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) )
return;
#endif
- if (dopt & wDrawOptTemp) {
- mode = tmpOp;
- } else if (dc == wDrawColorWhite) {
+ if (dc == wDrawColorWhite) {
mode = clrOp;
dc = wDrawColorBlack;
} else {
@@ -1224,22 +1429,9 @@ void wDrawBitMap(
RGB( 255, 255, 255 ), bm->w, bm->h, bm->bmx );
bm->color = dc;
}
- if ( (dopt & wDrawOptNoClip) != 0 &&
- ( px < 0 || px >= d->w || py < 0 || py >= d->h ) ) {
- x0 += d->x;
- y0 += d->y;
- hDc = GetDC( ((wControl_p)(d->parent))->hWnd );
- bmDc = CreateCompatibleDC( hDc );
- oldBm = SelectObject( bmDc, bm->bm );
- BitBlt( hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, tmpOp );
- SelectObject( bmDc, oldBm );
- DeleteDC( bmDc );
- ReleaseDC( ((wControl_p)(d->parent))->hWnd, hDc );
- return;
- }
bmDc = CreateCompatibleDC( d->hDc );
- setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt );
+ setDrawMode( d, 0, wDrawLineSolid, dc, dopt );
oldBm = SelectObject( bmDc, bm->bm );
BitBlt( d->hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, mode );
SelectObject( bmDc, oldBm );
@@ -1260,7 +1452,7 @@ wDrawBitMap_p wDrawBitMapCreate(
int h,
int x,
int y,
- const char * bits )
+ const unsigned char * bits )
{
wDrawBitMap_p bm;
int bmSize = ((w+7)/8) * h;
@@ -1322,12 +1514,14 @@ long FAR PASCAL XEXPORT mswDrawPush(
hDc = GetDC(hWnd);
if ( b->option & BD_DIRECT ) {
b->hDc = hDc;
- b->hBm = 0;
+ b->hBmMain = 0;
+ b->hBmTemp = 0;
b->hBmOld = 0;
} else {
b->hDc = CreateCompatibleDC( hDc );
- b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h );
- b->hBmOld = SelectObject( b->hDc, b->hBm );
+ b->hBmMain = CreateCompatibleBitmap( hDc, b->w, b->h );
+ b->hBmTemp = CreateCompatibleBitmap( hDc, b->w, b->h );
+ b->hBmOld = SelectObject( b->hDc, b->hBmMain );
}
if (mswPalette) {
SelectPalette( b->hDc, mswPalette, 0 );
@@ -1355,8 +1549,12 @@ long FAR PASCAL XEXPORT mswDrawPush(
if ( b->option & BD_DIRECT ) {
} else {
hDc = GetDC( b->hWnd );
- b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h );
- DeleteObject(SelectObject( b->hDc, b->hBm ));
+//- DeleteObject( b->hBmOld );
+ DeleteObject( b->hBmMain );
+ DeleteObject( b->hBmTemp );
+ b->hBmMain = CreateCompatibleBitmap( hDc, b->w, b->h );
+ b->hBmTemp = CreateCompatibleBitmap( hDc, b->w, b->h );
+//- b->hBmOld = SelectObject( b->hDc, b->hBmMain );
ReleaseDC( b->hWnd, hDc );
SetROP2( b->hDc, R2_WHITE );
Rectangle( b->hDc, 0, 0, b->w, b->h );
@@ -1383,6 +1581,7 @@ long FAR PASCAL XEXPORT mswDrawPush(
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
+ case WM_LBUTTONDBLCLK:
if (message == WM_LBUTTONDOWN)
action = wActionLDown;
else if (message == WM_RBUTTONDOWN)
@@ -1391,6 +1590,8 @@ long FAR PASCAL XEXPORT mswDrawPush(
action = wActionLUp;
else if (message == WM_RBUTTONUP)
action = wActionRUp;
+ else if (message == WM_LBUTTONDBLCLK)
+ action = wActionLDownDouble;
else {
if ( (wParam & MK_LBUTTON) != 0)
action = wActionLDrag;
@@ -1414,6 +1615,8 @@ long FAR PASCAL XEXPORT mswDrawPush(
iy = HIWORD( lParam );
x = XPIX2INCH( b, ix );
y = YPIX2INCH( b, iy );
+ b->lastX = x;
+ b->lastY = y;
if (b->action)
b->action( b, b->data, action, x, y );
if (b->hWnd)
@@ -1435,7 +1638,7 @@ long FAR PASCAL XEXPORT mswDrawPush(
case VK_RIGHT: extChar = wAccelKey_Right; break;
case VK_LEFT: extChar = wAccelKey_Left; break;
case VK_BACK: extChar = wAccelKey_Back; break;
- /*case VK_F1: extChar = wAccelKey_F1; break;*/
+ case VK_F1: extChar = wAccelKey_F1; break;
case VK_F2: extChar = wAccelKey_F2; break;
case VK_F3: extChar = wAccelKey_F3; break;
case VK_F4: extChar = wAccelKey_F4; break;
@@ -1450,9 +1653,9 @@ long FAR PASCAL XEXPORT mswDrawPush(
}
if (b && b->action) {
if (extChar != wAccelKey_None)
- b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 );
+ b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), b->lastX, b->lastY );
else
- b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 );
+ b->action( b, b->data, wActionText + ( wParam << 8 ), b->lastX, b->lastY );
}
return 0;
@@ -1468,11 +1671,22 @@ long FAR PASCAL XEXPORT mswDrawPush(
b->paletteClock = winPaletteClock;
}
}
+ HBITMAP hBmOld = SelectObject( b->hDc, b->hBmMain );
+
+ if (bDrawMainBM) {
+ BitBlt(hDc, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ b->hDc, rect.left, rect.top,
+ SRCCOPY);
+ }
+ SelectObject( b->hDc, b->bCopiedMain?b->hBmTemp:b->hBmMain );
BitBlt( hDc, rect.left, rect.top,
rect.right-rect.left, rect.bottom-rect.top,
b->hDc, rect.left, rect.top,
- SRCCOPY );
+ bDrawMainBM?SRCAND:SRCCOPY);
+ SelectObject( b->hDc, hBmOld );
EndPaint( hWnd, &ps );
+ b->bCopiedMain = FALSE;
}
}
break;
@@ -1499,18 +1713,44 @@ long FAR PASCAL XEXPORT mswDrawPush(
static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
wAction_t action;
-
+
switch( message ) {
case WM_MOUSEWHEEL:
/* handle mouse wheel events */
- /* fwKeys = GET_KEYSTATE_WPARAM(wParam); modifier keys are currently ignored */
- if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) {
- action = wActionWheelUp;
+ if (GET_KEYSTATE_WPARAM(wParam) & (MK_SHIFT|MK_MBUTTON) ) {
+ if (GET_KEYSTATE_WPARAM(wParam) & MK_CONTROL ) {
+ if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
+ action = wActionScrollLeft;
+ } else {
+ action = wActionScrollRight;
+ }
+ } else {
+ if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
+ action = wActionScrollUp;
+ } else {
+ action = wActionScrollDown;
+ }
+ }
} else {
- action = wActionWheelDown;
+ if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
+ action = wActionWheelUp;
+ } else {
+ action = wActionWheelDown;
+ }
+ }
+ if (b->action)
+ b->action( b, b->data, action, b->lastX, b->lastY );
+ return 0;
+ case WM_MOUSEHWHEEL:
+ if ( GET_KEYSTATE_WPARAM(wParam) & (MK_SHIFT|MK_MBUTTON)) {
+ if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) {
+ action = wActionScrollRight;
+ } else {
+ action = wActionScrollLeft;
+ }
}
if (b->action)
- b->action( b, b->data, action, 0, 0 );
+ b->action( b, b->data, action, b->lastX, b->lastY );
return 0;
}
@@ -1521,10 +1761,12 @@ static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, L
static void drawDoneProc( wControl_p b )
{
wDraw_p d = (wDraw_p)b;
- if (d->hBm) {
+ if (d->hBmMain) {
SelectObject( d->hDc, d->hBmOld );
- DeleteObject( d->hBm );
- d->hBm = (HBITMAP)0;
+ DeleteObject( d->hBmMain );
+ d->hBmMain = (HBITMAP)0;
+ DeleteObject( d->hBmTemp );
+ d->hBmTemp = (HBITMAP)0;
}
if (d->hPen) {
SelectObject( d->hDc, GetStockObject( BLACK_PEN ) );
@@ -1580,10 +1822,17 @@ void mswRepaintAll( void )
for ( b=drawList; b; b=b->drawNext ) {
if (GetUpdateRect( b->hWnd, &rect, FALSE )) {
hDc = BeginPaint( b->hWnd, &ps );
+ HBITMAP hBmOld = SelectObject( b->hDc, b->hBmMain );
BitBlt( hDc, rect.left, rect.top,
rect.right-rect.left, rect.bottom-rect.top,
b->hDc, rect.left, rect.top,
SRCCOPY );
+ SelectObject( b->hDc, b->hBmTemp );
+ BitBlt( hDc, rect.left, rect.top,
+ rect.right-rect.left, rect.bottom-rect.top,
+ b->hDc, rect.left, rect.top,
+ SRCAND );
+ SelectObject( b->hDc, hBmOld );
EndPaint( b->hWnd, &ps );
}
}
@@ -1648,6 +1897,7 @@ wDraw_p wDrawCreate(
SelectPalette( hDc, mswPalette, 0 );
ReleaseDC( d->hWnd, hDc );
}
+ d->bCopiedMain = FALSE;
return d;
}
@@ -1681,14 +1931,19 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes )
wNoticeEx( NT_ERROR, "CreateBitMap: CreateDC fails", "Ok", NULL );
return FALSE;
}
- d->hBm = CreateCompatibleBitmap( hDc, d->w, d->h );
- if ( d->hBm == (HBITMAP)0 ) {
- wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM fails", "Ok", NULL );
+ d->hBmMain = CreateCompatibleBitmap( hDc, d->w, d->h );
+ if ( d->hBmMain == (HBITMAP)0 ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM Main fails", "Ok", NULL );
+ return FALSE;
+ }
+ d->hBmTemp = CreateCompatibleBitmap( hDc, d->w, d->h );
+ if ( d->hBmTemp == (HBITMAP)0 ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM Temp fails", "Ok", NULL );
return FALSE;
}
d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0;
ReleaseDC( mswHWnd, hDc );
- d->hBmOld = SelectObject( d->hDc, d->hBm );
+ d->hBmOld = SelectObject( d->hDc, d->hBmMain );
if (mswPalette) {
SelectPalette( d->hDc, mswPalette, 0 );
RealizePalette( d->hDc );
@@ -1697,8 +1952,9 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes )
d->hFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSY );
d->DPI = 96.0; /*min( d->wFactor, d->hFactor );*/
d->hWnd = 0;
- SetROP2( d->hDc, R2_WHITE );
- Rectangle( d->hDc, 0, 0, d->w, d->h );
+ wDrawClear(d);
+//- SetROP2( d->hDc, R2_WHITE );
+//- Rectangle( d->hDc, 0, 0, d->w, d->h );
return d;
}
@@ -1709,10 +1965,12 @@ wBool_t wBitMapDelete( wDraw_p d )
DeleteObject( d->hPen );
d->hPen = (HPEN)0;
}
- if (d->hBm) {
+ if (d->hBmMain) {
SelectObject( d->hDc, d->hBmOld );
- DeleteObject( d->hBm );
- d->hBm = (HBITMAP)0;
+ DeleteObject( d->hBmMain );
+ d->hBmMain = (HBITMAP)0;
+ DeleteObject( d->hBmTemp );
+ d->hBmTemp = (HBITMAP)0;
}
if (d->hDc) {
DeleteDC( d->hDc );
@@ -1722,74 +1980,75 @@ wBool_t wBitMapDelete( wDraw_p d )
return TRUE;
}
-wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName )
+/**
+ * write bitmap file. The bitmap in d must contain a valid HBITMAP
+ *
+ * \param d A wDraw_p to process.
+ * \param fileName Filename of the file.
+ *
+ * \returns A wBool_t. TRUE on success
+ */
+
+wBool_t
+wBitMapWriteFile(wDraw_p d, const char * fileName)
{
- char *pixels;
- int j, ww, chunk;
- FILE * f;
- BITMAPFILEHEADER bmfh;
- struct {
- BITMAPINFOHEADER bmih;
- RGBQUAD colors[256];
- } bmi;
- int rc;
-
- if ( d->hBm == 0)
- return FALSE;
- f = wFileOpen( fileName, "wb" );
- if (!f) {
- wNoticeEx( NT_ERROR, fileName, "Ok", NULL );
- return FALSE;
- }
- ww = ((d->w +3) / 4) * 4;
- bmfh.bfType = 'B'+('M'<<8);
- bmfh.bfSize = (long)(sizeof bmfh) + (long)(sizeof bmi.bmih) + (long)(sizeof bmi.colors) + (long)ww * (long)(d->h);
- bmfh.bfReserved1 = 0;
- bmfh.bfReserved2 = 0;
- bmfh.bfOffBits = sizeof bmfh + sizeof bmi.bmih + sizeof bmi.colors;
- fwrite( &bmfh, 1, sizeof bmfh, f );
- bmi.bmih.biSize = sizeof bmi.bmih;
- bmi.bmih.biWidth = d->w;
- bmi.bmih.biHeight = d->h;
- bmi.bmih.biPlanes = 1;
- bmi.bmih.biBitCount = 8;
- bmi.bmih.biCompression = BI_RGB;
- bmi.bmih.biSizeImage = 0;
- bmi.bmih.biXPelsPerMeter = 75*(10000/254);
- bmi.bmih.biYPelsPerMeter = 75*(10000/254);
- bmi.bmih.biClrUsed = bmi.bmih.biClrImportant = mswGetColorList( bmi.colors );
- SelectObject( d->hDc, d->hBmOld );
- rc = GetDIBits( d->hDc, d->hBm, 0, 1, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS );
- if ( rc == 0 ) {
- wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bitmapinfo from Bitmap", "Ok", NULL );
- return FALSE;
- }
- bmi.bmih.biClrUsed = 256;
- fwrite( &bmi.bmih, 1, sizeof bmi.bmih, f );
- fwrite( bmi.colors, 1, sizeof bmi.colors, f );
- chunk = 32000/ww;
- pixels = (char*)malloc( ww*chunk );
- if ( pixels == NULL ) {
- wNoticeEx( NT_ERROR, "WriteBitMap: no memory", "OK", NULL );
- return FALSE;
- }
- for (j=0;j<d->h;j+=chunk) {
- if (j+chunk>d->h)
- chunk = d->h-j;
- rc = GetDIBits( d->hDc, d->hBm, j, chunk, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS );
- if ( rc == 0 )
- if ( rc == 0 ) {
- wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bits from Bitmap", "Ok", NULL );
- return FALSE;
- }
- rc = fwrite( pixels, 1, ww*chunk, f );
- if (rc != ww*chunk) {
- wNoticeEx( NT_ERROR, "WriteBitMap: Bad fwrite", "Ok", NULL);
- }
- }
- free( pixels );
- SelectObject( d->hDc, d->hBm );
- fclose( f );
- return TRUE;
+ FIBITMAP *dib = NULL;
+ FIBITMAP *dib2 = NULL;
+ FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
+ BOOL bSuccess = FALSE;
+
+ if (d->hBmMain) {
+
+ BITMAP bm;
+ GetObject(d->hBmMain, sizeof(BITMAP), (LPSTR)&bm);
+ dib = FreeImage_Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0, 0, 0);
+ // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why)
+ // So we save these infos below. This is needed for palettized images only.
+ int nColors = FreeImage_GetColorsUsed(dib);
+ HDC dc = GetDC(NULL);
+ GetDIBits(dc,
+ d->hBmMain,
+ 0,
+ FreeImage_GetHeight(dib),
+ FreeImage_GetBits(dib),
+ FreeImage_GetInfo(dib),
+ DIB_RGB_COLORS);
+ ReleaseDC(NULL, dc);
+
+ // restore BITMAPINFO members
+ FreeImage_GetInfoHeader(dib)->biClrUsed = nColors;
+ FreeImage_GetInfoHeader(dib)->biClrImportant = nColors;
+ // we will get a 32 bit bitmap on Windows systems with invalid alpha
+ // so it needs to be converted to 24 bits.
+ // (see: https://sourceforge.net/p/freeimage/discussion/36110/thread/0699ce8e/ )
+ dib2 = FreeImage_ConvertTo24Bits(dib);
+ FreeImage_Unload(dib);
+ }
+
+ // Try to guess the file format from the file extension
+ fif = FreeImage_GetFIFFromFilename(fileName);
+ if (fif != FIF_UNKNOWN) {
+ // Check that the dib can be saved in this format
+ BOOL bCanSave;
+
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib2);
+ if (image_type == FIT_BITMAP) {
+ // standard bitmap type
+ WORD bpp = FreeImage_GetBPP(dib2);
+ bCanSave = (FreeImage_FIFSupportsWriting(fif) &&
+ FreeImage_FIFSupportsExportBPP(fif, bpp));
+ } else {
+ // special bitmap type
+ bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
+ }
+
+ if (bCanSave) {
+ bSuccess = FreeImage_Save(fif, dib2, fileName, PNG_DEFAULT);
+ return bSuccess;
+ }
+ }
+ FreeImage_Unload(dib2);
+
+ return bSuccess;
}
diff --git a/app/wlib/mswlib/mswedit.c b/app/wlib/mswlib/mswedit.c
index fbae89f..dc70ac3 100644
--- a/app/wlib/mswlib/mswedit.c
+++ b/app/wlib/mswlib/mswedit.c
@@ -1,3 +1,25 @@
+/** \file mswedit.c
+ * Text entry widgets
+ */
+
+/* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
#include <windows.h>
#include <string.h>
#include <malloc.h>
@@ -15,6 +37,7 @@ struct wString_t {
wStringCallBack_p action;
};
+#ifdef LATER
struct wInteger_t {
WOBJ_COMMON
long low, high;
@@ -30,6 +53,7 @@ struct wFloat_t {
double oldValue;
wFloatCallBack_p action;
};
+#endif // LATER
static XWNDPROC oldEditProc = NULL;
@@ -47,53 +71,35 @@ long FAR PASCAL _export pushEdit(
UINT wParam,
LONG lParam )
{
- /* Catch <Return> and cause focus to leave control */
+
#ifdef WIN32
long inx = GetWindowLong( hWnd, GWL_ID );
#else
short inx = GetWindowWord( hWnd, GWW_ID );
#endif
- wControl_p b = mswMapIndex( inx );
+ wControl_p b = mswMapIndex(inx);
- switch (message) {
+ switch (message)
+ {
case WM_CHAR:
- if ( b != NULL) {
- switch( wParam ) {
- case 0x0D:
- case 0x1B:
- case 0x09:
- SetFocus( ((wControl_p)(b->parent))->hWnd );
- SendMessage( ((wControl_p)(b->parent))->hWnd, WM_CHAR,
- wParam, lParam );
- /*SendMessage( ((wControl_p)(b->parent))->hWnd, WM_COMMAND,
- inx, MAKELONG( hWnd, EN_KILLFOCUS ) );*/
- return 0L;
- }
- }
- break;
-
- case WM_KEYUP:
- if ( b != NULL)
- switch (b->type) {
- case B_STRING:
- if (((wString_p)b)->action)
- mswSetTrigger( (wControl_p)b, triggerString );
- break;
-#ifdef LATER
- case B_INTEGER:
- if (((wInteger_p)b)->action)
- mswSetTrigger( (wControl_p)b, triggerInteger );
- break;
- case B_FLOAT:
- if (((wFloat_p)b)->action)
- mswSetTrigger( (wControl_p)b, triggerFloat );
- break;
-#endif
- }
- break;
+ if (b != NULL) {
+ switch (wParam) {
+ case VK_RETURN:
+ triggerString(b);
+ return (0L);
+ break;
+ case 0x1B:
+ case 0x09:
+ SetFocus(((wControl_p)(b->parent))->hWnd);
+ SendMessage(((wControl_p)(b->parent))->hWnd, WM_CHAR,
+ wParam, lParam);
+ return 0L;
+ }
+ }
+ break;
}
- return CallWindowProc( oldEditProc, hWnd, message, wParam, lParam );
+ return CallWindowProc(oldEditProc, hWnd, message, wParam, lParam);
}
/*
@@ -112,7 +118,7 @@ void wStringSetValue(
WORD len = (WORD)strlen( arg );
SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)arg );
#ifdef WIN32
- SendMessage( b->hWnd, EM_SETSEL, len, len );
+ SendMessage( b->hWnd, EM_SETSEL, 0, -1 );
SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0L );
#else
SendMessage( b->hWnd, EM_SETSEL, 0, MAKELPARAM(len,len) );
@@ -140,60 +146,92 @@ const char * wStringGetValue(
return buff;
}
+/**
+ * Get the string from a entry field. The returned pointer has to be free() after processing is complete.
+ *
+ * \param bs IN string entry field
+ *
+ * \return pointer to entered string or NULL if entry field is empty.
+ */
-static void triggerString(
- wControl_p b )
+static char *getString(wString_p bs)
{
- wString_p bs = (wString_p)b;
- int cnt;
+ char *tmpBuffer = NULL;
+ UINT chars = SendMessage(bs->hWnd, EM_LINELENGTH, (WPARAM)0, 0L);
- if (bs->action) {
- *(WPARAM*)&mswTmpBuff[0] = 78;
- cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff );
- mswTmpBuff[cnt] = '\0';
- if (bs->valueP)
- strcpy( bs->valueP, mswTmpBuff );
- bs->action( mswTmpBuff, bs->data );
- mswSetTrigger( NULL, NULL );
- }
+ if (chars) {
+ tmpBuffer = malloc(chars > sizeof(WORD)? chars + 1 : sizeof(WORD) + 1);
+ *(WORD *)tmpBuffer = chars;
+ SendMessage(bs->hWnd, (UINT)EM_GETLINE, 0, (LPARAM)tmpBuffer);
+ tmpBuffer[chars] = '\0';
+ }
+
+ return (tmpBuffer);
}
+/**
+ * Retrieve and process string entry. If a string has been entered, the callback for
+ * the specific entry field is called.
+ *
+ * \param b IN string entry field
+ */
-LRESULT stringProc(
- wControl_p b,
- HWND hWnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam )
+static void triggerString(
+ wControl_p b)
{
- wString_p bs = (wString_p)b;
- int cnt;
- int modified;
-
- switch( message ) {
-
- case WM_COMMAND:
- switch (WCMD_PARAM_NOTF) {
- case EN_KILLFOCUS:
- modified = (int)SendMessage( bs->hWnd, (UINT)EM_GETMODIFY, 0, 0L );
- if (!modified)
- break;
- *(WPARAM*)&mswTmpBuff[0] = 78;
- cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff );
- mswTmpBuff[cnt] = '\0';
- if (bs->valueP)
- strncpy( bs->valueP, mswTmpBuff, bs->valueL );
- if (bs->action) {
- bs->action( mswTmpBuff, bs->data );
- mswSetTrigger( NULL, NULL );
- }
- break;
- SendMessage( bs->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L );
- }
- break;
+ wString_p bs = (wString_p)b;
+
+ char *enteredString = getString(bs);
+ if (enteredString)
+ {
+ if (bs->valueP) {
+ strcpy(bs->valueP, enteredString);
+ }
+ if (bs->action) {
+ bs->action(enteredString, bs->data);
+ }
+ free(enteredString);
}
+}
- return DefWindowProc( hWnd, message, wParam, lParam );
+
+LRESULT stringProc(
+ wControl_p b,
+ HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ wString_p bs = (wString_p)b;
+ int modified;
+
+ switch (message) {
+
+ case WM_COMMAND:
+ switch (WCMD_PARAM_NOTF) {
+ case EN_KILLFOCUS:
+ modified = (int)SendMessage(bs->hWnd, (UINT)EM_GETMODIFY, 0, 0L);
+ if (!modified) {
+ break;
+ }
+
+ char *enteredString = getString(bs);
+ if (enteredString) {
+ if (bs->valueP) {
+ strcpy(bs->valueP, enteredString);
+ }
+ if (bs->action) {
+ bs->action(enteredString, bs->data);
+ mswSetTrigger(NULL, NULL);
+ }
+ free(enteredString);
+ }
+ SendMessage(bs->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L);
+ }
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -249,10 +287,6 @@ wString_p wStringCreate(
return b;
}
-#ifdef CONTROL3D
- Ctl3dSubclassCtl( b->hWnd);
-#endif
-
newEditProc = MakeProcInstance( (XWNDPROC)pushEdit, mswHInst );
oldEditProc = (XWNDPROC)GetWindowLong(b->hWnd, GWL_WNDPROC );
SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newEditProc );
diff --git a/app/wlib/mswlib/mswint.h b/app/wlib/mswlib/mswint.h
index 2311415..e560053 100644
--- a/app/wlib/mswlib/mswint.h
+++ b/app/wlib/mswlib/mswint.h
@@ -1,6 +1,7 @@
#include "wlib.h"
#include "mswlib.h"
-#include "dynarr.h"
+//#include "dynarr.h"
+#include "common.h"
#ifndef WIN32
/*#define CONTROL3D*/
#endif
@@ -38,7 +39,9 @@
#define WSCROLL_PARAM_HWND HIWORD(lParam)
#endif
-#define CAST_AWAY_CONST (char *)
+#ifndef CAST_AWAY_CONST
+ #define CAST_AWAY_CONST (char *)
+#endif
#define BOOL_T wBool_t
#define POS_T wPos_t
@@ -122,16 +125,24 @@ struct wDraw_t {
double DPI;
wDrawRedrawCallBack_p drawRepaint;
wDrawActionCallBack_p action;
- HBITMAP hBm;
+ HBITMAP hBmMain;
+ HBITMAP hBmTemp;
+ HBITMAP hBmOld;
HPEN hPen;
HBRUSH hBrush;
wDraw_p drawNext;
- HBITMAP hBmOld;
wBool_t hasPalette;
int paletteClock;
HBITMAP hBmBackup;
HDC hDcBackup;
HBITMAP hBmBackupOld;
+ void *background;
+ wBool_t bTempMode;
+ wBool_t bCopiedMain;
+
+ wPos_t lastX;
+ wPos_t lastY;
+
};
extern HINSTANCE mswHInst;
@@ -147,6 +158,7 @@ extern wDrawColor wDrawColorWhite;
extern wDrawColor wDrawColorBlack;
extern long mswThickFont;
extern double mswScale;
+extern double scaleIcon;
DWORD mswGetBaseStyle( wWin_p );
char * mswStrdup( const char * );
@@ -190,4 +202,5 @@ void deleteBitmaps( void );
void mswDrawIcon( HDC, int, int, wIcon_p, int, COLORREF, COLORREF );
/* gwin32.c*/
-char *g_win32_getlocale (void); \ No newline at end of file
+char *g_win32_getlocale (void);
+
diff --git a/app/wlib/mswlib/mswlist.c b/app/wlib/mswlib/mswlist.c
index 2453a5e..95ecec3 100644
--- a/app/wlib/mswlib/mswlist.c
+++ b/app/wlib/mswlib/mswlist.c
@@ -243,7 +243,7 @@ wBool_t wListSetValues(
void * itemData )
{
listData * ldp;
- WORD curSel;
+ WORD curSel = -1;
ldp = (listData*)malloc( sizeof *ldp );
ldp->itemContext = itemData;
ldp->bm = bm;
diff --git a/app/wlib/mswlib/mswmenu.c b/app/wlib/mswlib/mswmenu.c
index 815752a..d56e24d 100644
--- a/app/wlib/mswlib/mswmenu.c
+++ b/app/wlib/mswlib/mswmenu.c
@@ -31,6 +31,7 @@
#include <math.h>
#include <ctype.h>
#include <assert.h>
+#include "misc.h"
#include "mswint.h"
#include "i18n.h"
@@ -579,7 +580,7 @@ wMenuPush_p wMenuPushCreate(
{
wMenuPush_p mi;
int rc;
- char label[80];
+ char *label = malloc(strlen(labelStr) + 30 ); /**< The label and sufficient space for the keyboard shortcut */
char *cp;
char ac;
UINT vk;
@@ -591,9 +592,9 @@ wMenuPush_p wMenuPushCreate(
mi->mparent = m;
mi->acclKey = acclKey;
mi->enabled = TRUE;
- strcpy( label, mi->labelStr );
+ strcpy(label, labelStr);
modifier = 0;
- if ( acclKey != 0 ) {
+ if ( acclKey != 0 && strlen(label ) < 60 ) {
DYNARR_APPEND( acclTable_t, acclTable_da, 10 );
cp = label + strlen( label );
*cp++ = '\t';
@@ -625,6 +626,7 @@ wMenuPush_p wMenuPushCreate(
acclTable(acclTable_da.cnt-1).mp = mi;
}
rc = AppendMenu( m->menu, MF_STRING, mi->index, label );
+ free(label);
return mi;
}
diff --git a/app/wlib/mswlib/mswmisc.c b/app/wlib/mswlib/mswmisc.c
index e045cc8..6b5f1c9 100644
--- a/app/wlib/mswlib/mswmisc.c
+++ b/app/wlib/mswlib/mswmisc.c
@@ -22,6 +22,7 @@
#define _WIN32_WINNT 0x0500
#include <windows.h>
+#include <shellapi.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
@@ -30,8 +31,10 @@
#include <stdio.h>
#include <assert.h>
#include <htmlhelp.h>
+#include "misc.h"
#include "mswint.h"
#include "i18n.h"
+#include "FreeImage.h"
#if _MSC_VER > 1300
#define stricmp _stricmp
@@ -47,6 +50,8 @@ char * mswStrdup(const char *);
#define ALARM_TIMER (902)
#define BALLOONHELP_TIMER (903)
#define TRIGGER_TIMER (904)
+#define CONTROLHILITEWIDTH (2)
+#define CONTROLHILITECOLOR (RGB(0x3a,0x5f,0xcd))
#define WANT_LITTLE_LABEL_FONT
@@ -78,6 +83,8 @@ HFONT mswLabelFont;
long mswThickFont = 1;
double mswScale = 1.0;
+double scaleIcon = 1.0; /**< Scaling factor for toolbar icons */
+
callBacks_t *mswCallBacks[CALLBACK_CNT];
void closeBalloonHelp(void);
@@ -87,7 +94,12 @@ static wControl_p getControlFromCursor(HWND, wWin_p *);
*/
struct wWin_t {
- WOBJ_COMMON
+ WOBJ_COMMON
+ int validGeometry;
+ int min_width;
+ int max_width;
+ int min_height;
+ int max_height;
wPos_t lastX, lastY;
wPos_t padX, padY;
wControl_p first, last;
@@ -174,7 +186,21 @@ static int dumpControls;
extern char *userLocale;
-
+// list of supported fileformats for image files
+char * filterImageFiles[] = { N_("All image files"),
+ "*.gif;*.jpg;*.jpeg;*.png;*.tif;*.tiff",
+ N_("GIF files (*.gif)"),
+ "*.gif",
+ N_("JPEG files (*.jpeg,*.jpg)"),
+ "*.jpg;*.jpeg",
+ N_("PNG files (*.png)"),
+ "*.png",
+ N_("TIFF files (*.tiff, *.tif)"),
+ "*.tif;*.tiff",
+ N_("All files (*)"),
+ "*",
+ };
+
/*
*****************************************************************************
*
@@ -610,6 +636,35 @@ static void getSavedSizeAndPos(
}
/**
+ * Set min and max dimensions for a window.
+ *
+ * \param min_width IN minimum width of window
+ * \param max_width IN maximum width of window
+ * \param min_height IN minimum height of window
+ * \param max_height IN maximum height of window
+ * \param base_width IN unused on Windows
+ * \param base_height IN unused on Windows
+ * \param aspect_ration IN unused on Windows
+ */
+void wSetGeometry(wWin_p win,
+ int min_width,
+ int max_width,
+ int min_height,
+ int max_height,
+ int base_width,
+ int base_height,
+ double aspect_ratio)
+{
+ win->validGeometry = TRUE; //remember that geometry was set
+ win->min_width = min_width;
+ win->max_width = max_width;
+ win->min_height = min_height;
+ win->max_height = max_height;
+
+ return;
+}
+
+/**
* Create a window. Retrieves the saved size and position and restores the created window accordingly.
*
* \param hWnd IN parent window
@@ -812,6 +867,10 @@ wWin_p wWinMainCreate(
wPrefGetInteger("draw", "maximized", &maximize, 0L);
option |= (maximize ? F_MAXIMIZE : 0);
+ wPrefGetFloat(PREFSECTION, LARGEICON, &scaleIcon, 1.0);
+ if (scaleIcon < 1.0) scaleIcon = 1.0;
+ if (scaleIcon > 2.0) scaleIcon = 2.0;
+
showCmd = SW_SHOW;
w = winCommonCreate(NULL, W_MAIN, option|F_RESIZE, "MswMainWindow",
WS_OVERLAPPEDWINDOW, labelStr, winProc, x, y, data,
@@ -819,13 +878,10 @@ wWin_p wWinMainCreate(
mswHWnd = w->hWnd;
if (!mswThickFont) {
- DWORD dw;
SendMessage(w->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L);
hDc = GetDC(w->hWnd);
GetTextMetrics(hDc, &tm);
mswEditHeight = tm.tmHeight+2;
- dw = GetTextExtent(hDc, "AXqypj", 6);
- mswEditHeight = HIWORD(dw)+2;
ReleaseDC(w->hWnd, hDc);
}
@@ -1380,12 +1436,11 @@ void wWinClear(
{
}
-void wSetCursor(
+void wSetCursor(wDraw_p win,
wCursor_t cursor)
{
switch (cursor) {
case wCursorNormal:
- case wCursorQuestion:
default:
SetCursor(LoadCursor(NULL, IDC_ARROW));
break;
@@ -1401,6 +1456,42 @@ void wSetCursor(
case wCursorIBeam:
SetCursor(LoadCursor(NULL, IDC_IBEAM));
break;
+
+ case wCursorQuestion:
+ SetCursor(LoadCursor(NULL, IDC_HELP));
+ break;
+
+ case wCursorHand:
+ SetCursor(LoadCursor(NULL, IDC_HAND));
+ break;
+
+ case wCursorNo:
+ SetCursor(LoadCursor(NULL, IDC_NO));
+ break;
+
+ case wCursorSizeAll:
+ SetCursor(LoadCursor(NULL, IDC_SIZEALL));
+ break;
+
+ case wCursorSizeNESW:
+ SetCursor(LoadCursor(NULL, IDC_SIZENESW));
+ break;
+
+ case wCursorSizeNWSE:
+ SetCursor(LoadCursor(NULL, IDC_SIZENWSE));
+ break;
+
+ case wCursorSizeNS:
+ SetCursor(LoadCursor(NULL, IDC_SIZENS));
+ break;
+
+ case wCursorSizeWE:
+ SetCursor(LoadCursor(NULL, IDC_SIZEWE));
+ break;
+
+ case wCursorAppStart:
+ SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
+ break;
}
curCursor = cursor;
@@ -1663,7 +1754,7 @@ void wControlSetLabel(
wControl_p b,
const char * labelStr)
{
- if (b->type == B_RADIO || b->type == B_TOGGLE) {
+ if (b->type == B_RADIO ) {
;
} else {
int lab_l;
@@ -1693,8 +1784,6 @@ void wControlSetContext(
b->data = context;
}
-static int controlHiliteWidth = 5;
-static int controlHiliteWidth2 = 3;
void wControlHilite(
wControl_p b,
wBool_t hilite)
@@ -1702,12 +1791,13 @@ void wControlHilite(
HDC hDc;
HPEN oldPen, newPen;
int oldMode;
+ LOGBRUSH logBrush = { BS_SOLID, CONTROLHILITECOLOR, (ULONG_PTR)NULL };
if (b == NULL) {
return;
}
- if (!IsWindowVisible(b->parent->hWnd)) {
+ if (!IsWindowVisible(b->parent->hWnd)) {
return;
}
@@ -1716,14 +1806,18 @@ void wControlHilite(
}
hDc = GetDC(b->parent->hWnd);
- newPen = CreatePen(PS_SOLID, controlHiliteWidth, RGB(0,0,0));
+ newPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_BEVEL,
+ CONTROLHILITEWIDTH,
+ &logBrush,
+ 0,
+ NULL);
oldPen = SelectObject(hDc, newPen);
oldMode = SetROP2(hDc, R2_NOTXORPEN);
- MoveTo(hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2);
- LineTo(hDc, b->x+b->w+controlHiliteWidth2, b->y-controlHiliteWidth2);
- LineTo(hDc, b->x+b->w+controlHiliteWidth2, b->y+b->h+controlHiliteWidth2);
- LineTo(hDc, b->x-controlHiliteWidth2, b->y+b->h+controlHiliteWidth2);
- LineTo(hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2);
+ Rectangle(hDc,
+ b->x - CONTROLHILITEWIDTH - 1,
+ b->y - CONTROLHILITEWIDTH - 1,
+ b->x + b->w + CONTROLHILITEWIDTH + 1,
+ b->y + b->h + CONTROLHILITEWIDTH + 1);
SetROP2(hDc, oldMode);
SelectObject(hDc, oldPen);
DeleteObject(newPen);
@@ -1766,6 +1860,26 @@ void wMessage(
ReleaseDC(w->hWnd, hDc);
}
+/**
+ * Open a document using an external application
+ *
+ * \param file
+ * \return TRUE on success, FALSE on error
+ *
+ */
+unsigned wOpenFileExternal(char *file)
+{
+ HINSTANCE res;
+
+ res = ShellExecute(mswHWnd, "open", file, NULL, NULL, SW_SHOW);
+
+ if ((int)res <= 32) {
+ wNoticeEx(NT_ERROR, "Error when opening file!", "Cancel", NULL);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
void wExit(int rc)
{
@@ -2040,12 +2154,22 @@ int wNotice3(
}
}
+/**
+ * Show help text for the given topic.
+ *
+ * \param topic The topic. if NULL the index page is shown.
+ */
void wHelp(
const char * topic)
{
char *pszHelpTopic;
HWND hwndHelp;
+ char *theTopic = "index";
+
+ if (topic) {
+ theTopic = topic;
+ }
if (!helpInitted) {
HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ;
@@ -2054,9 +2178,9 @@ void wHelp(
/* "c:\\help.chm::/intro.htm>mainwin", */
/* attention: always adapt constant value (10) to needed number of formatting characters */
- pszHelpTopic = malloc(strlen(helpFile) + strlen(topic) + 10);
+ pszHelpTopic = malloc(strlen(helpFile) + strlen(theTopic) + 10);
assert(pszHelpTopic != NULL);
- sprintf(pszHelpTopic, "/%s.html", topic);
+ sprintf(pszHelpTopic, "/%s.html", theTopic);
hwndHelp = HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_TOPIC,
(DWORD_PTR)pszHelpTopic);
@@ -2068,6 +2192,8 @@ void wHelp(
}
+
+
void doHelpMenu(void * context)
{
HH_FTS_QUERY ftsQuery;
@@ -2092,6 +2218,13 @@ void doHelpMenu(void * context)
HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_SEARCH,(DWORD)&ftsQuery);
break;
+
+ case 3: /*Context*/
+ const char * topic;
+ topic = GetCurCommandName();
+ wHelp(topic);
+ break;
+
default:
return;
}
@@ -2099,11 +2232,16 @@ void doHelpMenu(void * context)
helpInitted = TRUE;
}
+void wDoAccelHelp(wAccelKey_e key, void * context) {
+ doHelpMenu(context);
+}
+
void wMenuAddHelp(
wMenu_p m)
{
- wMenuPushCreate(m, NULL, "&Contents", 0, doHelpMenu, (void*)1);
- wMenuPushCreate(m, NULL, "&Search for Help on...", 0, doHelpMenu, (void*)2);
+ wMenuPushCreate(m, NULL, _("&Contents"), 0, doHelpMenu, (void*)1);
+ wMenuPushCreate(m, NULL, _("&Search for Help on..."), 0, doHelpMenu, (void*)2);
+ wMenuPushCreate(m, NULL, _("Co&mmand Context Help"), 0, doHelpMenu, (void*)3);
}
@@ -2326,6 +2464,24 @@ struct wFilSel_t {
#define SELECTEDFILENAME_BUFFERSIZE (8*1024) /**<estimated size in case all param files are selected */
+char *
+GetImageFileFormats(void)
+{
+ char *filter = malloc(2048);
+ char *current = filter;
+ char *message;
+
+ for (int i = 0; i < sizeof(filterImageFiles) / sizeof(filterImageFiles[0]); i += 2) {
+ message = gettext(filterImageFiles[i]);
+ strcpy(current, message);
+ current += strlen(message) + 1;
+ strcpy(current, filterImageFiles[i + 1]);
+ current += strlen(current) + 1;
+ }
+ *current = '\0';
+ return(filter);
+}
+
/**
* Run the file selector. After the selector is finished an array of filenames is
* created. Each filename will be fully qualified. The array and the number of
@@ -2356,11 +2512,16 @@ int wFilSelect(
strcmp(dirName, ".") == 0) {
dirName = wGetUserHomeDir();
}
-
memset(&ofn, 0, sizeof ofn);
ofn.lStructSize = sizeof ofn;
ofn.hwndOwner = mswHWnd;
- ofn.lpstrFilter = fs->extList;
+ if (fs->option == FS_PICTURES) {
+ ofn.lpstrFilter = GetImageFileFormats();
+ }
+ else {
+ ofn.lpstrFilter = fs->extList;
+ }
+
ofn.nFilterIndex = 0;
selFileName = malloc(SELECTEDFILENAME_BUFFERSIZE);
memset(selFileName, '\0', SELECTEDFILENAME_BUFFERSIZE);
@@ -2599,6 +2760,23 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
wAccelKey_e extChar;
switch (message) {
+ case WM_GETMINMAXINFO:
+ LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam;
+ inx = GetWindowWord(hWnd, 0);
+
+ if (inx >= CONTROL_BASE && inx <= controlMap_da.cnt) {
+ w = (wWin_p)controlMap(inx - CONTROL_BASE).b;
+ if (w != NULL) {
+ if (w->validGeometry) {
+ pMMI->ptMaxTrackSize.x = w->max_width;
+ pMMI->ptMaxTrackSize.y = w->max_height;
+ pMMI->ptMinTrackSize.x = w->min_width;
+ pMMI->ptMinTrackSize.y = w->min_height;
+ }
+ }
+ }
+ return(0);
+
case WM_MOUSEWHEEL:
inx = GetWindowWord(hWnd, 0);
b = getControlFromCursor(hWnd, NULL);
@@ -2614,22 +2792,6 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DRAWITEM:
case WM_COMMAND:
case WM_MEASUREITEM:
- case WM_NOTVALID:
- if (WCMD_PARAM_ID == IDM_DOHELP) {
- b = getControlFromCursor(hWnd, NULL);
- closeBalloonHelp();
-
- if (!b) {
- return 0L;
- }
-
- if (b->helpStr) {
- wHelp(b->helpStr);
- }
-
- return 0L;
- }
-
closeBalloonHelp();
if (WCMD_PARAM_ID < CONTROL_BASE || WCMD_PARAM_ID > (WPARAM)controlMap_da.cnt) {
@@ -2913,26 +3075,26 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_SETCURSOR:
/*if (any buttons down)
break;*/
- wSetCursor(curCursor);
+ wSetCursor(NULL, curCursor);
if (!mswAllowBalloonHelp) {
- break;
+ return TRUE;
}
if (IsIconic(mswHWnd)) {
- break;
+ return TRUE;
}
b = getControlFromCursor(hWnd, NULL);
if (b == balloonControlButton) {
- break;
+ return TRUE;
}
if (/*(!IsWindowEnabled(hWnd))*/ GetActiveWindow() != hWnd ||
(!b) || b->type == B_DRAW || b->helpStr == NULL) {
closeBalloonHelp();
- break;
+ return TRUE;
}
if (b != balloonHelpButton) {
@@ -2940,19 +3102,19 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
if (balloonHelpState != balloonHelpIdle) {
- break;
+ return TRUE;
}
balloonHelpTimer = SetTimer(mswHWnd, BALLOONHELP_TIMER,
balloonHelpTimeOut, NULL);
if (balloonHelpTimer == (UINT)0) {
- break;
+ return TRUE;
}
balloonHelpState = balloonHelpWait;
balloonHelpButton = b;
- break;
+ return TRUE;
case WM_SYSCOMMAND:
inx = GetWindowWord(hWnd, 0);
@@ -3211,13 +3373,13 @@ static BOOL InitApplication(HINSTANCE hinstCurrent)
return FALSE;
}
- wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
+ wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS;
wc.lpfnWndProc = mswDrawPush;
wc.lpszClassName = mswDrawWindowClassName;
wc.cbWndExtra = 4;
if (!RegisterClass(&wc)) {
- mswFail("RegisterClass(drawClass)");
+ mswFail("RegisterClass(drawClass)");
return FALSE;
}
@@ -3238,8 +3400,6 @@ int PASCAL WinMain(HINSTANCE hinstCurrent, HINSTANCE hinstPrevious,
HDC hDc;
char **argv;
int argc;
- TEXTMETRIC tm;
- DWORD dw;
if (!hinstPrevious) {
if (!InitApplication(hinstCurrent)) {
@@ -3264,10 +3424,6 @@ int PASCAL WinMain(HINSTANCE hinstCurrent, HINSTANCE hinstPrevious,
mswScale = 1.0;
}
- GetTextMetrics(hDc, &tm);
- mswEditHeight = tm.tmHeight + 8;
- dw = GetTextExtent(hDc, "AXqypj", 6);
- mswEditHeight = HIWORD(dw)+2;
ReleaseDC(0, hDc);
mswCreateCheckBitmaps();
/*
diff --git a/app/wlib/mswlib/mswmsg.c b/app/wlib/mswlib/mswmsg.c
index 4a21921..6445299 100644
--- a/app/wlib/mswlib/mswmsg.c
+++ b/app/wlib/mswlib/mswmsg.c
@@ -42,6 +42,7 @@ static void repaintMessage(
HFONT hFont;
LOGFONT msgFont;
double scale = 1.0;
+ TEXTMETRIC textMetrics;
hDc = GetDC( hWnd );
@@ -74,13 +75,15 @@ static void repaintMessage(
hFont = SelectObject( hDc, mswLabelFont );
}
+ GetTextMetrics(hDc, &textMetrics);
+
rect.bottom = (long)(bm->y+( bm->h ));
rect.right = (long)(bm->x+( scale * bm->w ));
- rect.top = bm->y;
+ rect.top = bm->y+1;
rect.left = bm->x;
SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) );
- ExtTextOut( hDc, bm->x, bm->y, ETO_CLIPPED|ETO_OPAQUE, &rect, bm->message, strlen( bm->message ), NULL );
+ ExtTextOut( hDc, bm->x, bm->y + ((bm->h + 2 - textMetrics.tmHeight) / 2), ETO_CLIPPED|ETO_OPAQUE, &rect, bm->message, strlen( bm->message ), NULL );
if( scale != 1.0 )
/* in case we did create a new font earlier, delete it now */
@@ -138,7 +141,7 @@ wPos_t wMessageGetHeight( long flags )
if( flags & BM_SMALL )
scale = SCALE_SMALL;
- return((wPos_t)((mswEditHeight - 4) * scale ));
+ return((wPos_t)((mswEditHeight) * scale ));
#endif
}
diff --git a/app/wlib/mswlib/mswpref.c b/app/wlib/mswlib/mswpref.c
index eaa39fe..201171a 100644
--- a/app/wlib/mswlib/mswpref.c
+++ b/app/wlib/mswlib/mswpref.c
@@ -5,6 +5,7 @@
#include <commdlg.h>
#include <math.h>
#include <stdio.h>
+#include "misc.h"
#include "mswint.h"
#include <shlobj.h>
#include <Shlwapi.h>
diff --git a/app/wlib/mswlib/mswprint.c b/app/wlib/mswlib/mswprint.c
index 91f05ea..13756c7 100644
--- a/app/wlib/mswlib/mswprint.c
+++ b/app/wlib/mswlib/mswprint.c
@@ -27,7 +27,7 @@ struct tagPD printDlg;
#endif
static int printStatus = FALSE;
static DOCINFO docInfo;
-static double pageSizeW = 8.5, pageSizeH = 11.0;
+static double tBorder = 0.0, rBorder = 0.0, bBorder = 0.0, lBorder = 0.0;
static double physSizeW = 8.5, physSizeH = 11.0;
static int pageCount = -1;
@@ -66,10 +66,16 @@ void getPageDim( HDC hDc )
size_h = GetDeviceCaps( hDc, VERTSIZE );
print_d.w = res_w = GetDeviceCaps( hDc, HORZRES );
print_d.h = res_h = GetDeviceCaps( hDc, VERTRES );
+ double pageSizeW, pageSizeH;
pageSizeW = ((double)res_w)/print_d.wFactor;
pageSizeH = ((double)res_h)/print_d.hFactor;
physSizeW = ((double)dims.x)/print_d.wFactor;
physSizeH = ((double)dims.y)/print_d.hFactor;
+ // Get Borders/Margins - offs are the top, left borders
+ lBorder = ((double)offs.x)/print_d.hFactor;
+ tBorder = ((double)offs.y)/print_d.hFactor;
+ rBorder = physSizeW-pageSizeW-lBorder;
+ bBorder = physSizeH-pageSizeH-tBorder;
}
static wBool_t printInit( void )
@@ -83,6 +89,7 @@ static wBool_t printInit( void )
return printerOk;
}
initted = TRUE;
+ memset(&printDlg, 0, sizeof printDlg);
printDlg.lStructSize = sizeof printDlg;
printDlg.hwndOwner = NULL;
printDlg.Flags = PD_RETURNDC|PD_RETURNDEFAULT;
@@ -194,16 +201,36 @@ void wPrintSetup( wPrintSetupCallBack_p callback )
}
}
+const char* wPrintGetName()
+{
+ static char sPrinterName[100];
+ HANDLE hDevNames = printDlg.hDevNames;
+ DEVNAMES* pDevNames = GlobalLock(hDevNames);
+ if (pDevNames == NULL) {
+ strcpy(sPrinterName, "Printer");
+ }
+ else {
+ strncpy(sPrinterName, (char*)pDevNames + pDevNames->wDeviceOffset, sizeof sPrinterName - 1);
+ sPrinterName[sizeof sPrinterName - 1] = '\0';
+ }
+ GlobalUnlock( hDevNames );
+ return sPrinterName;
+}
-void wPrintGetPageSize( double *w, double *h )
+void wPrintGetMargins(
+ double * tMargin,
+ double * rMargin,
+ double * bMargin,
+ double * lMargin )
{
- printInit();
- *w = pageSizeW;
- *h = pageSizeH;
+ if ( tMargin ) *tMargin = tBorder;
+ if ( rMargin ) *rMargin = rBorder;
+ if ( bMargin ) *bMargin = bBorder;
+ if ( lMargin ) *lMargin = lBorder;
}
-void wPrintGetPhysSize( double *w, double *h )
+void wPrintGetPageSize( double *w, double *h )
{
printInit();
*w = physSizeW;
@@ -378,10 +405,3 @@ wBool_t wPrintNewMargin( const char * name, double t, double b, double l, double
{
return TRUE;
}
-
-void wPrintSetCallBacks(
- wAddPrinterCallBack_p newPrinter,
- wAddMarginCallBack_p newMargin,
- wAddFontAliasCallBack_p newFontAlias )
-{
-}
diff --git a/app/wlib/mswlib/mswsplash.c b/app/wlib/mswlib/mswsplash.c
index 47df6b7..172b563 100644
--- a/app/wlib/mswlib/mswsplash.c
+++ b/app/wlib/mswlib/mswsplash.c
@@ -204,8 +204,11 @@ wCreateSplash( char *appname, char *appver )
/* create the title string */
pszBuf = malloc( strlen( appname ) + strlen( appver ) + 2 );
- if( !pszBuf )
- return( 0 );
+ if (!pszBuf) {
+ GlobalUnlock(hgbl);
+ GlobalFree(hgbl);
+ return(0);
+ }
sprintf( pszBuf, "%s %s", appname, appver );
lpw += 1+MultiByteToWideChar (CP_ACP, 0, pszBuf, -1, (LPWSTR)lpw, 50);
@@ -226,7 +229,6 @@ wCreateSplash( char *appname, char *appver )
GlobalUnlock(hgbl);
hSplash = CreateDialogIndirectParam( mswHInst, (LPDLGTEMPLATE) hgbl,
mswHWnd, (DLGPROC)SplashDlgProc, (LPARAM)hBmp );
- GetLastError();
/* free allocated memory */
GlobalFree(hgbl);
diff --git a/app/wlib/mswlib/mswtext.c b/app/wlib/mswlib/mswtext.c
index 293e2b4..0a0ce88 100644
--- a/app/wlib/mswlib/mswtext.c
+++ b/app/wlib/mswlib/mswtext.c
@@ -137,6 +137,9 @@ void wTextAppend(
if (b->option&BO_READONLY) {
SendMessage(b->hWnd, EM_SETREADONLY, 1, 0L);
}
+
+ // scroll to bottom of text box
+ SendMessage(b->hWnd, EM_LINESCROLL, 0, 10000L);
}
@@ -247,42 +250,54 @@ wBool_t wTextGetModified(
return (wBool_t)rc;
}
+/**
+ * Get the size of the text in the text control including terminating '\0'. Note that
+ * the text actually might be shorter if the text includes CRs.
+ *
+ * \param b IN text control
+ * \return required buffer size
+ */
int wTextGetSize(
wText_p b)
{
- int lc, l, len=0;
- lc = (int)SendMessage(b->hWnd, EM_GETLINECOUNT, 0, 0L);
+ int len;
- for (l=0; l<lc ; l++) {
- int charIndex = (int)SendMessage(b->hWnd, EM_LINEINDEX, l, 0L);
- len += (int)SendMessage(b->hWnd, EM_LINELENGTH, charIndex, 0L) + 1;
- }
-
- if (len == 1) {
- len = 0;
- }
+ len = GetWindowTextLength(b->hWnd);
- return len;
+ return len + 1;
}
+/**
+ * Get the text from a textentry. The buffer must be large enough for the text and
+ * the terminating \0.
+ * In case the string contains carriage returns these are removed. The returned string
+ * will be shortened accordingly.
+ * To get the complete contents the buffer size must be equal or greater then the return
+ * value of wTextGetSize()
+ *
+ * \param b IN text entry
+ * \param t IN/OUT buffer for text
+ * \param s IN size of buffer
+ */
+
void wTextGetText(
wText_p b,
char * t,
int s)
{
- int lc, l, len;
- s--;
- lc = (int)SendMessage(b->hWnd, EM_GETLINECOUNT, 0, 0L);
-
- for (l=0; l<lc && s>=0; l++) {
- *(WORD*)t = s;
- len = (int)SendMessage(b->hWnd, EM_GETLINE, l, (LPARAM)t);
- t += len;
- *t++ = '\n';
- s -= len+1;
- }
-
- *(t - 1) = '\0'; // overwrite the last \n added
+ char *buffer = malloc(s);
+ char *ptr = buffer;
+ GetWindowText(b->hWnd, buffer, s);
+
+ // remove carriage returns
+ while (*ptr) {
+ if (*ptr != '\r') {
+ *t = *ptr;
+ t++;
+ }
+ ptr++;
+ }
+ free(buffer);
}
diff --git a/app/wlib/mswlib/simple-gettext.c b/app/wlib/mswlib/simple-gettext.c
index d213fc3..412eece 100644
--- a/app/wlib/mswlib/simple-gettext.c
+++ b/app/wlib/mswlib/simple-gettext.c
@@ -148,8 +148,9 @@ utf8_to_native( char *str, unsigned int len, int dummy )
/* 2. convert from UTF-8 to system codepage */
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)buf, wcharLen, resBuffer, len + 1, NULL, NULL );
- free( buf );
+
}
+ free(buf);
return( resBuffer );
}
diff --git a/app/wlib/mswlib/unittest/CMakeLists.txt b/app/wlib/mswlib/unittest/CMakeLists.txt
new file mode 100644
index 0000000..b91c1ff
--- /dev/null
+++ b/app/wlib/mswlib/unittest/CMakeLists.txt
@@ -0,0 +1,11 @@
+# build unit tests for the xtrkcad Windows library
+
+add_executable(utf8test
+ utf8test.c
+ ../utf8conv.c
+ )
+
+target_link_libraries(utf8test
+ ${LIBS})
+
+add_test(UTF8ConversionTest utf8test)
diff --git a/app/wlib/mswlib/unittest/utf8test.c b/app/wlib/mswlib/unittest/utf8test.c
new file mode 100644
index 0000000..5b00371
--- /dev/null
+++ b/app/wlib/mswlib/unittest/utf8test.c
@@ -0,0 +1,65 @@
+/** \file utf8test.c
+* Unit tests for utf 8 conversion routines on Windows
+*/
+
+#include <setjmp.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <cmocka.h>
+
+#include <wlib.h>
+
+#define SIMPLEASCIITEXT "The quick brown fox jumps over the lazy dog."
+#define UMLAUTTEXT ""
+
+static void
+ASCIIText(void **state)
+{
+ char output[100];
+ char result[100];
+ bool success;
+ (void)state;
+
+ success = wSystemToUTF8(SIMPLEASCIITEXT, output, 100);
+ assert_true((void *)success);
+
+ success = wUTF8ToSystem(output, result, 100);
+ assert_true((void *)success);
+
+ assert_false(strcmp(SIMPLEASCIITEXT, result));
+}
+
+static void
+Umlauts(void **state)
+{
+ char output[100];
+ char result[100];
+ bool success;
+ (void)state;
+
+ success = wIsUTF8(UMLAUTTEXT);
+ assert_false((void *)success);
+
+ success = wSystemToUTF8(UMLAUTTEXT, output, 100);
+ assert_true((void *)success);
+
+ success = wIsUTF8(output);
+ assert_true((void *)success);
+
+ success = wUTF8ToSystem(output, result, 100);
+ assert_true((void *)success);
+
+ assert_false(strcmp(UMLAUTTEXT, result));
+}
+
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(ASCIIText),
+ cmocka_unit_test(Umlauts),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+} \ No newline at end of file
diff --git a/app/wlib/mswlib/utf8conv.c b/app/wlib/mswlib/utf8conv.c
new file mode 100644
index 0000000..62ada76
--- /dev/null
+++ b/app/wlib/mswlib/utf8conv.c
@@ -0,0 +1,210 @@
+/**
+ * \file utf8conv.c.
+ *
+ * UTF-8 conversion functions
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2020 Martin Fischer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <malloc.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <Windows.h>
+
+#include <wlib.h>
+
+/**
+ * Convert system codepage to UTF 8
+ *
+ * \param inString The input string.
+ * \param [in,out] outString The output string buffer.
+ * \param outStringLength Length of the output buffer
+ *
+ * \returns FALSE if it fails.
+ */
+
+bool
+wSystemToUTF8(const char *inString, char *outString, unsigned outStringLength)
+{
+ unsigned int cnt = 2 * (strlen(inString) + 1);
+ char *tempBuffer = malloc(cnt);
+
+ // convert to wide character (UTF16)
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ inString,
+ -1,
+ (LPWSTR)tempBuffer,
+ cnt);
+
+ // convert from wide char to UTF-8
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ (LPCWCH)tempBuffer,
+ -1,
+ (LPSTR)outString,
+ outStringLength,
+ NULL,
+ NULL);
+
+ free(tempBuffer);
+ return true;
+}
+
+/**
+ * Convert from UTF-8 to system codepage
+ *
+ * \param inString The input string.
+ * \param [in,out] outString the output string.
+ * \param outStringLength Length of the output buffer.
+ *
+ * \returns True if it succeeds, false if it fails.
+ */
+
+bool
+wUTF8ToSystem(const char *inString, char *outString, unsigned outStringLength)
+{
+ unsigned int cnt = 2 * (strlen(inString) + 1);
+ char *tempBuffer = malloc(cnt);
+
+ // convert to wide character (UTF16)
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ inString,
+ -1,
+ (LPWSTR)tempBuffer,
+ cnt);
+
+
+ cnt = WideCharToMultiByte(CP_ACP,
+ 0,
+ (LPCWCH)tempBuffer,
+ -1,
+ (LPSTR)outString,
+ 0L,
+ NULL,
+ NULL);
+
+ if (outStringLength <= cnt) {
+ return (false);
+ }
+
+ // convert from wide char to system codepage
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ (LPCWCH)tempBuffer,
+ -1,
+ (LPSTR)outString,
+ outStringLength,
+ NULL,
+ NULL);
+
+ free(tempBuffer);
+ return true;
+}
+
+/**
+ * Is passed string in correct UTF-8 format?
+ * Taken from https://stackoverflow.com/questions/1031645/how-to-detect-utf-8-in-plain-c
+ *
+ * \param string The string to check.
+ *
+ * \returns True if UTF 8, false if not.
+ */
+
+bool wIsUTF8(const char * string)
+{
+ if (!string) {
+ return 0;
+ }
+
+ const unsigned char * bytes = (const unsigned char *)string;
+ while (*bytes) {
+ if ((// ASCII
+ // use bytes[0] <= 0x7F to allow ASCII control characters
+ bytes[0] == 0x09 ||
+ bytes[0] == 0x0A ||
+ bytes[0] == 0x0D ||
+ (0x20 <= bytes[0] && bytes[0] <= 0x7E)
+ )
+ ) {
+ bytes += 1;
+ continue;
+ }
+
+ if ((// non-overlong 2-byte
+ (0xC2 <= bytes[0] && bytes[0] <= 0xDF) &&
+ (0x80 <= bytes[1] && bytes[1] <= 0xBF)
+ )
+ ) {
+ bytes += 2;
+ continue;
+ }
+
+ if ((// excluding overlongs
+ bytes[0] == 0xE0 &&
+ (0xA0 <= bytes[1] && bytes[1] <= 0xBF) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF)
+ ) ||
+ (// straight 3-byte
+ ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) ||
+ bytes[0] == 0xEE ||
+ bytes[0] == 0xEF) &&
+ (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF)
+ ) ||
+ (// excluding surrogates
+ bytes[0] == 0xED &&
+ (0x80 <= bytes[1] && bytes[1] <= 0x9F) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF)
+ )
+ ) {
+ bytes += 3;
+ continue;
+ }
+
+ if ((// planes 1-3
+ bytes[0] == 0xF0 &&
+ (0x90 <= bytes[1] && bytes[1] <= 0xBF) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
+ (0x80 <= bytes[3] && bytes[3] <= 0xBF)
+ ) ||
+ (// planes 4-15
+ (0xF1 <= bytes[0] && bytes[0] <= 0xF3) &&
+ (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
+ (0x80 <= bytes[3] && bytes[3] <= 0xBF)
+ ) ||
+ (// plane 16
+ bytes[0] == 0xF4 &&
+ (0x80 <= bytes[1] && bytes[1] <= 0x8F) &&
+ (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
+ (0x80 <= bytes[3] && bytes[3] <= 0xBF)
+ )
+ ) {
+ bytes += 4;
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+} \ No newline at end of file