Counter.C - a basic ViewKit component.

IRIX/Nekoware development, porting and related topics.
Forum rules
Any posts concerning pirated software or offering to buy/sell/trade commercial software are subject to removal.
User avatar
jimmer
Posts: 327
Joined: Tue Oct 12, 2004 3:54 pm
Location: London, Ingerlund

Counter.C - a basic ViewKit component.

Unread postby jimmer » Mon Apr 23, 2012 8:49 am

Hi All,

I messed around with geo's code from here: http://forums.nekochan.net/viewtopic.php?f=15&t=16726405 to see if i could maybe find what was causing the odd 'jump to the left' artefact he was seeing on IRIX. Unfortunately, I think it's a bug in IRIX Motif for which obviously we'll never see a fix.

My little experiment left me with some code for a basic ViewKit component. So instead of deleting it, I thought I'd post it here. Perhaps somebody might find it interesting or useful.

Counter.C

Code: Select all

/*
 Counter.C    A basic ViewKit component.

              (c)2012 under GPL, Avi Bercovich <avi@sillypages.org>
*/

#include <stdio.h>

#include <string>
#include <iostream>
using namespace std;

#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/Frame.h>
#include <Xm/PushB.h>
#include <Xm/Label.h>

#include <Vk/VkApp.h>
#include <Vk/VkSimpleWindow.h>

// the interval by which the counter increases or decreases
#define COUNTER_STEP 5

class Counter : public VkComponent {

   public:
   
      Counter(const char *name, Widget parent);
      ~Counter() {};

      virtual const char *className() { return "Counter"; }

      void    setCount(int count) { _count = count; }
      int    getCount() { return _count; }

      void    updateCounter();

   private:

      int _count;

      Widget ui_frame_counter;

      static String ui_defaultResources[];

      static void increase_cb(Widget w, XtPointer clientData, XtPointer callData);
      static void decrease_cb(Widget w, XtPointer clientData, XtPointer callData);
};


class CounterWindow : public VkSimpleWindow {

   public:

      CounterWindow(const char *name);
      ~CounterWindow() {};

      virtual const char *className() { return "CounterWindow"; }
};


String Counter::ui_defaultResources[] = {

   "*renderTable: normal14, bold24",
   "*fontType: FONT_IS_FONT",
   "*normal14.fontName: -*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*",
   "*bold24.fontName: -*-helvetica-bold-r-normal-*-24-*-*-*-*-*-*-*",

   NULL
};

Counter::Counter(const char *name, Widget parent) : VkComponent(name) {

   XmString _string;

   // _baseWidget remains unmanaged. The VkComponent->show() method called in main() takes care of that.
   _baseWidget = XtVaCreateWidget("BaseWidget", xmRowColumnWidgetClass, parent,

      XmNtopOffset, 5,
      XmNrightOffset,   5,
      XmNbottomOffset, 5,
      XmNleftOffset, 5,

      XmNnumColumns,          3,
      XmNorientation,         XmHORIZONTAL,
   
      NULL);

   // make sure ViewKit takes care of the widget destruction of our new VkComponent
   installDestroyHandler();
   
   // load font definitions, only works with Motif 2.1
   setDefaultResources(_baseWidget, ui_defaultResources);

   // create the Counter widgets and add the Xt callbacks for our buttons
   _string = XmStringCreate("-", "bold24");

   Widget ui_decrease_btn = XtVaCreateManagedWidget("DecreaseButton", xmPushButtonWidgetClass, _baseWidget,

      XmNlabelString, _string,

      NULL);   

   XtAddCallback(ui_decrease_btn, XmNactivateCallback, &Counter::decrease_cb, (XtPointer) this );

   Widget ui_frame = XtVaCreateManagedWidget("Frame", xmFrameWidgetClass, _baseWidget,

      XmNshadowType,    XmSHADOW_ETCHED_OUT,

      XmNrightOffset,   5,
      XmNleftOffset,    5,

      NULL);

   _string = XmStringCreate("Counter", "normal14");

   Widget ui_frame_label = XtVaCreateManagedWidget("FrameLabel", xmLabelWidgetClass, ui_frame,

      XmNframeChildType,             XmFRAME_TITLE_CHILD,
      XmNchildHorizontalAlignment,    XmALIGNMENT_END,

      XmNlabelString,    _string,

      NULL);

   _string = XmStringCreate("0", "bold24");

   ui_frame_counter = XtVaCreateManagedWidget("FrameCounter", xmLabelWidgetClass, ui_frame,

      XmNlabelString,         _string,

      NULL);

   _string = XmStringCreate("+", "bold24");

   Widget ui_increase_btn = XtVaCreateManagedWidget("IncreaseButton", xmPushButtonWidgetClass, _baseWidget,

      XmNlabelString, _string,

      NULL);   

   XtAddCallback(ui_increase_btn, XmNactivateCallback, &Counter::increase_cb, (XtPointer) this );

    // housekeeping...
   XmStringFree(_string);   

   // reset internal counter
   setCount(0);
}


void Counter::increase_cb(Widget w, XtPointer clientData, XtPointer callData) {

   // This is C++ casting magicke to get the actual object instance that triggered the callback
   Counter *obj = (Counter *) clientData;

   // Now that we have the correct object, we can deal with this event
   obj->setCount(obj->getCount() + COUNTER_STEP);
   obj->updateCounter();
}


void Counter::decrease_cb(Widget w, XtPointer clientData, XtPointer callData) {

   // This is C++ casting magicke to get the actual object instance that triggered the callback
   Counter *obj = (Counter *) clientData;

   // Now that we have the correct object, we can deal with this event   
   obj->setCount(obj->getCount() - COUNTER_STEP);
   obj->updateCounter();
}


void Counter::updateCounter() {

   // There's no way to feed XmStringCreate the 'count' parameter as an integer, So we need this nasty little C typing workaround.
   char bla[10];
   sprintf(bla, "%d", getCount());

   XmString _string = XmStringCreate(bla, "bold24");

   XtVaSetValues(ui_frame_counter,

      XmNlabelString, _string,

      NULL);

   XmStringFree(_string);
}


CounterWindow::CounterWindow(const char *name) : VkSimpleWindow(name) {

   Widget ui_root = XtCreateWidget("UIRoot", xmFormWidgetClass, mainWindowWidget(), NULL, 0);

   Counter *ui_counter = new Counter("Counter", ui_root);
   ui_counter->setCount(0);
   ui_counter->show();
   
   addView(ui_root);
}


int main(int argc , char *argv[]) {

   VkApp *app = new VkApp("Counter", &argc, argv);
   
   CounterWindow *win = new CounterWindow("Counter Window");
   win->show();

   app->run();
}


Makefile

Code: Select all

APP_NAME = counter

APP_OBJS = Counter.o

INCDIRS = -I. -I/usr/local/include  -I/usr/nekoware/include
LIBDIRS   = -L/usr/local/lib -L/usr/nekoware/lib

STDLIBS      = -lm
STDCPPLIBS   = -lC -lCio
X11LIBS    = -lXt -lX11 -lPW
MOTIFLIBS   = -lSgm -lXm
VKLIBS       = -lvk

LIBS=      $(VKLIBS) \
      $(MOTIFLIBS)\
      $(X11LIBS)\
      $(STDCPPLIBS)\
      $(STDLIBS)

CXX      = CC
CXXOPTS    = -O2 -LANG:std

CC      = c99
COPTS      = -O2

all : $(APP_NAME)

$(APP_NAME): ${APP_OBJS}
   ${CXX} ${APP_OBJS} ${LIBDIRS} ${LIBS} -o ${APP_NAME}

%.o : %.c   
   ${CC} ${COPTS} ${INCDIRS} -c $<

%.o : %.C   
   ${CXX} ${CXXOPTS} ${INCDIRS} -c $<


clean :
   rm -rf ${APP_NAME} *.o core *~ ii_*
:Fuel: redbox 800Mhz 4Gb V12

User avatar
geo
Posts: 525
Joined: Tue Jul 21, 2009 5:07 am
Location: Shenzhen, P.R.C

Re: Counter.C - a basic ViewKit component.

Unread postby geo » Thu May 03, 2012 8:08 am

hi jimmer thanks for sharing this code :)

btw, got a quick question, is it possible to pass more than one widget as client data on a callback? Example is my case, i have a button callback. Inside the callback i need to check two widgets to accomplish a task.

My original way was to declare the two widget as global, but this way is not applicable for me because it would left me a design limitation or flaw. So that's why i should pass the widget properly through the callback right? but i need to pas two of them so how can i pass the two widget? i already tried many way but everyone will cause segmantation fault :(

i already tried, pass by value, pass by reference, pass by pointer of widget array, structure which contains the address of the widget.. still the same :( hoping you could enlighten me with some code snippets :) thanks in advance, night!
:Octane: (Sakura) :O2: (Sasuke) :1600SW: (Naruto) ... lil Jesse! (O2 laptop)
“Imagination is more important than knowledge.“ – A. Einstein

User avatar
jimmer
Posts: 327
Joined: Tue Oct 12, 2004 3:54 pm
Location: London, Ingerlund

Re: Counter.C - a basic ViewKit component.

Unread postby jimmer » Thu May 03, 2012 12:00 pm

I wouldn;t have thought there would be any issues with passing a struct containing more than one widget, but you seem to have discovered there is. Who knew. That said, my solution would be to not access the other widgets at all, but have them modify some datastructure - and then I;d read the datastructure rather than the widget. oh wait... that's what the MVC pattern is all about!

My advice/approach would be to refactor your code so that the app state is contained in a Model and then implement a bunch of callbacks to push Model changes to the UI.

But I would say something like that as I;ve been messing with Android for the last few months.

grts,

J
:Fuel: redbox 800Mhz 4Gb V12

User avatar
geo
Posts: 525
Joined: Tue Jul 21, 2009 5:07 am
Location: Shenzhen, P.R.C

Re: Counter.C - a basic ViewKit component.

Unread postby geo » Thu May 03, 2012 5:44 pm

morning jummer!

jimmer wrote:I wouldn;t have thought there would be any issues with passing a struct containing more than one widget, but you seem to have discovered there is. Who knew.

hehe maybe i implemented it wrong? but really i tried it but no success, also i think i did it right coz got used on pass by pointer coz on embedded field :) but i hope someone can also confirm if this is indeed another issue with motif

jimmer wrote:That said, my solution would be to not access the other widgets at all, but have them modify some datastructure - and then I;d read the datastructure rather than the widget. oh wait... that's what the MVC pattern is all about!

My advice/approach would be to refactor your code so that the app state is contained in a Model and then implement a bunch of callbacks to push Model changes to the UI.

geeez you really are a guru! hehe thanks for the advice!! why i never thought about that way hehe so meaning instead of sending the widgets, ill make a structure that will hold the two datas that i need. so the two datas will be filled by another two callbacks which is from the two widget... ok will try your approach and report back later, thanks jimmer!!!

jimmer wrote:But I would say something like that as I;ve been messing with Android for the last few months.

aha!! so you messing with java now right? been there last year, but i stopped coz got busy with work :) also got frustrated with the development kit hehe
:Octane: (Sakura) :O2: (Sasuke) :1600SW: (Naruto) ... lil Jesse! (O2 laptop)
“Imagination is more important than knowledge.“ – A. Einstein

User avatar
geo
Posts: 525
Joined: Tue Jul 21, 2009 5:07 am
Location: Shenzhen, P.R.C

Re: Counter.C - a basic ViewKit component.

Unread postby geo » Fri May 04, 2012 8:06 am

hi jimmer, tried your advice, still nothing :( i even tried to pass the simplest structure, the callback cannot receive the expected data, really strange, is this a bug? or design limitation?
:Octane: (Sakura) :O2: (Sasuke) :1600SW: (Naruto) ... lil Jesse! (O2 laptop)
“Imagination is more important than knowledge.“ – A. Einstein

User avatar
jimmer
Posts: 327
Joined: Tue Oct 12, 2004 3:54 pm
Location: London, Ingerlund

Re: Counter.C - a basic ViewKit component.

Unread postby jimmer » Fri May 04, 2012 9:30 am

Not sure why you're still trying to pass the structure to your widget. You should try and setup a globally accessible datastructure to keep track of the UI and its state. Then read from that datastructure what you need, when you need.

Say your 2 other widgets are text boxes, if the text in any of those widget changes you put the new values into the global datastructure. When you fire the callback of the third widget in which you need to use the textbox values, you don't query the textboxes themselves, rather you ask the global datastructure for the stored values. This way keeping track of component access and pointers etc. simply goes away, which is the whole point of the Model-View-Controller (MVC) pattern.

Of course there are exceptions etc. but on the whole it works pretty well.

J.

User avatar
geo
Posts: 525
Joined: Tue Jul 21, 2009 5:07 am
Location: Shenzhen, P.R.C

Re: Counter.C - a basic ViewKit component.

Unread postby geo » Sat May 05, 2012 1:16 am

EUREKA!!! i found it jimmer!! hehe now everything worked as planned hehe before i explain my solution ill answer your post first :) actually i already tried your advice and yes it worked but as i mentioned earlier, i cannot use global because it will contradict with the design of application. to elaborate more, i have a function that will create a custom made popup dialog. one of the buttons callback needs two information, one from a list widget, the other from a text widget. note that using the function, i can instantiate many pop-up dialogs and each instance can have different values for each widget. so if i will use global, if i press button from 1st dialog, its possible to get the values set by the 2nd dialog. so to handle this case, i only need local variable from the function so that every time the function is called, a new instance is created in which the widgets are done. hehe i hope i explained my case here, anyway now for the solution:

just to share maybe anyone will stumble to this same issue, looking at many reference about Motif, i didn't encounter passing more than one widget to a callback hehe na ja, here is what i learned:

to pass two widgets, use

Code: Select all

Widget* SENDDIALOG_ClientData = malloc((sizeof(Widget)*2));


then create the widgets by

Code: Select all

...
...
SENDDIALOG_ClientData[0] = XmCreateScrolledList (SENDDIALOG_Form_Upper, "Users", args, n);
XtManageChild (SENDDIALOG_ClientData[0]);
...
...
SENDDIALOG_ClientData[1] = XmCreateScrolledText(SENDDIALOG_Form_Lower, "Message", args, n);
XtManageChild (SENDDIALOG_ClientData[1]);
...
...


then register callback by

Code: Select all

XtAddCallback (SENDDIALOG_BtnG_Send, XmNactivateCallback, sendDialog_SendCallBack, (XtPointer)SENDDIALOG_ClientData);


then in callback, unwrap data by

Code: Select all

Widget* SENDDIALOG_List_Users = (Widget*)client_data;
Widget* SENDDIALOG_Text_Message = (Widget*)client_data+1;


hehe i think this is known already by everyone here but hehe want to share my happiness by this :)
thanks jimmer for your replies, hopefully can show my work here soon!
:Octane: (Sakura) :O2: (Sasuke) :1600SW: (Naruto) ... lil Jesse! (O2 laptop)
“Imagination is more important than knowledge.“ – A. Einstein

User avatar
jimmer
Posts: 327
Joined: Tue Oct 12, 2004 3:54 pm
Location: London, Ingerlund

Re: Counter.C - a basic ViewKit component.

Unread postby jimmer » Sat May 05, 2012 8:08 pm

Good to hear you've solved your issue. Looking forward to seeing your software :)


Return to “SGI: Development”

Who is online

Users browsing this forum: No registered users and 1 guest